Il est difficile de répondre à cette question car chacun a sa propre idée de la manière dont un système de composants d'entité doit être structuré. Le mieux que je puisse faire est de partager avec vous certaines des choses que j'ai trouvées les plus utiles pour moi.
Entité
J'adopte l'approche ECS pour les matières grasses, probablement parce que je trouve que les méthodes de programmation extrêmes sont très inefficaces (en termes de productivité humaine). À cette fin, une entité est pour moi une classe abstraite à hériter de classes plus spécialisées. L'entité a un certain nombre de propriétés virtuelles et un simple indicateur qui me dit si cette entité doit exister ou non. Donc, par rapport à votre question sur un système de rendu, voici à quoi Entity
ressemble:
public abstract class Entity {
public bool IsAlive = true;
public virtual SpatialComponent Spatial { get; set; }
public virtual ImageComponent Image { get; set; }
public virtual AnimationComponent Animation { get; set; }
public virtual InputComponent Input { get; set; }
}
Composants
Les composants sont "stupides" en ce qu'ils ne font rien ou ne savent rien. Ils n'ont aucune référence à d'autres composants, et ils n'ont généralement pas de fonctions (je travaille en C #, donc j'utilise des propriétés pour gérer les getters / setters - s'ils ont des fonctions, ils sont basés sur la récupération des données qu'ils contiennent).
Les systèmes
Les systèmes sont moins "stupides", mais restent des automates stupides. Ils n'ont aucun contexte du système global, n'ont aucune référence à d'autres systèmes et ne contiennent aucune donnée à l'exception de quelques tampons dont ils peuvent avoir besoin pour effectuer leur traitement individuel. Selon le système, il peut avoir une méthode Update
ou une Draw
méthode spécialisée , ou dans certains cas, les deux.
Interfaces
Les interfaces sont une structure clé de mon système. Ils sont utilisés pour définir ce qu'un System
processus peut traiter et ce dont un Entity
est capable. Les interfaces pertinentes pour le rendu sont: IRenderable
et IAnimatable
.
Les interfaces indiquent simplement au système quels composants sont disponibles. Par exemple, le système de rendu doit connaître le cadre de sélection de l'entité et l'image à dessiner. Dans mon cas, ce serait le SpatialComponent
et le ImageComponent
. Il ressemble donc à ceci:
public interface IRenderable {
SpatialComponent Component { get; }
ImageComponent Image { get; }
}
Le système de rendu
Alors, comment le système de rendu dessine-t-il une entité? C'est en fait assez simple, donc je vais juste vous montrer la classe dépouillée pour vous donner une idée:
public class RenderSystem {
private SpriteBatch batch;
public RenderSystem(SpriteBatch batch) {
this.batch = batch;
}
public void Draw(List<IRenderable> list) {
foreach(IRenderable obj in list) {
this.batch.draw(
obj.Image.Texture,
obj.Spatial.Position,
obj.Image.Source,
Color.White);
}
}
}
En regardant la classe, le système de rendu ne sait même pas ce qu'est un Entity
. Tout ce qu'il sait, c'est IRenderable
et on lui donne simplement une liste à dessiner.
Comment tout cela fonctionne
Il peut également être utile de comprendre comment je crée de nouveaux objets de jeu et comment je les alimente dans les systèmes.
Création d'entités
Tous les objets de jeu héritent de l'entité et de toutes les interfaces applicables qui décrivent ce que cet objet de jeu peut faire. À peu près tout ce qui est animé à l'écran ressemble à ceci:
public class MyAnimatedWidget : Entity, IRenderable, IAnimatable {}
Nourrir les systèmes
Je garde une liste de toutes les entités qui existent dans le monde du jeu dans une seule liste appelée List<Entity> gameObjects
. Chaque cadre, je passe ensuite au crible cette liste et copie les références d'objet vers d'autres listes basées sur le type d'interface, telles que List<IRenderable> renderableObjects
, et List<IAnimatable> animatableObjects
. De cette façon, si différents systèmes doivent traiter la même entité, ils le peuvent. Ensuite, je remets simplement ces listes à chacun des systèmes Update
ou Draw
méthodes et je laisse les systèmes faire leur travail.
Animation
Vous pourriez être curieux de savoir comment fonctionne le système d'animation. Dans mon cas, vous voudrez peut-être voir l'interface IAnimatable:
public interface IAnimatable {
public AnimationComponent Animation { get; }
public ImageComponent Image { get; set; }
}
L'élément clé à noter ici est que l' ImageComponent
aspect de l' IAnimatable
interface n'est pas en lecture seule; il a un setter .
Comme vous l'avez peut-être deviné, le composant d'animation ne contient que des données sur l'animation; une liste d'images (qui sont des composants d'image), l'image actuelle, le nombre d'images par seconde à dessiner, le temps écoulé depuis le dernier incrément d'image et d'autres options.
Le système d'animation tire parti du système de rendu et de la relation entre les composants d'image. Il modifie simplement le composant d'image de l'entité en incrémentant l'image de l'animation. De cette façon, l'animation est rendue indirectement par le système de rendu.