Game Actor and System Architecture

Started by
3 comments, last by crancran 9 years, 9 months ago

Hey guys, I've been looking through some books and online on the topic of game engine architectures and how actors factor in. A big one was from this thread right here (http://www.gamedev.net/topic/617256-component-entity-model-without-rtti/page-2). The way I understood it is like this:

Actor Component: Defines some relatively independent data that represents some isolated attribute of a larger being. For example, a actor for a gun might have a component for the gun's model, a component for the amount of ammo, and a component for the damage properties of the gun.

Actor: A list of actor components.

System: Runs the game logic, has a list of actors on which the system operates. An example, the physics system has a list of actors that have a physics object which it uses to check for collisions and notify's the actors and their components when a collision happens.

This is where things get kind of shady. A system is supposed to carry out game logic but it doesn't make sense for all the game logic to be done in a system. Using the physics system example, it makes sense for the system to find collisions but when a collision happens, it doesn't always mean calculate the reflection of both objects. Sometimes, I might be colliding with ammo so I should be picking it up instead. Stuff like that doesn't make sense to be done in the system but rather in the actor/their components.

This works nice but then it makes defining the components a bit more iffy. If the ammo actor is supposed to have some way of reacting to a collision, how does the physics system know which component it should be looking for? There might only be one type of component that is a physics collision model which could describe the collision model for the ammo, but that same component could be used for a rigid body on another actor which should react by physics laws to a collision.

So the way I understand it, here is how it roughly looks right now:


class Actor
{
    std::vector <IActorComponent> m_ActorComponents;
};

class IActorComponent
{
    // will be overridden and will have some new properties
    virtual bool VInit ();
    virtual bool VDestroy ();
};

class ISystem
{
    virtual void VInit ();
    virtual void VUpdate (unsigned int deltaMs);
    virtual void VDestroy ();
};

And here is a implementation:


class CollisionModelComponent : public IActorComponent
{
    std::vector <Vertices> m_VertexArray;
};

class PhysicsSystem : public ISystem
{
    std::list <Actor> m_Actors;
    void VUpdate ()
    {
        for every actor
        {
            if actor collided
            {
                // What do we look for here? How do we know to run ammo collision response or rigid body response?
            }
        }
    }
};

You could make a collision response actor component which tells the physics system how to respond to a collision but then you have a issue where the ammo collision response has to have access to the ammo component.

In my code, the actors are created from xml files and each actor is created the same through a factory class. In it, I loop through all the nodes of a xml file and apply the properties to the given component at hand. All components override the virtual VInit function which takes no parameters. If I wanted to create a dependancy between ammo component and collision response component, I would need to somehow pass the ammo instance to the collision response through the init but not all components need a dependancy so it doesn't make sense to have it by default pass a pointer to some actor component through VInit. There could also be cases where we have multiple dependancies which complicates the process.

Is there another way to do this or some way to restructure or apply constraints in order to make this architecture work? It's a really clean architecture if one where to be able to make everything separable. Any help?

Advertisement

I haven't read (yet) the thread you've cited. The following is just the approach I'm following in my own implementation of CES (which uses sub-systems, and allows for both data components and behavior components, the latter as some kind of plug-in for sub-systems).

Actor entities can be equipped with components that belong to perception. Besides the visual and aural perception (I'm playing with thoughts about olfactorial perception), there is also touch perception. All of them are used for AI purposes, but the latter one is also used to apply physical damage. Conceptually, the interaction of a stimulus (something that can be perceived) and a receptor (something that detects stimuli and assesses it against thresholds) result in an actual perception.

So this concept distinguishes collision for touch perception purposes from general rigid body collision. It introduces a specific group of colliders (the geometry of the touch stimuli, usually line-strips) and collidees (the geometry of touch receptors, usually some bounding volumes), between which an unilateral collision detection has to be done. The immediate result of collision detection is just to hand over the stimulus to the receptor for further processing. The linked in damage sub-system isn't sufficiently parametrized with the boolean "there is a collision". Instead, it uses attributes of the stimulus together with "the stats" to compute the resulting damage (which may perhaps be zero).

I'm running a sub-system that is called SpatialServices. This sub-system allows for uni-lateral collision detection (and proximity detection for e.g. the other senses) as is described above. The physics sub-system, perhaps a black box, isn't used for this purpose.

Hope that helps a bit smile.png

What I have done for collision-type work is, first, define what objects each entity can collide with (collision meaning cannot occupy the same space...think top-down 2d game). So, an entity can collide with a bullet, and it can collide with a wall. It CAN'T collide with a teleporter, but it can use it if it's touching it.

Also, I would create a collision component, and give it to each entity that is colliding with each other. So, the collision component has a link to other entity that is being collided with. If it's a bullet hitting a player, then the damage system would remove the bullet entity (thus, the collision entities), and damage the player entity.

If it's a wall hitting a player, there isn't a system defined for it, so the physic system just handles it, and does the proper collision response. Once the player stops touching the wall, the collision component is removed between the 2.

That might not be the best way to do it, but it should give you an idea of other ways to do this.

My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)

