Game Enity System & Processing Entities

Started by
7 comments, last by signal_ 15 years, 6 months ago
I am building a simple game entity system for my current project. Just wanted to run it by gamedev people for constructive criticism and for one question about processing entities. This is a tilebased 2D game written in C++ and SDL with OpenGL. The terrain tiles are 32x32 pixels. My requirements for this entity system are as follows: 1. There should be a method to inquire what entities, if any, are on tile (x,y)? This method will return entity IDs of the entities on that particular game tile. 2. There should be a method to inquire what entity ID corresponds to what type of entity. For example, we ask what is entity 5? Answer: Entity (5) is alien(4) -- read as, "Entity five corresponds to alien number 4." In this case, "alien" is an entity-type. 3. Entity-types will be classes. 4. There will be an Entity class that holds all the information. Within the entity class, as private members, will be vectors of entity-types. So, points (1)and (2) can be implemented using STL std::map or std::multimaps. (4) will be std::vector. Example organization:


class Entity 
{
    private:
        int entity_ID;
        // std::vector for aliens from Alien class
        // std::ector for bullets from Bullet class
        // std::vector for whatever


    public:
        // getEntityAt(x,y) function
        // whatIsEntity(entity_ID) function
        // et cetera....

};


How does this sound? Any glaring errors or oversights? Two Processing Questions: 1. If you have, let's say 5 entities, you can process the AI for each every frame. But let's say you have x entities where x is a large number? In the interests of processing efficiency do some people process entities 0 thru 33 one frame, entities 34 thru 66 two frame, entities 67 thru 100, three frame, with a 3 frame cycle for 100 entities, for example? Basically, what is a good strategy for processing entities when the entity number becomes large? 2. The distinction between "On Screen" and "Off Screen" entities. Obviously, Onscreen entities (OSE) should be processed every frame for the interest of continuity for the player's perspective. But what about Offscreen entities (OFFE)? One extreme would be to not process OFFEs and once they become OSE start processing them again. But, this seems like it could be done better. Any advice for me? Any feedback will be greatly appreciated. Thanks.
Advertisement
Quote:Original post by signal_

2. There should be a method to inquire what entity ID corresponds to what type of entity. For example, we ask what is entity 5? Answer: Entity (5) is alien(4) -- read as, "Entity five corresponds to alien number 4." In this case, "alien" is an entity-type.


Usually entities are used as alternatives to strongly typed design.

Instead of worrying whether something is or isn't, focus on what it can do. For example, don't worry if a thing is alien. As if it has blood, then check if that blood is green.

The benefit here is reduced complexity - if you want to make something killable, add health component to it. If you want to make something drivable, add steering component.

No need to worry whether it extends a certain class or if it's of a certain type or if signature matches something.

Quote:2. The distinction between "On Screen" and "Off Screen" entities. Obviously, Onscreen entities (OSE) should be processed every frame for the interest of continuity for the player's perspective.


Again, forgetting about strict typing.

Each component registers with its respective updater. Components which are renderable will be updated on render, components with physics component will be updated by physics, AI by AI and so on.

Entity (the container) here is mostly secondary, most of processing revolves solely around components.
On the first question, Antheus is speaking about something closer to a component-based entity system, I believe. There are pros and cons to both approaches, but I can't speak to the component-based design because I am only familiar with the concept and have not actually implemented or worked with it myself. The big danger, IMO, with the class-based model of things is is that, almost invariably, everyone makes their hierarchy too deep and too complex. Not every entity should be its own leaf in the tree of entity inheritance, in fact, it is extremely bad practice to do so.


...Gotta run, to be continued...

throw table_exception("(? ???)? ? ???");

Thanks for the replies guys.

I googled "entity system" and "game entity system" last night and found a good article regarding component vs class based entity systems. From what I could gather, the component based system, although it is more troublesome to setup and establish, outperforms the class based system in terms of ease of use and organization.

Currently, I am doing a class based system since I can sort of envision that better than the component based system. But, I am definitely not opposed to component based, just need to learn more.

I had made a messy, confusing system many months ago, but my current incarnation should be better; however, it is still class based. I am planning on integrating it into my current project once it is finished. Just want try it out and see if it works okay. I am trying to organize it and comment it very well so that I may possibly release it for critique. We'll see.

In any case thank you for yr contributions Antheus and Ravyne.
To continue, on the second question...

In the past, I've used the concept of "area of influence" to guide what entities are active. The area of influence is some superset of the viewable area that can be thought of as the area in which your presence affects the potential behavior of entities -- in other words, the area in which you could be seen by an off-screen enemy and attacked by him, for instance. These entities are processed, but not drawn unless they also fall into the viewable area.

