Need opinions on my component based design

Started by
10 comments, last by pinebanana 10 years, 7 months ago

I have an Entity class and a Component class. The Entity class has a list of attached components, and each component also has a member variable that is a reference to the entity that it is attached to (cyclical design).

Then, there is the EntityManager class, which has a list of (you guessed it!) entities, and each entity also has a reference to its encapsulating entity manager.

The reason for this cyclical design is due to data reliance. To explain further, my Entity class is essentially just a giant bucket of data: any data any type of entity needs already exists on this class when it is instantiated. However, in order to make use of this data, the Entity needs the relevant components attached. For example, my Rendering component takes the Entity's spriteData member and draws it to the backbuffer. Without a rendering component, spriteData is not utilized. Since my components need to access the Entity's member variables, each component needs a reference to the Entity it is attached to.

For an example of why my entity needs a reference to the entity manager, it is because some components (such as collision) need to access other entities' data buckets in order to function (for collision, this would be checking nearby entities' position vector and comparing it to the component's referenced entity).

There is more to it than this, but I just wanted to highlight the central idea of what I was doing, and wanted opinions on whether a cyclical approach like this (with little data encapsulation as well..) is a good idea or not. Maybe I'm just overthinking it /shrug. Opinions on how to steer the design would be hugely appreciated, as well.

Advertisement
Hi.
I don't know if it helps, but this is how I do it myself:

- a class for main d3d rendering
- a class for the d3d scene

- a class for sprites, one for meshes, one for meshinstances etc
- the d3d scene has a vector with sprite objects,mesh objects, instances objects, shaders/effects etc
A meshinstance has a member int storing the id of the corresponding mesh
- in the d3d main renderer class there's a pointer to the d3dscene, set when loading the scene

- then there's a entitymanager class which is a friend class of the d3dscene

So my advice would be to draw out what you want to achieve and which classes need to be able to access each other. In my case I basically designed everything around 2 classes, the d3drenderer and the d3dscene. It works quite flexible, I can add nice things relatively quick and easy, maintaining flexibility/ structure.

Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me


... To explain further, my Entity class is essentially just a giant bucket of data: any data any type of entity needs already exists on this class when it is instantiated. However, in order to make use of this data, the Entity needs the relevant components attached. ...

For sure, all roads lead to Rome, and nothing exists that can be looked at as a standard component based entity system. However, for me it sounds that you stopped on half the way: Behavior is modeled by components, but data is still monolithic (IMHO, this is rather the strategy pattern than a CES). If I'm right, then what's the reasoning for this decision? The intention of composition is just to avoid "monolithicism" ...


If I'm right, then what's the reasoning for this decision?

i'm, saying!

first thing that popped into my mind too!

why are you doing this?

second thing that popped into my mind:

a "link back" to the owner of a chunk of data is only required if you can't design your system to work without them. which you may or may not be able to do depending on the situation.

but the more fundamental question remains: why?

i recently considered C-E for a testbed "engine" or "framework" i'm playing around with, and found it was unnecessary.

apparently C-E is primarily for when you want to have non-programmers be able to define new types of entities from an existing library of available component types already built-in to the game engine.

if the entity's components are hard-coded in your entity class declaration, you're negating the whole point of using C-Es. apparently the whole point of C-Es is they let you soft code your entity definitions.

one would only need to soft code entity definitions in a generic engine like unity, in a large project where non-coders created defined entities with in-house tools, or other situations where one has no source code access. for the small team, small project, or lone wolf its probably overkill.

