This page is a mirror of Tepples' nesdev forum mirror (URL TBD).

# Script-based character movement

As a little preparation for the start of my new game that I want to begin in March, I'd like to talk about a topic that's less about actual code and more about best practices and script definition:

The movement of opponents.

In my last game, I simply had individual functions for every character. This was justified because their movements were vastly different: One only walks back and forth, one only jumps, one flies around without being hindered by the environment etc.
Also, I had only seven opponents, so a scripting engine would have been overkill.

But my new game is supposed to be a top-down action adventure, similar to "The Legend of Zelda" and "Final Fantasy Adventure". And this game, as an UNROM game, will probably have a huge bunch of opponents. Maybe 20-30 or so.

That's why I intended to create a data-/script-based approach: One function MoveOpponent that simply reads values from an array to decide what the opponent shall do next.

I think I could come up with something if I think of it:
For example, the first value could be an indicator of what the next values are supposed to be, i.e. each value stands for a sub algorithm like "walk in straight line", while the next value or values are parameters.

But I wanted to ask whether there's an established way to do this in an efficient and space-saving way.
Are there algorithms or general descriptions on how to implement opponent behavior of simple adventure game opponents?

And is there any knowledge on how the famous games did it?
What does the algorithm look like that decides that a Moblin walks in straight lines, occasionally turns to the side and shoots arrows while a ghost flies in certain patterns and cannot be stopped by walls?
Did anybody already analyze the "Zelda" ROM regarding this?
Quote:
is there any knowledge on how the famous games did it?

I only know about an in-depth analysis of the PacMan ghosts.

EDIT. In my own games, I have a list of moves a character can do, and a series of 'if then', count down, move X squares, switch moves based on (wall reached, player position, some counter, random, etc).
Random tip: I've found a good way to quickly visualize mechanisms (enemy AI, but not limited to) and compare outcomes of versions, is to start up Xmind (or freeMind, though i haven't used that), and use it for flow charting rather than mindmapping. There might be free flow chart software, too.
This isn't much more than a guess, but I imagine most games of the era - even Zelda-esque adventures - just used program code based on state machines to control enemy AI, rather than writing full scripting engines. I know a few games with full, decently documented disassemblies - Metroid and the 16-bit Sonic games - do things that way. Sonic 3+K in particular has some fairly sophisticated scripted sequences, and everything's still written in plain old assembly.

That said, the book Retrogame Archeology has a section on interpreters; while I don't believe any of them are interpreters for exactly the kind of scripting you're looking for, it might be worth looking in there for some ideas?
dougeff wrote:
I only know about an in-depth analysis of the PacMan ghosts.

I'm not so much interested in how individual characters move (Blinky always targets Pac-Man's sqare, Pinky always targets the square ahead of Pac-Man. One ghost walks through corners from the left, the other one from the right etc.).
It's more about the data format that is used to save the behavior.
I guess this cannot be applied to "Pac-Man" anyway since I assume they simply hard-coded the behavior of the four ghosts individually.

dougeff wrote:
EDIT. In my own games, I have a list of moves a character can do, and a series of 'if then', count down, move X squares, switch moves based on (wall reached, player position, some counter, random, etc).

Is this a series of general purpose functions and every time you add a new opponent, you simply need to declare a new data array with values that describe his behavior?
If yes, the details of the data might be of interest. (In a general description way: Which byte stands for what etc. I'm not talking about posting the source code that actually reads the data and updates the screen, only some words about the data itself.)

WheelInventor wrote:
Random tip: I've found a good way to quickly visualize mechanisms (enemy AI, but not limited to) and compare outcomes of versions, is to start up Xmind (or freeMind, though i haven't used that), and use it for flow charting rather than mindmapping. There might be free flow chart software, too.

As I said, I'll probably be able to come up with my own mechanism if I think about it. If I need a chart, I could surely find software or draw it by hand.
But my question is more whether there are established ways of doing enemy behavior in a game that has not only a handful of NPCs, but a huge number.

