4

I'm trying to create a basic C/E game engine for Android, and I'm trying to re-create pong as a basic warm-up. I currently have a EntityManager class that contains a list of all the UUIDs for its Entities, and has a render() function that calls render() on all Components that implement RenderableComponent (a basic interface with a render() function itself), and the same for update().

Stop me if I'm already doing something incorrectly...

My question is, should I be creating specific components that only apply to each entity? (E.g. a BallMovement, BallDraw, etc. component for the ball) or what is the correct way to create components for Entities?

Thanks in advance! (:

Nick Badal
  • 534
  • 6
  • 19

1 Answers1

5

No, I think your components should be as generic and reusable as possible. And the examples you gave certainly don't need specific components. Here's an example of the type of components you could be thinking about:

  • TransformComponent - Has as Position in the world.
  • SpriteComponent - Has a Sprite and renders it at TransformComponent.Position
  • MovableComponent - Has a Velocity and updates TransformComponent.Position
  • BoxComponent - Has a Rectangle and detects collisions with other BoxComponents

Then, all of these have parameters that will vary from entity to entity.

For example, and still thinking about the ball:

  • The TransformComponent could store the ball's initial position
  • The SpriteComponent could keep a reference to the ball sprite
  • The MovableComponent could store the ball's initial velocity.
  • The BoxComponent could store the ball size and have a special handler for its collision event

Then your paddles might also have some of these components, but they will probably have different initial parameters for each of them, and this is what will make them unique and different from the ball entity. A good component for them might be an InputComponent that handles user input and updates the TransformComponent when the player presses the up or down keys.

PS: If you have never tried Unity3D, I think it's a good place to start wrapping your head around these concepts!

David Gouveia
  • 24,875
  • 5
  • 84
  • 124
  • 1
    Question: OP says he is rendering on a component-to-component basis (I personally use "systems" to handle rendering but I'm not saying which approach is better). Your example mentions SpriteComponent using TransformComponent.Position. How would you suggest OP handle the coupling between them? – Mike Cluck Mar 03 '12 at 02:41
  • @MikeC Actually I haven't researched much into the best way to implement a component based system, so this might not be the best way, but following my gut instinct I would it implement it like this: Any component that is registered with an entity would automatically store an internal reference to that entity. And all entities would have a GetComponent(Type) method. Then on initialization, the SpriteComponent could simply call entity.GetComponent(tyepof(TransformComponent)) and store it locally. Then use that reference when rendering. – David Gouveia Mar 03 '12 at 02:55
  • @MikeC Another possibility that I can think of is a message based system, where any component can send a message through the entity to every other component so that they can react accordingly. In that scenario, the TransformComponent might know how to react to a GetPosition message by returning its internal position, and the SpriteComponent would simply send a message of that type through the entity when it required the position. – David Gouveia Mar 03 '12 at 03:00
  • Messages are basically just really, really late linked function calls =P They're pretty cool for small systems like you're experimenting with and are very flexible to let you try out different setups without too much trouble. – Patrick Hughes Mar 03 '12 at 03:05
  • 1
    @DavidGouveia I can't say I've researched it much myself, kind of learning as I go, but personally I'd feel uneasy creating direct coupling between components like that. I'm actually in the process of trying to resolve this issue in my own engine, which is why I asked. – Mike Cluck Mar 03 '12 at 04:23
  • @MikeC Isn't your concern covered by my second alternative? Messages provide loose coupling. For instance, in the example given, the SpriteComponent does not know about the TransformComponent. All it requires it that there exists some component capable of handling the GetPositionmessage, but without specifying which one. – David Gouveia Mar 03 '12 at 11:38
  • 1
    @DavidGouveia Messages aren't enough. They are good for notifying components of things that happen rarely, but components also need to access information on-demand, like the position. I've posted an answer here about how I implemented my CBS: http://gamedev.stackexchange.com/a/23759/6188 – Paul Manta Mar 03 '12 at 13:35
  • @PaulManta Interesting post! But there are several different ways to approach the problem. Personally, for information on-demand I'm content with the simple approach of directly querying the entity for a component or component type, and using it. In fact I'd probably use both messages and interface querying, and choose between them depending on the situation (IIRC that's the way described in GPG6). I can also think of a message sending mechanism that allows a value to be returned by the first component to handle the message - that's what I had in mind with the GetPosition message. – David Gouveia Mar 03 '12 at 14:07
  • @DavidGouveia But isn't querying for the component type very time consuming? Surely in a decently sized game, this wouldn't be a good solution. And not only that, this allows components to interact in unspecified ways (dependencies are not made clear) and there's no nice way to ensure that the component it is looking for actually exists. – Paul Manta Mar 03 '12 at 14:12
  • @PaulManta In the example above, I would just need to query for the TransformComponent once at initialization. I would store a reference to that component inside the SpriteComponent and all further operations would be done with that reference. I could also assert on initialization if the component is not found. As for how to query for a component, I think a simple Dictionary<Type, Component> on the entity would be enough. It's definitively not perfect and requires entities to be set up properly but, and this is just as a personal opinion, I think it would be enough for any of my projects – David Gouveia Mar 03 '12 at 14:18
  • @DavidGouveia The messaging is a decent point but as you mentioned in your most recent comment, you're still allowing components to hold references to one another which by definition forces coupling. I prefer having components only contain data and basic functions for acting upon/accessing that data then having systems which hold references to entities who contain certain components (see the Artemis framework for a similar approach) and those systems handle all component interactions. – Mike Cluck Mar 03 '12 at 15:54
  • @MikeC When I mentioned holding a reference to the other component I was not talking about the messaging system, I was already talking about the hybrid approach I would take. I also described it should be possible to use a messaging system to fetch values from other components without having to know the specific component time. The first component to recognize and handle the message would return the value to be used. – David Gouveia Mar 03 '12 at 16:04
  • @DavidGouveia True enough and I apologize for mending your approaches together :) I think at it's root our difference in opinion lies in where the logic is handled. You say the components should be able to talk to one another (without explicitly knowing what component they are talking to) and I am suggesting an external manager of sorts to handle inter-component messaging. I may have to tinker with direct component messaging, it seems like an interesting approach. – Mike Cluck Mar 03 '12 at 16:10
  • @MikeC Woops, I meant component type, not component time. :) But I see what your point is and it is quite interesting too! I.e. keeping interactions between components localized in external managers instead. That looks like a clean solution to separate logic and data. Well, to be honest I just had my first practical experience with components the other day with Unity, and found it very interesting to work with. I haven't researched how it's being implemented there though. – David Gouveia Mar 03 '12 at 16:17