Hmm okay I'm starting to see a path through this. The perception idea is super cool but I probably don't need to implement something as complicated as that for my game in terms of touch, sound, smell etc with the stimuli. It is something I will want to look at in the future just because it sounds so cool and plays well with some other ideas I have bouncing around in my head. Okay so I think I figured out a nice way of organizing everything:

To start off, actors are as always just a id and a collection of components except now they are a collection of component id's instead of pointers.

Components of each type are instead stored in each of their own component managers which might be just a list, a vector or a map. This would allow for future endeavors to compress the components since we know each component manager only holds variables of one component type. As an example, if my component manager holds orientation components for all actors, it could apply some sort of spacial optimization to all the components or reuse similar coordinates if such compression where ever needed. It also has the capability of being more data oriented although since my project isn't going to be huge, I'll just leave them as maps. Each component manager has to only implement simple methods like add/destroy component and get component manager type.

Components are same as always except now initialization will be a little different. So before, I just had a Init method for the actor to call Init on all components but now I added a post init which could be used to resolve all component dependencies. A orientation component won't have a dependency so its PostInit method will be empty. But something like a physics collision component could add in post init a dependency to the orientation by going through the owner actor pointer and searching for a component of type orientation. I could also have it add a collision response component/s which could be used to resolve collisions in the physics system when they happen. The benefit of post init is that we know all components are created, we are now just linking them together sort of like your program compiles everything, and then links.

In PostInit, we could also attach our components to all the systems they have to be attached to. So a physics collision model could check to see if a orientation and collision response component exist on its current actor. If they do, it can link them up and attach itself to the physics system. Otherwise, it could signal an error or maybe run a default although I would rather signal an error.

As for BeerNutts method of solving the collisions, I think with the system I described above you could implement it since I sort of wrapped my head around settling dependencies between components. I do have two options however. I could make multiple collision responses for collision with different types of actors (although this creates a issue since a actor doesn't really have a type, its just a bundle of components). Or could make one large collision response component that handles multiple collision types. Both are a bit weird since a actor doesn't have a type. Would you somehow grab it from the collision model component which could potentially hold a type or add a type to each actor by default?

There is another thing that bothers me that might be a bit more physics related but still something I think needs to be understood by me. Lets say two teleporters collide (yes this shouldn't ever happen but there could be other similar situations). Both objects have equal priority in terms of resolving the collision so which one would take priority and teleport the other to the teleporting location? Since its very likely two colliding actors will try to somehow resolve a collision, if both collision responses want to modify the other actor, it has to be somehow decided which one gets priority over the other and applies the modification first.

I was also of thinking of just having a collision response actor that implements rigid body responses to collision, instead of having it in the physics system. That way, the physics system only ever worries about finding collisions and calling the appropriate collision response calls based on whatever priority. By doing so, the actor components technically implement all the systems while the system manages them to have everything work as a group.

Thanks for all the help so far!!

EDIT: Hmm, looking at it now, I think its better to skip having the component managers in the first place since for now, they don't really make a difference other than take extra implementation time. Maybe in the future I should add them in but everything else should apply as long as id's are changed to pointers.

This is where things get kind of shady. A system is supposed to carry out game logic but it doesn't make sense for all the game logic to be done in a system. Using the physics system example, it makes sense for the system to find collisions but when a collision happens, it doesn't always mean calculate the reflection of both objects. Sometimes, I might be colliding with ammo so I should be picking it up instead. Stuff like that doesn't make sense to be done in the system but rather in the actor/their components.

This works nice but then it makes defining the components a bit more iffy. If the ammo actor is supposed to have some way of reacting to a collision, how does the physics system know which component it should be looking for? There might only be one type of component that is a physics collision model which could describe the collision model for the ammo, but that same component could be used for a rigid body on another actor which should react by physics laws to a collision.

Look at the situation from the opposing side and it might make a bit more sense. First, your physics system simply steps your simulation and determines where collisions have happened. It emits those collisions in some fashion for the related actors and it's done. You then have other systems that listen or inspect the actors for these collisions and respond accordingly.

Taking your example, the bullets which are to be collected upon collision are actors maintained in a pickup system because they have a pickup component. Upon a collision situation with these actors, it looks at the collision component to see whom it collided with. If the collision was with a player, it simply adds itself to the player's inventory in question and then signals the actor (bullet) to be removed. In the case of shooting a bullet at another player, this bullet is managed by a damage system because it has a damage component. Upon collision, the damage system determines the collision actor list, calculates the damage and emits the damage caused to the related actors. The damage system then signals the actor (bullet) to be removed.

Now you can add coins and other pickup items that go into the player's inventory by simply giving them the same pickup component. The pickup component can have flags that determine what it does upon pickup (add to inventory, increment ammo counter, increment powerup level, etc). But in the end, the reaction between the actors is identical, collision implies pickup.

Similarly, you can add additional things that do damage such as melee attacks, castable spells, falling rocks, etc. The damage system is then the place that inspects that collision list of actors for a given actor that can do damage, determines the damage done and emits those events to the related actors.

Like with anything in programming, break things down into their smallest yet reasonable interactions and you'll see how quickly things can come together, particularly when you are working with an actor/entity system.

This topic is closed to new replies.

Advertisement