Aller au contenu

Origins Jeu RTS multi-joueur en 2D


Messages recommandés

Bonjour,

J'hésite à poster cette présentation dans la partie jeu ou programmation car ça porte sur les deux.

Surtout que j'aimerais avoir des commentaires sur le code source quand je pourrai le mettre après le 4 juin.

je vous mets un lien de mon jeu.

Je voulais savoir s'il est bien fait.

Le code source sera disponible qu'à partir du 3 juin !

http://08.innovgame.efrei.fr/

Voici le lien pour télécharger le code source

http://www.2shared.c...entOrigins.html

C'est un jeu RTS multi-joueur.

J'ai utilisé les sockets pour communiquer entre les joueurs (TCP).

Donc quand le code source sera disponible, j'aimerais savoir ce qui n'est pas bien, qu'est-ce qui serait à améliorer, ...

Il y a environ 7400 lignes de code.

Je vous mets le lien pour avoir le code source le 4 juin.

Présentation rapide : Le jeu a été en 4-5 mois environ, je n'avais aucune connaissance en Java à part celle du langage C.

Le jeu a été fait sous Java et Slick 2d, le jeu est dans le cadre du concours Innov'Game 2012.

Il y a un mode solo et multi-joueur (marche en LAN et sur internet)

Je n'ai géré que du 1v1.

Le serveur est héberger par le joueur 1.

Le schéma UML :

uml.png

1 ) Tu utilises quelles bibliothèques ?

java, Slick 2D (qui utilise la LWJGL)

2 ) Ça fait longtemps que tu travailles dessus ?

Depuis le Jeudi, 17 Novembre 2011 00:00, lors du lancement du concours Innov'Game.

Je ne connaissais pas le java avant d'avoir commencer à coder ce jeu (ni Slick 2d)

3 )Tu est seul à le développer ou tu a une équipe ? Je suis seul à développer mais faudrait que j'apprenne à travailler en équipe.

4 ) Quant au concours, il est noté sur quoi ?

Noté sur :

- Détails / Profondeur de l’univers

- Originalité

- Architecture de l’application et complexité des algorithmes utilisés

- Pertinence des technologies / framework utilisés

- Cohérence avec l’univers imaginé lors du round 1

- Organisation et clarté du code-source

- Prise en main : critère qui évalue l'ergonomie, ici la facilité de l'utilisation

- Look & Feel : critère qui évalue l'esthétique, le design, l'impression générale (sensations agréables, plaisir, attractivité)

- Fun Factor : le plaisir de jouer

- Dépendance : le degré de dépendance au jeu (plusieurs paramètres peuvent y contribuer : nombre de missions, difficulté des missions...)

- Durée de vie : le temps des missions du jeu, l'investissement qu'il implique...

- Fréquentation, nombre de visiteurs

Lien vers le commentaire
Partager sur d’autres sites

  • 2 semaines après...

Salut !

Voilà ce que je peux dire après un premier coup d'oeil ;

- Crée des packages en essayant de séparer les données du jeu et les traitements sur ces données.

- Les classes Lancement et Game sont beaucoup trop longues, il faut les splitter en plusieurs classes. (Sépare la configuration du jeu, des images, des sons, des polices ...)

- En Java, on essaie de ne pas affecter les paramètres

- Utilise des énumérations plutôt que des int (notamment dans la classe Monster)

- Évite de dupliquer du code avec juste des paramètres différents

- N'hésite pas à donner des noms longs à tes méthodes

- Évite ce genre de code : if (inGameChoixON = true && !inGameOptionON)

Ci dessous les Warnings que me renvoie Eclipse :

