Description
Although the title mentions the word game, this is not a playable game. It's an experiment with different parsing technique, and especially a test to see how scripting engines and virtual machines can enhance the game-play of any type of game.It was also my introduction project to DirectX (DirectDraw, really) programming.
Only the high-level routines are working in this sample. This includes
building backdrop scenes, animation system and object control.
What's really rocking is the build-in scripting language and the
virtual machine that controls the characters. I wanted to add scripting
to a game, just the way you write scripts to control the monsters in
the Quake and Unreal games.
The game is a typical walk-around adventure. The characters are controlled by a number of states. Each state is driven by some simple actions like "walk to room #3". The character jumps between different states as the game progresses. Here is a state sample:
#STATE 1 GOTO "MainRoom" (60,70) PLAYANIM "Bow" WAIT FOLLOW "Hero" SWITCHSTATE 0
To make the characters more exciting, scripting is used. Each character behaves differently because their behaviour can be scripted. The characters are affected by events, which have scripting code associated.
As such, the state machine and scripting code is totally separated. The state actions are usually primitive, but may affect the target for a considerable time (e.g. the
GOTO
command instructs the target to
find a path and walk to a particular location). On the other hand,
the scripting language contains much more advanced and low-level logic.
Here is a sample script:
#ENTERROOM i++; if( i==5 ) SwitchState(2); SwitchState(1);The script is based on actual programming language syntax (the C language). It is very flexible and has build-in helper functions. In addition some pre-defined objects are available with member functions accessible through the dot-notation (C++ or Java notation):
int r; // Check if hero is in same room as character r = Hero.Room; if( r==this.Room ) SwitchState(3);
Parsing techniques
The script compiler
The game contains a complete language compiler, which parses a C-like language and turns it into p-code. The p-code is saved to disk in a binary form and can be executed by the Virtual Machine when the game runs.The parser is a top-down parser written in C++.
The virtual Machine
The virtual machine executes p-code generated by the script compiler.The p-code ("pseudocode") interpreter is a relatively simple machine that processes a series of "high-level" operation codes ("opcodes"):
CODE_PROGRAMINIT
CODE_PROGRAMEXIT
CODE_CALL
CODE_RETURN
CODE_CLEAR
CODE_LOADCONST
CODE_LOADVAR
CODE_PUSH
CODE_POPADD
CODE_POPSUB
CODE_STORE
CODE_JUMPTO
CODE_IFJUMPTO
...
They define operations the machine can perform. It is a stack machine
because it doesn't use any physical registers to pass information between
instructions. There is one pseudoregister called program counter, which
is a pointer into the code section currently executing.
The Virtual Machine has its own message queue (it is event driven), its own stack and is given a short time-slice to run in (executes a fixed number of instructions).
It sits idle as long as no event is triggered. Events can be generated by other scripts, or generated by the game engine as a result of a character entering the player's room, a timer event or if a character dies etc.
Because event code can be customized for each character, they each have their own virtual machine running. Each VM is allowed to run a number of instructions per frame (turn) so they will not bog the system.
The State Machine
I initially only wanted to use a state machine to control the game-play. But I quickly realized that combined with the virtual machine, the game-play could be controlled much easier.The state machine controls the overall actions that the game characters take. One character's states could be defined as...
- State 1: Walk to elevator, wait a given period.
- State 2: Follow another character. If the player takes a certain item jump to state 3.
- State 3: Find player and start speech dialogue. Then continue with state 1.
The state machine can generate (send) events that trigger scripting code - while the scripting code can force a state change. This allows an almost endless freedom in character control.
The state code is interpreted directly while the game is running. Although string parsing is slow when done real-time, usually only a single line has to be parsed/executed once in a while.
The game model files
The game's rooms are constructed using some model files.These files are formatted text files and describe how the rooms are constructed, which objects are present in each room, which exits are present and which animations to use for the different characters.
To get familiar with some more advanced parsing techniques, I used LEX and YACC to parse the files.
Notes
Source Code Dependencies
Microsoft Visual C++ 6.0Microsoft MFC Library
Microsoft DirectX 3.0 SDK
Useful Links
FlipCode - Game and DirectX programming site.Download Files
Source Code and executable (299 Kb) |