there can be a second reason for C-E, and that's as a cache optimization method. but it requires a specific implementation and is only about optimization. soft coded entities can be added on top if desired. i've only seen one reference to it, it works, its drastic (IE it doesn't get you much unless you code is total junk to begin with, and you only use it as a last resort), and its not the method that anyone you've ever talking about C-E uses.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

apparently a lot of the popularity of C-E is that its seen as a workaround for the inherent difficulties of applying traditional OO C++ design methodologies to games. In some (many?) ways, traditional OO C++ design does not lend itself well to building games. C-E takes the traditional OO hierarchy design and converts it to a relational database / parallel array type design.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

apparently a lot of the popularity of C-E is that its seen as a workaround for the inherent difficulties of applying traditional OO C++ design methodologies to games. In some (many?) ways, traditional OO C++ design does not lend itself well to building games. C-E takes the traditional OO hierarchy design and converts it to a relational database / parallel array type design.

This. Class hierarchies have a way of spiraling out of control towards the end of project making bug hunting tedious just as it becomes the most important task. There is also the runtime flexibility it allows which is handy given that live updating your world via an external or embedded editor has huge implications for the productivity of the design team. Adding and removing components to an entity and propagating those changes to a running instance of the game is exceptionally awkward to do with a standard OOP design.

I think there is room for both approaches. The Entity-Component model works best at a high level, the extreme end of that being only having a single entity GameObject that contains components. The components themselves are built from a usual class hierarchy or Rener(ables) Update(ables) Stream(ables) etc. In this scenario a game object representing a vehicle would have a component for the engine, the wheels, the seats, etc. In turn Engine would inherit from IUpdatable but not much else. Wheel would inherit from IUpdatable and IRenderable etc. This is the approach I favor and it works well as long as the team as a whole is clear about where one design paradigm ends and the other begins and what type of functionality belongs in which system. It's easy for people not privy to the intent of the two systems to start blurring the line and eventually create a mess that must be cleaned up later. Code reviews help with this.

If what you have is working for you, than I don't recommend making any huge changes unless you start running into problems. But for your next project, you might want to consider some of these other approaches.

It doesn't make much sense to me to have an entity with several fields that might or might not be used depending on whether it is renders le, collidable, etc. So my data is held by the components. Most components also hold a reference to a functor. Components such as position/orientation don't. My game is set up as several systems or modules: an entity system, a render system, a physics system, an audio system, an AI system, etc. The entity system maintains a list of entities for each of the other systems. So, in the game loop, for each system that needs processing, the game polls the entity system for a collection of entities to process. For example, you can ask for all entities with a renderable component. The entity system provides a first and last iterator that are then fed to the render system. The render system iterates through, calling each renderable component's functor. I use functors because 3D models, sprites, UI elements, etc. needs to be handled differently, so I have a different functor for each type of renderable processing needed, which allows me to avoid having to hardcode a lot of specific algorithms and routines into the various systems.

I haven't touched my code in a long while, but when I finally get back to it, I'd like to replace the components' functors with handles to lua scripts.


Most components also hold a reference to a functor. Components such as position/orientation don't.

so your movement "flight model" is hard coded?

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php


Class hierarchies have a way of spiraling out of control

i am blessed to work in the nirvana which is pure c code in a c++ program. thus i have no C++ OOP related issues in my universe. wink.png

in my testbed engine/framework program, i've gotten the API down to one call:

void Zmain(Hprogram_instance);

and about a dozen user defined functions.

everything else is soft coded.

but its designed for any type of 3d graphics game. so i'm finding "flight model" to be an entity type specific function, the same way that render info is. so far, its still generic enough to make any type of vehicle sim (including shooter), RTS/RTT, citybuilder, total war, whatever, even 3d graphics implementations of 2d games like space invaders. about the only assumption so far is the game will use directx for graphics, and its real time. but odds are there's already an appropriate hook into the engine to add "press enter to end turn" for turn based games.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

Thanks for the feedback everyone.

To those who are wondering my decision to have components but have a monolithic entity class, the answer is flexibility and ease of prototyping. Anytime during my design if I think "you know what, so-and-so Entity would be cool, I will need x new property, y new component, and I can reuse a,b,c component" all I have to do is create a new property in the giant Entity class, toss in some already made components, and create the new component that I need for this entity.

I alaso didn't mention that I use Lua scripting for entity initialization and behavior. the components essentially only fire "triggers" (and perform lower level tasks such as sprite batching) which call Lua scripts that are attached to entities on initialization. These scripts are what perform actual game logic.

Entities are ordered in the entity manager by ID, and components are ordered in the entity by a map of component type, to components. When an aspect of the game is updated, such as physics, the entity manager calls update on each entity with physics components.

I'm sure there's a more efficient, "sexier" way to handle this than having a bunch of different, unrelated data in one class. I'm pretty much a novice at this smile.png

Edit: yckx I like that approach, I might fork and experiment..

This topic is closed to new replies.

Advertisement