Java Game Dev: Essayer de séparer le monde et le moteur de rendu


Je développe un petit jeu en Java et j'ai rencontré un problème pour décider comment abstraire mon monde de jeu du framework que j'utilise.

Comme je l'ai maintenant, j'ai une classe appelée World qui garde une trace de tous les différents objets du monde et les met à jour selon les règles du jeu. Alors j'ai trois classes d'objet Person, Obstacle, et Item. Chaque objet a différents "types" qui sont représentés par une variable membre. Toutes les classes d'objets sont étendues à partir de la classe GameObject.

Comme je l'ai maintenant, les classes World et object sont séparées du framework qui rend le jeu et etc. La classe Game à la fois dit au monde de mettre à jour et rend le monde et les objets dans le monde.

Le problème est que je rends les objets avec les trois méthodes drawPersons(), drawObstacles() et drawItems() ce qui est bien parce que j'ai déjà écrit le code et je n'ajouterai plus de classes d'objets. Le vrai problème est de rendre les différents "types" de chaque objet classe. Comme je l'ai maintenant, les méthodes draw dessinent les éléments en vérifiant la variable object.type puis il y a une instruction switch qui choisit le bitmap approprié à dessiner.

Je veux simplifier cela afin de ne pas avoir à ajouter à l'instruction switch chaque fois que j'ajoute un nouveau "type" à la classe Item par exemple. La seule façon dont je peux penser à le faire est de faire en sorte que les objets stockent le bitmap auquel ils doivent être rendus lorsqu'ils sont construits et ont leur élément.tapez ensemble de variables. De cette façon je pourrais supprimez les instructions switch de la méthode drawItems(). De plus, je pourrais également donner à chaque classe d'objet une méthode draw() bla bla bla mais la raison pour laquelle je ne veux pas le faire est parce que cela ruine la séparation que j'ai du moteur de rendu/framework et du monde imaginaire du jeu.

Je ne sais pas quoi faire, d'une part, je sais que c'est une mauvaise idée d'utiliser des instructions switch comme je le suis actuellement, mais de l'autre, je sais qu'il est préférable d'avoir mes classes World et object indépendantes de la framework donc, si je le voulais, je pourrais le gifler dans un nouveau framework ou quoi que ce soit sur la ligne.

Y a-t-il un moyen d'avoir les deux?

Author: Kyle V., 2012-01-16

6 answers

Ce que vous pouvez faire est d'utiliser la composition, c'est-à-dire que vos entités contiennent plusieurs composants qui ont des objectifs différents. Par exemple, il peut y avoir un composant de rendu, un composant physique, un composant ai, etc.

Le monde gérerait les entités en général et les sous-systèmes interrogeraient ensuite les entités pour les composants corrects. Ainsi si le moteur de rendu veut rendre une entité il l'interroge pour le composant de rendu et peut être un composant de position et utilise les données celles ci fournir pour rendre l'entité.

Dans ce cas, le composant de rendu peut contenir des données telles que texture/bitmap, forme, matériau, etc.

Pour plus d'informations, vous voudrez peut-être regarder dans entité systèmes.

 2
Author: Thomas, 2012-01-16 08:03:28

Il ne devrait pas être un problème de stocker un objet image dans chacun de vos objets dessinables. Le stockage d'une image ne perturbe pas le fonctionnement de vos boucles de rendu. Parfois, la sur-abstraction peut être lourde si elle n'est pas nécessaire. Je ne vois rien de mal à stocker des images dans des objets. Les instructions Switch deviennent rapidement très inefficaces une fois que vous commencez à ajouter plus d'objets dessinables à votre jeu. Pensez aux jeux avec des centaines d'objets dessinables. Les pointeurs nécessitent peu d'espace et accélèrent votre code dans le long terme.

 2
Author: collinjsimpson, 2012-01-16 07:59:27

Je crois que vous pourriez envelopper vos classes en utilisant le Motif décorateur.

Un décorateur contient une instance GameObject et implémentera également les fonctions GameObject en appelant les méthodes sur l'instance d'origine.

Lorsque vous sous-classez GameObject de cette manière, vous pouvez également faire en sorte que les décorateurs implémentent une interface Renderable avec une méthode draw().

 2
Author: JBert, 2012-01-16 08:04:45

Vous pouvez étudier le modèle de visiteur . Vos objets du monde du jeu emmènent un visiteur alphabétisé à travers eux en effectuant une opération: dans ce cas, l'opération est le dessin. Logique pour choisir différentes implémentations en fonction de ce que l'objet du jeu est conservé du côté visiteur.

 2
