Monday, July 30, 2018

architecture - Entity System and rendering


Okey, what I know so far; The entity contains a component(data-storage) which holds information like; - Texture/sprite - Shader - etc


And then I have a renderer system which draws all this. But what I don't understand is how the renderer should be designed. Should I have one component for each "visual type". One component without shader, one with shader, etc?


Just need some input on whats the "correct way" to do this. Tips and pitfalls to watch out for.



Answer




This is a difficult question to answer because everyone has their own idea about how an entity component system should be structured. The best I can do is share with you some of the things I have found to be most useful for me.


Entity


I take the fat-class approach to ECS, probably because I find extreme methods of programming to be highly inefficient (in terms of human productivity). To that end, an entity to me is an abstract class to be inherited by more specialized classes. The entity has a number of virtual properties and a simple flag that tells me whether or not this entity should exist. So relative to your question about a render system, this is what the Entity looks like:


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; }
}


Components


Components are "stupid" in that they don't do or know anything. They have no references to other components, and they typically have no functions (I work in C#, so I use properties to handle getters/setters - if they do have functions, they are based around retrieving data that they hold).


Systems


Systems are less "stupid", but are still dumb automatons. They have no context of the overall system, have no references to other systems and hold no data except for a few buffers that they may need to do their individual processing. Depending on the system, it may have a specialized Update, or Draw method, or in some cases, both.


Interfaces


Interfaces are a key structure in my system. They are used to define what a System can process, and what an Entity is capable of. The Interfaces that are relevant for rendering are: IRenderable and IAnimatable.


The interfaces simply tell the system which components are available. For example, the rendering system needs to know the bounding box of the entity and the image to draw. In my case, that would be the SpatialComponent and the ImageComponent. So it looks like this:


public interface IRenderable {
SpatialComponent Component { get; }

ImageComponent Image { get; }
}

The RenderingSystem


So how does the rendering system draw an entity? It's actually quite simple, so I'll just show you the stripped down class to give you an idea:


public class RenderSystem {
private SpriteBatch batch;
public RenderSystem(SpriteBatch batch) {
this.batch = batch;
}

public void Draw(List list) {
foreach(IRenderable obj in list) {
this.batch.draw(
obj.Image.Texture,
obj.Spatial.Position,
obj.Image.Source,
Color.White);
}
}
}


Looking at the class, the render system doesn't even know what an Entity is. All it knows about is IRenderable and it is simply given a list of them to draw.


How It All Works


It may help to also understand how I create new game objects and how I feed them to the systems.


Creating Entities


All game objects inherit from Entity, and any applicable interfaces that describe what that game object can do. Just about everything that is animated on screen looks like this:


public class MyAnimatedWidget : Entity, IRenderable, IAnimatable {}

Feeding the Systems


I keep a list of all entities that exist in the game world in a single list called List gameObjects. Each frame, I then sift through that list and copy object references to more lists based on interface type, such as List renderableObjects, and List animatableObjects. This way, if different systems need to process the same entity, they can. Then I simply hand those lists to each one of the systems Update or Draw methods and let the systems do their work.



Animation


You might be curious how the animation system works. In my case you may want to see the IAnimatable interface:


public interface IAnimatable {
public AnimationComponent Animation { get; }
public ImageComponent Image { get; set; }
}

The key thing to notice here is the ImageComponent aspect of the IAnimatable interface is not read-only; it has a setter.


As you may have guessed, the animation component just holds data about the animation; a list of frames (which are image components), the current frame, the number of frames per second to be drawn, the elapsed time since the last frame increment, and other options.


The animation system takes advantage of the rendering system and image component relationship. It simply changes the image component of the entity as it increments the animation's frame. That way, the animation is rendered indirectly by the rendering system.



No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...