Wiki

Clone wiki

agtools / Tutorial 4f - Smarter Entities

Outline

ts4f.png

Back to more fun areas again. The coordinate space topic needed covered because it crops up so often in games and is easy to mess up, but we're done with that and can spend our time now doing things that provide content for the game design.

This time we're going to change the entity behaviour to do something more complex - a procedure that seeks target coordinates. Each entity will have its own target coordinates to seek, but the behaviour will be the same for all entities.

We're still working in screenspace but that part doesn't really matter. It could work either way.

Setup

This time, instead of assigning a different velocity to each entity instance spawned, we'll assign an identifying number or index:

    s16 index = 0;
    penew = EntitySpawn(EntityType_LETTER_X, g_viewport_worldx, g_viewport_worldy);
    EntityMakeRelative(penew, g_viewport_worldx, g_viewport_worldy);
...and our change...
    penew->wz = index++;

Now each entity instance is uniquely numbered. We use the wz field for this because it's free. We could have used one of several others instead, but we need to be extra careful to avoid giving any field more than one purpose in the same entity behaviour (at least, at the same time). More on this later.

Mainloop

Once again, no changes here.

The Tick Function

Everything new is going to happen in or around the tick function.

Rather than paste the letter_fntick source here (its longer than the others) its sufficient to describe what its does at a high level:

  • Find the intended target coordinates for this entity's assigned 'index', using a predefined table.
  • If the entity is below or above the target y coordinate, seek up or down accordingly, one pixel.
  • If the entity has matched y then start seeking the target x coordinate.
  • Stop when entity coordinates are a match for both y and x target coordinates.

The Entity Dictionary

And no changes here.

Summary

The result should be that all letters begin at their spawn position (top left of the screen) and move downwards, then move horizontally until they each find their target coordinates.

The entities are acting independently and each complete their behaviour at different points in time - they have different ending conditions.

The code changes are small. All the changes are really focused on the entity behaviour itself, which is really how it should be.

Additional

For the less confident with 'C', here some notes on tables. The use of tables is common for AI code so getting a handle on it is a good idea.

The table lookup for this AI was implemented in 2 steps:

A table of pointers to (x,y) pairs, with each (x,y) pair itself a table of 2 s16 signed integers. The pointer table is first indexed using the entity's number in wx, and that pair is indexed with [0] and [1] to recover (x,y) respectively.

There are many ways to do this in C, and many more in C++. And this is certainly not the most efficient way. I chose this method mainly because it works for something other than pairs, with minor edits - so the pattern may get reused in other tutorials for other things.

An alternative way would be to encode a single table with no pairs - just { x,y,x,y,x,y } etc. and index the table with a << shift or x2 multiplier. This is more of a m68k assembly approach. That's fine also.

In C++ there is a multitude of ways which will eliminate some code/syntax but also obfuscate whats going on for the unfamiliar. So that route will be avoided, even if it does provide benefits in practice.

Updated