I don't think that all of these characters were implemented in code individually:
www.spriters-resource.com/game_boy_gbc/ ... heet/33378
There must be some kind of general-purpose functions where each character simply has parameters that are applied to the functions.

And I'd like to know whether these old official Nintendo games used well-established mechanisms. And whether we know anything about the details of the "AI" in the same way we know exactly how levels in "The Legend of Zelda" are stored.

This isn't much more than a guess, but I imagine most games of the era - even Zelda-esque adventures - just used program code based on state machines to control enemy AI, rather than writing full scripting engines.

How do I have to imagine this in the context of games? Can you please describe a simple example?
Ah, i see. Beside the well commented metroid disassembly, i haven't read much about it.

If there are many types of enemies and/or many desireable behaviours, it really makes sense to have a simple bitwise flag array to check whether they hook in to various common AI routines. They could be neatly organised in condition/trigging categories. When a condition is met, every set bit within that table trigs the execution of the corresponding AI fuctions for that instance of the object type.

MapHit:
doRevertCurrentDirection
doRandomNewDirection
doLeftTurn
doRightTurn
doStop
doExplode
MapHitDoPriority1
MapHitDoPriority2

IfNearObject:
doMove
doShoot
doRevertCurrentDirection
doSetMovementTarget
MovementTargetFleeOrAttack
doAccelerate

Idle:
UpdateWaveY
UpdateWaveX

Timer1Alarm:
doSomeStuff

IfOnlyEnemyOnScreen:
setAnotherTrigCondition
doSomeOtherStuff

A lot of different enemy types can be varied this way without hard-coding the behaviour for each one of them; saving program space and keeping things neat (but you've already figured out as much). Different combinations (or omissions) lead to varying results. Priority bits decide what to do first (may be important depending on the nature of the functions).
Ninja Gaiden does something like this for its enemies:

Code:
; the boxer guy

state0:
set_health
set_animation
next_state
RTS

state1:
face_player
if (in_range)
next_state
else
move(NORMAL)
RTS

state2:
move(LUNGE)
prev_state
RTS

It keeps a state index for each object and uses function pointer tables to handle the flow of the AI. Most functions that implement the actual behavior are reused and have arguments passed to them.

If you want to see the actual code, I can post the partial disassembly when I get home.

edit: clarified my explanation
@WheelInventor:
Your setup, setting one value for pre-determined game situations, already looks quite neat. This is definitely something that can be built upon.

never-obsolete wrote:
Ninja Gaiden does something like this for its enemies

So, it looks like "Ninja Gaiden", despite re-using functions, still hard-coded a lot:
Code:
face_player
if (in_range)
next_state

Or am I misunderstanding anything here?
To me, it doesn't look like each opponent simply has an array of data value that are feeded to one generic movement function. There are still individual details in code.

That's what I did for my previous game, "City Trouble".

Because it is a side-scrolling platformer, the movements are so vastly different and specific that a scripting engine wouldn't really have paid-off.

I mean, how am I supposed to include "if the character is falling down a gap, let him open his parachute and slowly hover down in a diagonal movement) in a script-based way?
Or the movenent: "Jump to the end of the house, then let a flying object appear and then jump and hold onto the object and fly back and forth with it."

Those things were all hard-coded by me because they aren't really reusable.

There are of course things that were reusable:
The jumping function, the animation change if a character periodically cycles through animations. And of course stuff that isn't even done in the individual movement functions, but in the general loop: Collision checks, behavior when being defeated etc.

But a top-down action-adventure, despite being a much larger game, has a much more simple and more unified way of moving. In the end, it all boils down to whether the character moves up, down, left or right in the next frame.
And this calls for a single movement function that simply takes a data array as a parameter.

never-obsolete wrote:
If you want to see the actual code, I can post the partial disassembly when I get home.

At least for me, actual code is not that interesting. This is more about getting to know different concepts. Like the example WheelInventor posted above.

That the movement function includes something like
Code:
if (direction == right
&& screen[playerY][playerX + 1] == noObstacle)
{
++playerX;
}
this is something that I'd have to (and be easily able to) program myself anyway, so it's not really my focus of interest.