Description Resource Path Location TypeRedundant null check: The variable v cannot be null at this location Client.java /Tests/src/res/eps/tests/tmp line 167 Java ProblemRedundant null check: The variable v cannot be null at this location ClientReceiver.java /Tests/src/res/eps/tests/tmp line 240 Java ProblemRedundant null check: The variable v cannot be null at this location ClientReceiver.java /Tests/src/res/eps/tests/tmp line 258 Java ProblemRedundant null check: The variable v cannot be null at this location ClientReceiver.java /Tests/src/res/eps/tests/tmp line 273 Java ProblemRedundant null check: The variable v cannot be null at this location ClientReceiver.java /Tests/src/res/eps/tests/tmp line 334 Java ProblemRedundant null check: The variable v cannot be null at this location ClientReceiver.java /Tests/src/res/eps/tests/tmp line 351 Java ProblemRedundant null check: The variable v cannot be null at this location ClientReceiver.java /Tests/src/res/eps/tests/tmp line 368 Java ProblemThe declared exception SlickException is not actually thrown by the method initGLetAutre(GameContainer) from type Lancement Lancement.java /Tests/src/res/eps/tests/tmp line 458 Java ProblemThe method checkAchatNain() from the type IA is never used locally IA.java /Tests/src/res/eps/tests/tmp line 98 Java ProblemThe method checkCombat() from the type IA is never used locally IA.java /Tests/src/res/eps/tests/tmp line 62 Java ProblemThe method checkNainPos() from the type IA is never used locally IA.java /Tests/src/res/eps/tests/tmp line 89 Java ProblemThe method checkNainStrategy() from the type IA is never used locally IA.java /Tests/src/res/eps/tests/tmp line 93 Java ProblemThe method checkNbNain() from the type IA is never used locally IA.java /Tests/src/res/eps/tests/tmp line 85 Java ProblemThe method checkUnit(ArrayList<Monster>) from the type IA is never used locally IA.java /Tests/src/res/eps/tests/tmp line 81 Java ProblemThe method checkUnitAllieArround() from the type IA is never used locally IA.java /Tests/src/res/eps/tests/tmp line 76 Java ProblemThe method checkUnitDistanceCooldownRun() from the type IA is never used locally IA.java /Tests/src/res/eps/tests/tmp line 72 Java ProblemThe method checkUnitEngaged() from the type IA is never used locally IA.java /Tests/src/res/eps/tests/tmp line 68 Java ProblemThe method get(String, String) from the type Lancement is never used locally Lancement.java /Tests/src/res/eps/tests/tmp line 4381 Java ProblemThe parameter url should not be assigned Lancement.java /Tests/src/res/eps/tests/tmp line 4385 Java ProblemThe parameter x should not be assigned Lancement.java /Tests/src/res/eps/tests/tmp line 4086 Java ProblemThe parameter x should not be assigned Lancement.java /Tests/src/res/eps/tests/tmp line 4089 Java Problem
Lien vers le commentaire
Partager sur d’autres sites

Merci pour ce premier coup d'oeil.

Quand j'ai commencé ce concours, je n'avais aucune connaissance de Java et j'ai appris les packages il y a un mois.

En Java, on essaie de ne pas affecter les paramètres

Affecter les paramètres ? Qu'est-ce que ça signifie ?

Utilise des énumérations plutôt que des int (notamment dans la classe Monster)

J'avais cru lire qu'il n'y avait pas d'énumération dans Java mais apparemment si : http://fr.wikibooks....va/Énumérations

Et sur quels variables est-ce que j'utiliserais ça ?

Je penses refaire le code complet en C++ et mettre Monster en Abstraite.

Les classes Lancement et Game sont beaucoup trop longues

Tout à fait d'accord. Comme dit plus haut, je ne connaissais pas les packages, je vais m'y mettre à présent.

Redundant null check

Donc d'après Java, il est impossible qu'il y est un objet NULL dans l'array à ce moment là. C'est bien ça ?

Est-ce que je perd vraiment beaucoup de temps en faisant cette vérification ?

Évite de dupliquer du code avec juste des paramètres différents

Quels méthodes ? ou constructeur ?

Car je crois utiliser toutes les méthodes que j'ai créé. Mais au niveau constructeur peut-être pas tous.

Peut-être "spawnUnit()" qui est en effet répété plusieurs fois en changeant juste quelques petits trucs dedans, il aurait fallu faire ça mieux.

L'IA n'a pas été faite faute de temps et de connaissances dans ce domaine.

J'aimerais savoir si c'est bien fait au niveau serveur/client car c'est ce que j'ai programmé en dernier et j'ai donc dû ajouter les fonctions là où j'en avais besoin et ça fait, je trouve, un peu <<bazar>>.

