6
\$\begingroup\$

I'm trying to learn more about Component Entity systems. So I decided to write a Tetris clone. I'm using the "style" of component-entity system where the Entity is just a bag of Components, the Components are just data, a Node is a set of Components needed to accomplish something, and a System is a set of methods that operates on a Node. All of my components inherit from a basic IComponent interface.

I'm trying to figure out how to design the Render/Graphics/Drawable Components. Originally, I was going to use SFML, and everything was going to be good. However, as this is an experimental system, I got the idea of being able to change out the render library at will. I thought that since the Rendering would be fairly componentized, this should be doable. However, I'm having problems figuring out how I would design a common Interface for the different types of Render Components. Should I be using C++ Template types?

It seems that having the RenderComponent somehow return it's own mesh/sprite/whatever to the RenderSystem would be the simplest, but would be difficult to generalize. However, letting the RenderComponent just hold on to data about what it would render would make it hard to re-use this component for different renderable objects (background, falling piece, field of already fallen blocks, etc).

I realize this is fairly over-engineered for a regular Tetris clone, but I'm trying to learn about component entity systems and making interchangeable components. It's just that rendering seems to be the hardest to split out for me.

\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

Templates are not the answer, no.

The first thing to keep in mind is that your Drawable components will generally just be data components. For instance, in a simpler 2.5D game I have right now, my DrawableComponet has the following broad subclasses:

  • SpriteDrawableComponent
  • ParticleEmitterComponent
  • FluidComponent
  • StaticMeshComponent

All these components do is hold data and state. All of the actual logic for rendering is encapsulated entirely by the graphics system.

The graphics system contains a list of these drawable components in a data structure optimized for rendering and batching of the draw calls. In my example, the graphics system itself is still actually fully abstracted from the low-level graphics API, and deals with more general purpose rendering concepts. It knows how to ask the graphics API wrapper to create textures, create buffers, set rendering state, load shader packages, and submit geometry to the GPU.

The graphics API wrapper is made of a smaller number of abstract interfaces. There are interfaces for the various types of GPU resources (vertex buffers, textures, shader programs, vertex attrib layouts, and state objects). The implementation of the API then knows how to map those to whichever API is in use (OpenGL 3.3, GL|ES 2.0, and D3D11, for example). The only game-specific code that we need to rewrite for each API then becomes the shaders, and only because Cg outright doesn't support GL|ES shaders.

tl;dr version:

  • Components hold data.
  • Rendering system manages scene state and rendering.
  • Graphics wrapper deals with portability between platform APIs.
\$\endgroup\$
3
  • \$\begingroup\$ So I would assume that your Rendering System would key based off the different type of Drawable subclass, and then do different things based on whether it's a Sprite, ParticleEmitter, etc? \$\endgroup\$
    – s73v3r
    Apr 11, 2012 at 1:30
  • \$\begingroup\$ @s73v3r: something like that. again, it stores them in data structures designed for optimal rendering. the simplest version would just put each type of component into its own list, and then during draw it would loop over each list and do the necessary draw calls for each item. getting good batching, culling, and so on requires something a bit more sophisticated, but that's out of scope for this question imo. \$\endgroup\$ Apr 11, 2012 at 3:15
  • 1
    \$\begingroup\$ +1 for keeping "graphics system" separate from "graphics API wrapper". This seems to be the most reasonable, yet often overlooked way to keep this stuff straight. One level of indirection would likely result in just a pile of render code and one indirection more would probably be over-engineering. Personally, I like the terms "Renderer" for the high level rendering module accessible by the other engine modules and "Render Device" as a graphics API abstraction. \$\endgroup\$
    – Koarl
    May 11, 2012 at 10:36

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .