La Tour Part II - Drones, NPCs


Drones

Finally comes the magic: drones. Where my preferred design differs at least a little from other designers is that my objects do not have per-frame logic. Instead, objects are essentially static, and respond only to events (such as clicking).

Diagram showing relationship of drones to other engine components

Drones are essentially entities that only have per-frame update logic. They are not tied to a specific object, and do not have a physical or visible representation.

Enemies are represented by drones. When we want to place for example a lizard, what I do is select the lizard object and add it to the map. Next, when the map loads it does a quick search for all objects that have a special property: "is_enemy_object". Next, it asks the object what type of enemy drone it should create, and creates that drone. Finally the drone is linked to the object itself and the object is now "drone controlled" and can attack/etc.

More on the Above Diagram

First, the green part is what I'm calling "common practice". This is the normal way to organize game logic, with everything more or less wrapped into one ball. This can work well particularly for small projects; in fact for smaller projects this is precisely what I do.

The right hand part is how Texas is structured. I have a class called "Sprite" which is fairly a misnomer. Think of it as a physics object; it exists in a physical space. Tied to it can be three types of things: first, a renderable. Renderable just defines what it looks like, for instance it could be a cube, a flower, a dresser, or a burning fire.

Also attached to a sprite is a soundable. This is (you guessed it) a sound effect generator. Since the sprite represents the physicality of the object it's fairly easy to do things like locate sound effects in 3D space, etc.

Finally there is the real magic, "mover". Mover is like a special kind of AI that knows only how to move things around. It does not animate or try to coordinate with animation, it only moves the sprite's x/y. Movers handle collisions, can do interesting things like apply gravity, and in fact can be in some cases combined together.

These four classes are in C++; they are pretty bare-bones to look at, I'd estimate only a few thousands lines all told. But they are fast, efficient and they get the core low-level work done.

Next comes Object. This is a Lua class with enormous functionality. In fact it's sort of like an overgrown version of the Object class on the left. It interacts with and in some ways defines the actual game engine. There's too much to describe here, really!

... Which brings us to the Drone class itself. As you might gather from looking at the above diagram, Drones can be really complex. In fact, there is so little "set behaviour" for a drone, they can be almost anything. Probably they would benefit for a little bit of categorization; for instance drones that are attached to the player, drones that are used for area-wide effects, and so forth. But the interface stays roughly the same and so they are just sort of lumped in together.

Global Drones, NPCs

Drones do not have to be tied to an object and they do not have to be created by an object. Moreover, they don't even have to be tied to an area!

When the game starts, it creates a list of "npc drones"; one per NPC. Right now there are 34 NPCs in the game, and *they are active at all times.* The game engine has facilities for pathfinding even on areas that aren't loaded into memory (this is a really nice trick that I'll have to explain later) so an NPC can do something along these lines:

- Suppose the NPC is in the field, farming.

- Now we notice that it's 6pm, time for dinner!

- Ask the game engine for a path from our current position to the dinner table.

- Start a counter within this path, so we know where we are in an area even if the area is not loaded.

- Each nth of a second, move to the next step.

Now, simultaneously what is going on is we are:

- Check if the area has changed since the last frame update.

- If it has, then check if the area is the same as our current path area.

- If it is, then add an object representation for us to the current area so the player can see us/talk to us.

- "Pause" the control logic above, and use a different walk algorithm to walk to our destination point in-area.

- The above is in case the player stops to talk to us, etc.;

- Once we leave the current area, the above control logic resumes

As you can see, NPC logic is fairly complex. The main trick is that we don't keep the entire world in-memory, but we want NPCs to exist globally at all times. The game really does maintain a daily schedule for all NPCs and tracks them at all times. If you follow NPCs around, you will see they get into all sorts of trouble!

Next Time: The Editor

The next part in "La Tour" will have some screenshots and an explanation of the in-game editor that I use. Stay tuned...

2010-05-31


◀ Back