Merci pour ta réponse, je vais essayer de revoir un peu tout.

Lien vers le commentaire
Partager sur d’autres sites

Ne vois pas de critique pure dans ce que je dis, je sais que tu débutes et le principal, c'est de progresser ;)

On est tous passé par là.

- En Java, on essaie de ne pas affecter les paramètres :

C'est à dire qu'à certains endroits, tu affectes une variable en paramètre :

private void changeDeltaMinimap(int x, int y) {if ((x > 0) && (x < 190) && (y < 750) && (y > 625)) {  y = y - 625;  if (x < 40) {	x -= 20;  }  if (x > 140) {	x += 40;  }  if ((y < 30) && (y >= 10)) {	y -= 10;  }  if (y > 90) {	y += 20;  }

x et y sont en paramètres et ils sont réaffectés.

- Utilise des énumérations plutôt que des int (notamment dans la classe Monster)

public boolean changeMetamor(final int metamor){ /*  *  Metamor = 0 -> Unités de base	  deplacement moyenne  nain  * Metamor = 1 -> Unités de corps ˆ corps   deplacement rapide   fantasin  * Metamor = 2 -> Unités de corp ˆ corps avancée deplacement rapide   minotaure  *  Metamor = 3 -> Unités de distance faible  deplacement lent  archer  *  Metamor = 4 -> Unités de de distance avancée deplacement moyenne  centaure  *  Metamor = 5 -> Unités de distance de zone  deplacement lent  mage  */ checkStaticInt(); switch(metamor){ case 0:

La variable metamor pourrait être une énumération. Après si la classe devient abstraite, ça n'aura peut être plus d'intérêt.

- Redundant null check

			  for (final Monster v : game.arrayMonsterOwner) {				if (v != null) {				  if (v.getId() != Integer.valueOf(MsgSplitterBuffer2[1])) {					continue;				  } else {					if (v != null) {					  //v.setMetamor(Integer.valueOf(MsgSplitterBuffer2[2])); // L'autre m´thode m'´vite d'avoir besoin d'envoyer la vie, le mana restant					  v.changeMetamor(Integer.valueOf(MsgSplitterBuffer2[2]));// Tout g´rer (nb de kills, ...)					  break;					}				  }				}

Tu vérifies que v n'est pas null alors que tu l'as déjà fait un peu plus haut.

- Évite de dupliquer du code avec juste des paramètres différents

private void collisionEtoile(final Monster v) {// Voir si je fais un arrayList qui stocke les ID des unites en mvt car j'aurai surement un arrylist pour les unites en mvt attaqueif (v != null) {  final int x = v.getDestX();  final int y = v.getDestY();  switch (countMonsterEtoile) {  case 0:	break;  case 1:	v.changeDestination(x + 30, y);	break;  case 2:	v.changeDestination(x + 30, y + 30);	break;  case 3:	v.changeDestination(x, y + 30);	break;

Tu dupliques n fois v.changeDestination(). Il faut plutôt faire :

 private void collisionEtoile(final Monster v) {// Voir si je fais un arrayList qui stocke les ID des unites en mvt car j'aurai surement un arrylist pour les unites en mvt attaqueif (v != null) {  int x = v.getDestX();  int y = v.getDestY();  switch (countMonsterEtoile) {  case 0:	break;  case 1:	x += 30;	break;  case 2:	x += 30;	y += 30;	break;  case 3:	y += 30;	break;  ... }   v.changeDestination(x, y);

Voilà, j'espère t'avoir aidé !

N'hésite pas à utiliser Eclipse (ou un autre IDE de ton choix qui peut déjà t'indiquer des soucis de qualité).

Lien vers le commentaire
Partager sur d’autres sites

Ne vois pas de critique pure dans ce que je dis, je sais que tu débutes et le principal, c'est de progresser ;)

On est tous passé par là.

Désoler si tu as vu ce que j'ai dis ainsi, j'aime bien les critiques, ça me permet de m'améliorer.

private void changeDeltaMinimap(int x, int y) {	if ((x > 0) && (x < 190) && (y < 750) && (y > 625)) {	  y = y - 625;	  if (x < 40) {			x -= 20;	  }	  if (x > 140) {			x += 40;	  }	  if ((y < 30) && (y >= 10)) {			y -= 10;	  }	  if (y > 90) {			y += 20;	  }

Les variables sont affectées car les images des unités sur la minimap auraient été mal placées sans cette modification des variables.

Donc là, je n'ai pas vraiment le choix.

Donc pour l'énumération :

public enum Test {NAIN(0),FANTASSIN(1),MINAUTAURE(2),ARCHER(3),CENTAURE(4),MAGE(5);private final int value;private Test(int value) {this.value = value;}public int getValue() {return this.value;}

j'utilise Eclipse

Très important :

J'aurai aimé savoir comment faire pour que les joueurs n'aient pas de soucis de connexion entre eux.

Je m'explique :

Pour mon jeu, le joueur est le serveur, j'utilise le port 18000 mais si le joueur 1 bloque le port 18000 (ou son routeur, etc) tous les autres ne peuvent pas le rejoindre.

Alors comment faire ? (Ne me parler pas d'ouvrir le port et de rediriger le port car c'est un moyen mais pas tout le monde est capable de le faire, je veux qq chose qui marche pour tout le monde)

J'essaie d'imaginer pour le jeu Starcraft II et je crois que c'est Blizard qui host les parties.

Aussi on est bien d'accord sur le fait que si le port 18000 est bloqué, on peut envoyer des informations sur ce port mais rien ne peut rentrer chez la personne.

Donc je me suis dit que blizard devait créer une sorte de log de tout ce qui se passe dans la partie en cours et les joueurs vont lire une page http qui se trouve sur un site et font les mise à jour des unités, etc dans la partie.

Serait-ce un moyen pour palier au blocage de port ?

Dîtes moi si vous avez compris le concept.

Lien vers le commentaire
Partager sur d’autres sites

pourquoi mettre un champ value

= ?

Je sais qu'en C enum va donné les valeur 0,1,2,3, etc mais en Java, j'ai pas vu que l'enum attribué une valeur par défaut.

Tu peux me donner ta façon de faire pour cet exemple STP.

Sinon t'as une idée sur ce que j'ai dit pour le serveur ??

EDIT: J'ai vu que tu utilisé souvent le mot clé final, alors je me suis dit :

Serait-ce comme pour faire dans le C++ où lorsqu'on met const la variable n'est pas copié mais pris en valeur, je sais pas bien expliquer mais en gros il n'y a pas de variable qui est créée en plus dans la mémoire.

Est-ce pour ça ?

Lien vers le commentaire
Partager sur d’autres sites

Pour l'énumération, elle se suffit à elle même sans le champ value :

public enum Test {NAIN,FANTASSIN,MINAUTAURE,ARCHER,CENTAURE,MAGE;}

Pour le serveur, pourquoi ne pas faire que n'importe quel joueur puisse le lancer ?

Et les autres doivent rentrer son IP et le port.

Du coup, il n'y a qu'un seul joueur qui doit savoir faire du NAT sur un port.

Lien vers le commentaire
Partager sur d’autres sites

Pour le serveur, pourquoi ne pas faire que n'importe quel joueur puisse le lancer ?

Et les autres doivent rentrer son IP et le port.

Du coup, il n'y a qu'un seul joueur qui doit savoir faire du NAT sur un port.

Ben non car y en a qui veulent jouer ensemble et aucun des deux savent faire ce qu'il faut.

Aussi le programme permet déjà de créer des serveurs chez soi et le 2ème joueur peut rentrer l'adresse IP de la personne qu'il veut rejoindre.

Donc penses-tu que blizard à fait comme j'ai dit ? (faire un log d'évènements sur une page web et les 2 joueurs vont lire cette page, bien sûr c'est le programme qui fait ça)

Lien vers le commentaire
Partager sur d’autres sites

Tout simplement :

  private static String get(String url) throws IOException, Exception{ // Les erreurs sont gérer à l'appel de la fonction pour personnalisé le msg d'erreur    String source ="";   URL urlObject = new URL(url);   URLConnection urlCon = urlObject.openConnection();   BufferedReader in2 = new BufferedReader(new InputStreamReader(urlCon.getInputStream()));   String inputLine2;   while ((inputLine2 = in2.readLine()) != null) source +=inputLine2;   try{ in2.close();   }catch(Exception e){}  return source;  }

Permet d'aller lire des pages web, on peut ainsi facilement récupérer les informations de la partie.

Et cette méthode n'est pas bloquer par le routeur ou autre (sauf un software qui bloque les programmes qui tentent de faire des trucs)

Lien vers le commentaire
Partager sur d’autres sites

as-tu une idée sur comment faire pour éviter les problèmes dû aux routeurs, etc ?

En même, le joueur va juste lire une page internet, regarde jusqu'à la ligne où il s'est arrêté la dernière fois et fait les actions qui y aura écrit.

Pour éviter d'avoir un retour (source) énorme on peut faire un système de php et MySQL où on n'affiche que les actions dont le joueur n'a pas déjà fait la MAJ, ce qui réduit déjà pas mal.

Lien vers le commentaire
Partager sur d’autres sites

j'utilise cette même méthode sauf que j'y ajoute des paramètres dans l'URL et le site va gérer les informations et ajouté tout ça dans une BDD dédiée à chaque match puis le joueur va lire une autre page internet et celle-ci lui renvoie les nouveaux évènements en n'affichant que ceux qui dépasse tel ID (ID incrementé et unique) et le jeu fait les MAJ nécessaire (côté client).

Et le cycle recommence.

On a ainsi un site internet qui stocke tout ce qui se passe dans la partie et les joueurs vont lire ce dont ils ont besoin.

Y a même mieux à faire :

Le site ne fait office que d'intermédiaire pour transiter les informations, le jeu (pour moi la classe Game) est joué sur le serveur (le site) et les joueurs se retrouvent juste à envoyer les cliques (cliques utiles bien sûr) et récupérer les informations.

Voila j'espère avoir été clair.

Lien vers le commentaire
Partager sur d’autres sites

J'ai bien compris ce que tu veux faire.

Je dis juste qu'à ma connaissance, les lettres RT de RTS veulent dire Real Time et qu'avec cette solution, tu seras loin d'avoir des performances temps réelles.

De plus, les gens qui ont une connexion performante seront très avantagés par rapports aux autres.

Lien vers le commentaire
Partager sur d’autres sites

Je dis juste qu'à ma connaissance, les lettres RT de RTS veulent dire Real Time et qu'avec cette solution, tu seras loin d'avoir des performances temps réelles.

De plus, les gens qui ont une connexion performante seront très avantagés par rapports aux autres.

J'ai fait des recherches et c'est faux car blizzard host les parties pour Starcraft II (c'est la même chose pour battlefield 3 et pour d'autres jeux)

En gros il y a des serveurs un peu partout le monde et les gens se connectent à ces serveurs, créer des parties, en joignent,... et jouent dessus.

Le Real Time comme tu dis est une question de latence, c'est comme si tu jouais en france et que tu te connectais au serveur qui se trouve vers le japon ou la corée.

Donc ceux qui jouent en france et jouent sur le serveur français n'auront pas de soucie de latence. Le seul soucie est leur propre connexion mais ça, c'est le problème du client pas.

Après le serveur peut détecter que le joueur lag et va suspendre un court instant la partie ou autre.

Voila, je vais donc créer un exécutable serveur et un autre client.

Transformer mon pour le mettre en C++, améliorer les graphismes, passer en 3D peut-être.

Lien vers le commentaire
Partager sur d’autres sites

ok ben dans ce cas je vais ça en Socket.

Donc le serveur dans un exécutable et pareil pour le client (joueur).

Je mettrai le serveur sur un ordi dédié à ça.

Merci pour toutes tes réponses !

J'ai pu mieux saisir les réseaux, comment structuré la programmation, connaître les points à améliorer,...

Merci.

Lien vers le commentaire
Partager sur d’autres sites

  • 2 mois après...

Archivé

Ce sujet est désormais archivé et ne peut plus recevoir de nouvelles réponses.

×
×
  • Créer...