Author: , 2012-01-16 09:53:27

Ma suggestion est d'utiliser l'atlas bitmap , c'est-à-dire toutes vos images dans une grande image, puis de créer une méthode abstraite dans votre classe GameObject qui renvoie les régions qu'un objet de jeu a dans l'atlas.

Comme ceci

public abstract class GameObject{

...
...
..

public abstract TextureRegion getGameObjectTextureRegion();
...
..
}

Et dans chaque classe qui étend GameObject, stockez une variable d'instance comme celle-ci

public class Person extends GameObject{
....
....
...
public static final TextureRegion person_region = new TextureRegion(top,left,height,width);
...
...
public TextureRegion getGameObjectTextureRegion(){
return person_region;
}

Puis stocker tous vos objets de jeu dans un tableau ou ArrayList comme ceci

ArrayList<GameObject> game_objects = new ArrayList<GameObject>();
//add items to it 
game_objects.add(new Person());
gmae_objects.add(...);

Et dans votre méthode draw, bouclez la liste et l'appel game_objects getGameObjectTextureRegion

for(GameObject item : game_objects)
{
TextureRegion region = item.getGameObjectTextureRegion();
// then pass them with the game object position to your rendering method 
...


}

Remarque: TextureRegion ressemble à ceci

public class TextureRegion{

float top;
float left;
float width;
float height;
}
 1
Author: confucius, 2012-01-16 08:43:16

J'aime la réponse "entity systems" de Thomas. Mais je pensais à une approche différente moi-même. Je vais essayer de le présenter aussi abstraitement que possible car je ne suis pas très familier avec Java.

Vous pourriez avoir une sorte de variable 'resources' qui stocke des paires de object_type:data qui contient les ressources requises pour chaque type d'objets que vous avez l'intention d'insérer dans votre monde. La variable "ressources" peut être une liste d'animations ou d'autres ressources communes.

Pour être plus concrètement, permettez-moi de vous donner un exemple en Python (puisque c'est ce que je connais le mieux). Cela ne devrait pas être un problème d'appliquer la même chose en Java ou dans pratiquement n'importe quel autre langage d'ailleurs. En Python, je créerais une variable de dictionnaire qui ressemble à ceci:

{
Person1:["person1.bmp", "person1_alternative1.bmp", "person1_whatever.wmv"],
Person2:["person2.bmp", "person2_alternative1.bmp", "person2_whatever.wmv"],
Obstacle1:["Obstacle1.bmp", "Obstacle1_alternative1.bmp", "Obstacle1_whatever.xyz"],
Obstacle1:["Item1.bmp", "Item1_alternative1.bmp", "Item1_whatever.xyz"]
}

... et ainsi de suite

Vous pouvez étendre cela comme bon vous semble; Ajouter d'autres types de ressources, peut-être des coordonnées d'objets, des dimensions ou autre.. Par exemple

{
person1:{basic_animation:"person1.bmp", alt_animation:"person1_alternative1.bmp", sfx1:"person1_whatever.wmv"},
person2:{basic_animation:"person2.bmp", alt_animation:"person2_alternative1.bmp", sfx1:"person2_whatever.wmv"},
obstacle1:{basic_animation:"obstacle1.bmp", alt_animation:"obstacle1_alternative1.bmp", res1:"obstacle1_whatever.xyz"},
item1:{basic_animation:"item1.bmp", alt_animation:"item1_alternative1.bmp", sfx1:"item1_whatever.wmv"}
}

La syntaxe et est probablement différente dans Java, mais vous avez l'idée générale. Je ne sais pas comment Java gère le type de variables key:value, je suppose qu'il a une classe pour cela. Si pas, vous pouvez toujours faire votre propre.

Cette grande variable "ressources" peut faire partie de votre classe de jeu et être initialisée et remplie avec des données pertinentes lorsque vous avez instance la classe de jeu. Il peut même être stocké ailleurs si vous préférez regrouper toutes vos constantes dans un endroit séparé / module / peu importe (ce que je fais!). Ensuite, vous pouvez les unifier drawPersons (), drawObstacles () et drawItems () dans une seule fonction draw () qui vérifie 'object.type "pour chaque" objet "et le regarde dans "ressources" pour obtenir ses données pertinentes.

Maintenant, je ne connais pas les performances et d'autres facteurs, il a probablement besoin d'une optimisation de la part de quelqu'un de plus intelligent!

 0
Author: Osama Arafa, 2014-01-22 09:12:00