The size of this area is chosen according to how much border space is needed to ensure a reasonable level of perception of continuity. Let me give an example. If you had no such system and only updated entities that had come into the viewable area because the player's movements, the player's sense of continuity is upset by the fact that an enemy guard on patrol will pause each time the player's movements take said enemy out of the viewable area. When the player approaches again, the guard is still at the exact position and state he was when last seen. Furthermore, such a system is easily exploited -- Position the guard where you want, move off-screen, sneak around behind him without getting close enough to re-activate him, viola -- he's easily trumped.

If, instead, the guard was active for the viewable area and, say, the surrounding 8 screens worth of map, the world becomes more believable because you never see the start/stop -- The guard will continue his patrol and actually walk into the viewable area of his own accord, for instance. This system is not easy (if possible at all) to manipulate -- at the very least, the player's attempts at manipulation are operating blind, and at its worst a sufficiently large AOI can make the system unmanipulable (at least in regards to the type of manipulation I've described above.)

throw table_exception("(? ???)? ? ???");

Thanks for the additional response, Ravyne.

The AOI stuff is a good idea, especially extending the area beyond the viewable screen to ensure the illusion of continuity. I had been toying around with the idea of AOI, but with an added twist. Please let me know what you think:

The system will still use AOI, but entities will have two different member functions: microUpdate() and macroUpdate(). Entities that are in the AOI will call the microUpdate() function and entities outside the AOI will call macroUpdate().

microUpdate() will be the complete update function. It will allow the AI to make use of more cpu expensive algorithms, etc. macroUpdate() will be the "lite" update function for entities not in the AOI, working on the macroscopic level -- no cpu-intense algorithms here.
Certainly that's a valid approach -- its akin to switching high-detail 3D models for low-detail ones when they are further away. It's scaling fidelity to match perception, just applied to AI instead of models, textures or sounds.

I would wait, however, until you know that running the detailed AI routines for everyone in the AOI is too intensive, and that the bottleneck is not elsewhere.

There are also other possibilities to reduce the burden of AOI entities, such as running their AI at less than nominal speed. For example, guarantee that all entities in the viewable area are running full-speed, but allow the remainder of entities to be split into 2/3/4 groups and alternate running the group's AI in a round-robin fashion once per frame. Just make sure that their actions are scaled to compensate (this should be decoupled anyway) or, in other words, just because the AI for each group updates every other frame, doesn't mean the entities should walk at half speed.

Which approach is better for your situation I don't presume to know, but this one has the distinct advantage of not needing to write, maintain and orchestrate two different AI routines.

throw table_exception("(? ???)? ? ???");

signal_, I wouldn't worry about the whole entity-as-blob vs entity-as-component-container approach if I were you. Before you refactor a deep hierarchy into components, you first need a deep hierarchy... depending on the complexity of your game, you might never have this problem to begin with.

I think, however, that Antheus was not talking about just that. It's also a question of the levels of abstraction that you (should) introduce in your design. Although using simple composition to add functionality to your entities will keep your code cleaner.

Firstly, I'd say your concept of Entity is a bit different from what we usually mean when we say that word (although the word Entity is certainly overloaded). What your Entity looks like to me is more like an EntityPool (or maybe EntitySoup or EntityList or whatever is fashionable these days). That's fine by itself, you need to store those entities somewhere after all. What you don't need are separate lists for each entity-type. Let's say you want to update all your entities. Consider the following code:

for each alien in aliens    alien.update()for each bullet in bullets    bullet.update()for each door in doors    door.update()    for each npc in npcs    npc.update()


Do you see a pattern here? It's code repetition. Now what Antheus is telling you above is that you need to abstract at a higher level (polymorphism), so that you can just keep one list of entities and write:

for each entity in entities    entity.update()


Now you can treat all entities the same. If you need alien-specific behavior, put it in the actor class which is a subclass of entity. You should avoid having an alien class - you can instead reuse the actor class for aliens, npcs, and players, simply by changing the (perhaps attached? -> composition, but without a full-blown dependency-checked runtime-variable entity-component system) ai controller or having the actor run a different finite state machine.
Thanks for the replies, Ravyne and lightbringer.

Ravyne: you give me some things to think about. I guess I'll mess around with those ideas and try to get something satisfactory up and running.

lightbringer: I get yr point about my Entity class. I should rename it to EntityList or something like that. As far as yr other point, which I am very appreciative that you pointed out, regarding abstraction and polymorphism has kind of prodded me to implement the system in the fashion that you advocate.

Today, while I was writing the generic Entity class, I thought to myself, "this seems inefficient; I will be retyping a lot of the same code over and over." So, point well taken. I am now trying to code the system as you described.

EDIT: so, I made most of the modifications & now my code is cleaner and must execute less lines of code too! Thanks everyone. whoot polymorphism & abstraction.

[Edited by - signal_ on October 22, 2008 9:32:08 PM]

This topic is closed to new replies.

Advertisement