DescriptionAlthough 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
GOTOcommand 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);
The script compilerThe 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 MachineThe 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"):
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.
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 ...
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 MachineI 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 filesThe 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.
Source Code DependenciesMicrosoft Visual C++ 6.0
Microsoft MFC Library
Microsoft DirectX 3.0 SDK
Useful LinksFlipCode - Game and DirectX programming site.
|Source Code and executable (299 Kb)|