Questions about the Actor class

    This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

    • Questions about the Actor class

      Hello everyone.

      I have some questions about the Actor interface in the book.

      I understand that ActorParams work kind of like a factory for a kind of Actors. Makes pretty good sense to me, a kind of serializable object factory.

      But... what I don't understand is why IActor has an Update method. Nowhere in the source code (and I've tried using the search function on Google code) can I find that this method is actually used.

      The BaseGameActor seems to store enough information to be used in TeaPotWars. That is, it's a useful data container. But as I gather the structure proposed in the book is one of message passing (called events in the book), where things that listen to events update the game state.

      I guess the GameLogic would be in charge of updating the actors. Something that feels a bit iffy to me, won't this result in a gargantuan switch-block?

      After some contemplation I guess my actual question is this: we have GameLogic, we have events, but what if I have a bazillion different types of Actors (Door, Hovering Banana, Headless Kamikaze) etc with different behaviour. Where do I manage this?

      In the Actor class, through the Update method? "Check we have zero health"... would the Actor notify the world about it's poor health?

      TeaPotWars seems (and I'm probably wrong here) to encode all this Actor behaviour in it's event handler. But with a growing number of actors, I can see this becoming a massive problem.

      Sorry for this rambling "question", thank you for any help in advance.

      ----------
      Edit:

      And some more thinking:

      We could have different listeners that implement the Actors behaviour, but what use would the Actor objects be then, we could effectively replace them with just the ActorId and some kind of storage.

      The post was edited 1 time, last by skurmedel ().

    • RE: Questions about the Actor class


      But... what I don't understand is why IActor has an Update method. Nowhere in the source code (and I've tried using the search function on Google code) can I find that this method is actually used.

      Correct, it is never used in Teapot Wars. I think this function was provided in case you wanted to tick the actors every frame, but that's not how it works right now.


      The BaseGameActor seems to store enough information to be used in TeaPotWars. That is, it's a useful data container. But as I gather the structure proposed in the book is one of message passing (called events in the book), where things that listen to events update the game state.

      I guess the GameLogic would be in charge of updating the actors. Something that feels a bit iffy to me, won't this result in a gargantuan switch-block?

      You are correct that if you wanted to tick the actors every frame, it should live in logic. In this case, you'd override VOnUpdate() in TeapotWarsBaseGame and loop through the actor map. And yes, with the way things are now, it's possible to have a big event handling switch/case block.


      After some contemplation I guess my actual question is this: we have GameLogic, we have events, but what if I have a bazillion different types of Actors (Door, Hovering Banana, Headless Kamikaze) etc with different behaviour. Where do I manage this?

      In the Actor class, through the Update method? "Check we have zero health"... would the Actor notify the world about it's poor health?

      TeaPotWars seems (and I'm probably wrong here) to encode all this Actor behaviour in it's event handler. But with a growing number of actors, I can see this becoming a massive problem.


      We could have different listeners that implement the Actors behaviour, but what use would the Actor objects be then, we could effectively replace them with just the ActorId and some kind of storage.


      These are good points, especially the last one. That's essentially what I do in my home-grown engine. The way I handle such issues is to use a component based architecture. I have an Entity class that has nothing but a list of components. Each component represents a different aspect of that entity. I can mix & match different components for different behaviors. One component is the TransformComponent, which stores the position, orientation, and scaling values. I also have a Renderable component to handle rendering. One important component is the ScriptComponent, which is the only component exposed to the script side.

      One top of components, I also have something I call Component Systems. A component system is a class that registers with a specific component type and is notified when a new component of that type is created. It can then store a list of those components so they can be processed as necessary. Each component system has its own Update() function and knows enough about its domain to handle whatever it needs to handle.

      It's easiest to explain this with an example. Say I want to create a simple AI enemy. In data, I could define the entity as having three components: the Renderable component, the Transform component, and the AI component. There are two component systems involved here, one is the render system that lives on my Graphics layer (similar to View in GCC). The other is the AI system which lives in the Logic layer. The Transform component doesn't need a system because it doesn't need an update tick.

      Every frame, the graphics system loops through all of its components and decides whether or not that component needs to render. If it does, it adds it to the list. This is the list sent to the render thread. On the logic side, it loops through every AI component and tells the component to run the AI logic for that character. This is a virtual function on the AiComponent base class so it doesn't care what actually happens, it just says "your turn to update". As you can see, both of those components are decoupled from each other. The AI component has no idea it's being rendered and doesn't care. The Renderable component has no idea there's an AI update and doesn't care.

      Sometimes components need to talk to each other. For example, the AI component might need to tell the Transform component to change position. To do this, you simply send message notifying any component who cares what the new position is. This might trigger the physics component to validate the position (possibly triggering another message) and the transform component to update its position. Another method is to simply call into the component directly. You can ask a component if its entity has a component of a particular type and even get a pointer to if you need to, though this is typically discouraged. The idea of the component system is to make them as self contained as possible.

      Here are a few good articles on component based architecture:
      cowboyprogramming.com/2007/01/05/evolve-your-heirachy/
      garage.gaspowered.com/?q=su_301
      lambdor.net/?p=171

      -Rez
    • That sounds quite enticing. Things are starting to come together. And the book is good at keeping me from just playing with the graphics (the ultimate destroyer of my productivity :D)

      What happens when an actor/object is destroyed in your engine? I guess you could store the components related to a system in the system. But for those that have none, your Transform component for example? Or do the systems just keep references/pointers to a big bag of components?

      The only problem I have with this is interdependencies, and interdependent initialization of components. But I think even that can be solved pretty often, and shouldn't be a huge problem.
    • skurmedel,

      Regarding logic, my plan is to create custom Process' in the Game for things that need an update call, and everything else will just register for events. My engine still needs a bunch more work and refinement, so we'll see how that actually turns out, but I liken it to how GUI development in WPF (and lots of other frameworks) works.

      Say you create a button. If you want to move that button constantly, you'd need to set up a timer (Process) that would frequently update it. However, if it's just reactive (like a door in a game), then all you do is register for the button's Click event and wait. In a door example, it really just needs to register for is some sort of ActorInteractionEvent. In that event handler you'd just change from open/shut and create processes for animation, dispatching sound effects, whatever else, but that would be the only place logic happens (in this simplistic example). In order to use a door then, you just create it as a component, add it to your list of components, and then position it accordingly.

      For example, I'm currently working on a basic Console implementation on the Engine side, where in its constructor it registers itself with the event system for key presses, and adds itself to the graphics system (visibility set to false by default). Whenever the '~' key gets pressed, it toggles its internal state and visibility. When it gets destroyed, it unregisters itself. As a result, you have the Console which is effective stand alone (though it does do its own position and the '~' is currently hard coded, so multiple would be pointless/bad), that all you have to do is create it and it's good to go.

      Using this sort of design, to add an enemy to your level, you basically just create a new EnemyLogic instance and add it to your Game logic's list of current enemies. The class itself takes care of adding something to the graphics system, registering itself with AI, registering itself with physics, etc, etc. Maybe you pass in parameters for what sort of enemy, or maybe you subclass it for specific enemies. Once you have this logical class set up, then it should lend itself nicely to scripting, where all you have to do is create the enemy, and possibly register some of your scripting functions to callbacks in the class (if scriptable logic is needed).

      Just FYI, all of this is based on how I'm separating between my "Engine" and "Game". All logic lives in "Game", so that's where the logic classes are, and there's basically a callback that serves as the game's entry point (where it should set up menus and whatever else, and then register for callbacks to New Game, Load Game, etc.). The Engine contains a bunch of classes and base classes. Most likely the Game can just rely on Engine classes for Physics, Graphics, AI, etc., and registers for their existing callbacks/events, but if need be the Game could subclass and implement its own.

      James

    • What happens when an actor/object is destroyed in your engine? I guess you could store the components related to a system in the system. But for those that have none, your Transform component for example? Or do the systems just keep references/pointers to a big bag of components?

      The entity has a list of strong pointers to the components it owns (in fact, those are the only strong pointers to components in the engine), so when the entity is destroyed, all of its components are cleaned up regardless of whether or not they were owned by a component system. Inside component systems, components are stored as weak pointers so when an entity is destroyed, no notification is necessary. The component goes away and the system cleans up it's list as it iterates through it.


      The only problem I have with this is interdependencies, and interdependent initialization of components. But I think even that can be solved pretty often, and shouldn't be a huge problem.


      Regarding the interdependent initialization orders, it doesn't matter. Entities do not care what order their components are initialized in and components don't care what other components might exist during initialization. This was something I made sure to avoid. Even still, the initialization order is completely deterministic. Components are guaranteed to be initialized in the order they appear in the entity's definition data file. But again, if the component is written correctly, it doesn't matter.

      Regarding dependencies on other components during run-time, you can never get away from it completely. Let's say you have a creature that needs to move. The AI Component is the one that knows where to go and the Transform Component is the one that knows where we are right now. We need to read the transform and then update it. How? There are two basic schools of thought here.

      First, we can simply have them depend on each other in some way. The AI Component can query its entity owner and ask for a transform component. If it gets one, it can ask for the position, do logic, then tell it to update to the new position. The advantage to this is that there is one, single authority for the transform on an entity. There are no caches to get out of sync and the logic itself is much simpler. The disadvantage is that now the AI Component assumes a transform component exists. If we use a different method for storing position (maybe a physics component), we have to modify every place that grabs the transform component.

      The second way is through messages. The AI Component has a transform cache that it uses for all calculations. When the transform is updated, the transform component sends a message to all components that care saying that there's a new transform. The AI Component would register for this message and update its cache. It would also send a message requesting that it update the transform of the entity to some new position. The advantage here is that you've decoupled those systems, so changing where the transform is coming from doesn't require you to edit another system. The disadvantage is that those caches can get out of sync and you end up with a lot of switch/case event handlers. It's also a bit slower.

      I've done both ways in the past. At Planet Moon while working on Drawn to Life, we used the message system. We had three different transforms that described an entity that all needed to be synched up. The RenderComponent, the PhysicalComponent, and the LogicComponent all had their own transforms. It caused a HUGE amount of very difficult to find bugs.

      When I worked at SuperEgo Games, we used the other method of just directly calling into the components. This worked out okay for the most part, except that we ended up having certain dependencies everywhere. The SeClump was a component that represented the model in 3D space and was all over the place. If the class ever changed in a significant way, it was a major pain in the ass to fix it all. It also turned into a dumping ground for common functionality.

      For my own engine, I tried to choose a method that gave me a little bit of both. The way I try to balance it is by distinguishing between component interfaces and component implementations. The object system has a number of component interfaces it knows about. Each component has a component interface that it conforms to, linked by an ID. The implementation doesn't matter as long the interface is conformed to. The caller can never get the implementation, only the interface pointer. For example, here's my Renderable component:

      Source Code

      1. class Renderable : public EntityComponent
      2. {
      3. public:
      4. const static EntityComponentId INTERFACE_ID;
      5. // construction
      6. explicit Renderable(void) : EntityComponent(INTERFACE_ID) {}
      7. // interface
      8. virtual bool GetRenderData(SpriteRenderCommand* pOutRenderData) = 0;
      9. virtual bool IsVisible(void) const = 0;
      10. virtual void SetVisible(bool isVisible) = 0;
      11. };
      Display All


      I can have as many implementation sub classes as I want, they just have to implement those virtual functions. These components are also mutually exclusive, so an entity can only have one component that conforms to the Renderable interface.

      It's not perfect, but at least I'm only creating dependencies to thin interfaces instead of implementations. In the case I mentioned above where the transform gets replaced by the physics component, it's easy enough to write a PhysicsTransform implementation of the Transform component that grabs the Physical component (if it exists) and returns the appropriate values. This is all done behind the scenes in the new component implementation, so no other code is changed. In fact, once the new component is written, all you have to do is update the entity data to use the new component. This gives me the best of both worlds: I am relatively decoupled from other systems and I still have one authoritative place for something to live so I'm not dealing with messages all over the place.

      It's always a trade-off no matter what you do. :)

      -Rez
    • RE: Questions about the Actor class

      Thanks for the ideas guys. I like both of your ideas.

      It's especially valuable hearing from people that's done this stuff for real and seeing real implementations.

      I found some other discussions but it's all very theoretical which sometimes gets frustrating. I'm currently a web/systems programmer by trade and know that usually you can't get everything perfect. Sometimes things have to be a bit ugly (especially with JavaScript, everything is ugly.)

      I'm working in a component system right now and the other ideas in the GCC-book. Then when I've gotten the basic components and actors working I can finally render something :)
    • I had the "joy" of working with an entity-system which tried to modify other components in the same entity and it quickly became very ugly! (nebula device uses something like that, too).
      my problem was that I had transform-informations in a component and aswell in the physics system which needed to be in sync.

      what worked really well for me was a slightly changed approach to entity systems: your component is a pure data container without any functions working on them. instead you have functions working on entities with special components, think you have entities with ai- and transform-components and updating does a function (for example moveAiEntites) which does work with the ai component and sets the transform-component of all entities with an ai-component. so your entity is a dumb container for components and other functions work on them.
      the nice advantage of using this update mechanism is that you can split the update of the entites across multiple cores/processors easily!

      I have not invented this style, so here is the original reference:
      t-machine.org/index.php/2010/0…ity-system-1-javaandroid/
      but I have implemented a c++ version which can be found here
      unseen-academy.de/snippet_component_system.html

      to test the entity system I've implemented a simple nbody system which runs on multicore-machines, also found with source code on my webpage.

      The post was edited 1 time, last by questor/fused ().