Well, I'm not working on a real time strategy game, but I have recently
implemented a script system in my RPG engine. So let's have a go at the
questions..... (^_^)
Vic wrote:
> Hello...there have been some threads about AI and scripting languages
> lately...So I started thinking about it...
> How should one do this? How can you make your game interact with the
> scripts and the scripts with the game?
Well, you need something to turn the text scripts into something your
computer can run. I wrote a parser that uses C-like syntax, and turns the
scripts into compiled bytecodes. Then I have a stack based virtual machine
(easy concept, difficult name) that I wrote to execute the bytecodes. I
used the lex/yacc (actually flex/bison) combination to create the parser
which generates a parse tree from the script. Then I turn the parse tree
into the byte codes.
> How do you control a guy with a script?
Each object in my engine can have one or more scripts associated with it.
When it comes time for the object to do something or react to something, I
pass the script name to the script engine, and if that script exists it is
called.
For example, if the object was touched, I call the "Touched" script with a
single parameter. In the text script file I have something like
script Touched
(
ULONG pvParametersIn
)
{
// C style code for handling the object being touched goes here.
}
The pvParametersIn variable is actually a pointer to a structure with all
the inputs to the script, but my engine only supports 4 byte unsigned longs
since it was quicker to implement that than trying to worry about type
casting and conversion. (It might open my scripts up to lots of hard to
find bugs though.)
Scripts can do calculations themselves, call other scripts, or call certain
functions that the engine has made available to the scripts. This way I can
perform processor intensive functions (path finding algorithms, graphics
functions, and the like) in compiled code, but control it all from scripts.
Scripts can access any data in the parent object through a generic
interface. By this I mean I store most of the object's data (statistic,
characteristics, etc.) in a continuous buffer of memory. Then the script
can get or set any info by calling certain routines and passing it the
offset into the block of data and the size of the data it is accessing.
> How modular do you make your game? Should you be able to add a
> completely new guy, with graphics etc? or just to modify the behaviour
> of currently available guys?
My system is designed to be flexible, so I want to be able to add entire new
characters without problems. Of course graphics, sounds, and other binary
data is stored in a binary format, not in a script. But I set up my game
engine to scan the current directory for all types of files that it knows,
then these are loaded in. Therefore all files with a *.scr ending are
parsed as scripts. Other files are parsed as graphics, or sound. Since the
graphics and other binary data has a text name associated with it, my
scripts can reference those separate graphic files. Therefore I can set my
game up so that any new characters' files simply need to be added to the
directory that is scanned for the character to be included in the game. Of
course your engine will have to be set up so it knows how to handle newly
added data (where to put it, how to make it accessable, how to use it, etc.)
> I know there are a lot of questions here :). I'd appreciate it if you
> (real time strategy gurus :) could answer at least some of my questions,
> or point me to more resources on the net about this.
> thanx :)
Hope this helps,
Michael Duffy
mdu...@ionet.net
thanx, this is very good for a start...
> Well, you need something to turn the text scripts into something your
> computer can run. I wrote a parser that uses C-like syntax, and turns the
> scripts into compiled bytecodes. Then I have a stack based virtual machine
> (easy concept, difficult name) that I wrote to execute the bytecodes.
yeah, this is another thing , how to run the bytecodes...
Where could I learn more about the stack system?
> My system is designed to be flexible, so I want to be able to add entire new
> characters without problems. Of course graphics, sounds, and other binary
> data is stored in a binary format, not in a script.
Yes, I know:)
But if I add a whole new guy...
Let's say I only have guys in my game. And they have a certain array of
bitmaps for animations.
I want to add an archer. Now, maybe I'm gonna need more animations...
What about the arrow? Do I make the arrow an entity itself, being
spawned by the archer? This is what I meant about adding stuff...
> What I did with my language is make it so the script can call "system"
> functions. Since my language is quite similar to C, it works a lot
> like library functions in C, such as strcmp(), getch(), strcpy(), etc.
> You can pass variables into the system functions, and it can return a
> value back to your script. I also have this sort of alias thing like
> C++ has (though it works the opposite way.. You specify an alias in
> the function call rather than the function declaration). If you
> design your scripting language right, you should be able to expand it
> easily, adding more system functions or removing some, or changing
> what is passed to some, etc. I think it should work out great for
> what I'm doing.
How did you handle the actual calling of the system routines?
In my script language I specify templates for functions with one, two, three,
four, or five parameters. All parameters are unsigned longs, since that
parameter can also hold a 32 bit pointer. When I register a system (engine)
function, it must match one of the templates. Registered functions are
stored in a structure which holds a function pointer to the function, the
type of function (ie how many parameters), the name of the function in an
ASCIIZ string, and a hash value for making searching through the strings
faster. These structures are stored in a linked list.
When I have to make a call to an engine function, the script bytecodes store
the name of the function, it's hash value for quick lookup, and the number of
parameters on the stack. The actual call is made by searching through the
linked list for the correct function, then calling the function via the
function pointer and using the template according to the number of parameters
as stored in the structure. (You can compare the number of parameters in the
byte code and the function structure to make sure they match for error
checking.) Parameters can be passed back to the script either through
passing a pointer to the variable to change, or by a return value, since all
functions are defined to return an unsigned long.
Remember everyone: Post signal, not noise. (^_^)
Later,
Michael Duffy
mdu...@ionet.net
Yes, but how do you actually find that pointer to the function?
Let's say I have this function, find_path(struct vector v1,v2) in my
engine (which is an alredy compiled EXE using a stack based virtual
machine or whatever :) and in my script my little guy wants to call this
function to find a path. The EXE is compiled, I don't have the function
names in the EXE, how does my bytecode script know how to call it?
BTW, I was just thinking about this:
the game engine itself would be just this: a graphics displayer (like
loading and drawing the tile maps etc) the sound procesor, plus the
scipt interpreter. The, EVERYTHINg else in controled from scripts, like
For each "level" I have a scene file describing the graphics to load and
the scripts attached to this scene, like the "monsters" with their
graphics and sounds, maps, etc, then in the scipts each monster has it's
own behaviour. This way I can create completely different things just by
compiling new scripts, using the same engine. Of course I will provide
things like pathfinding and others in the main engine, since it's more
efficient .
Does this sound like a reasonable thing to expect, or should I just get
some sleep and think about it tomorrow?
TIA,
Vic wrote:
> yeah, this is another thing , how to run the bytecodes...
> Where could I learn more about the stack system?
I don't remember where I first read about how stack machines work, but when it
came to implementation I just made it up as I went. Page 41 of the book
"Algorithms" by Robert Sedgewick talks about a parse tree representation of an
algorithm, and later in the book it talks about using stacks to traverse trees. I
think that is probably where I learned about it. I also drew upon my experience
with Intel x86 assembly language when designing the bytecodes for my system.
> > My system is designed to be flexible, so I want to be able to add entire new
> > characters without problems. Of course graphics, sounds, and other binary
> > data is stored in a binary format, not in a script.
> Yes, I know:)
> But if I add a whole new guy...
> Let's say I only have guys in my game. And they have a certain array of
> bitmaps for animations.
> I want to add an archer. Now, maybe I'm gonna need more animations...
> What about the arrow? Do I make the arrow an entity itself, being
> spawned by the archer? This is what I meant about adding stuff...
You want to add an archer. The way I have my system set up, it would take three
files. One would be a collection of graphics and sounds in the data library
format I use. The second would be the game scripts which control the AI,
reactions to the environment, etc. The third is the actual definition of the
object stored as a text file which is parsed with a separate parser than the game
scripts, one that builds game objects from text descriptions. It is this third
script which ties the graphics, sounds, and game scripts to the object. The
definition would also tell how to use the object, such as how often it appears on
a certain terrain or in a certain scenario.
I plan to implement missile weapons as game objects just like a character. The
missile weapon game object would simply move in a straight line for a certain
distance. If it collided with any other game object and the combat system decided
that it "hit", then it would cause damage to the target. Optionally you could
have the fact that the missle weapon "hits" decided when the object was launched,
and it would simply move towards it's target. Creating game objects for the
launching of missiles or for other reasons would need to be a feature of the
scripting language. If you build in general functionality to the script language
(as opposed to specific functionality for specific cases) then you can handle a
wide range of cases that perhaps you didn't plan for when the language was
created.
Later,
Michael Duffy
mdu...@ionet.net
Vic wrote:
> Michael Duffy wrote:
> > When I have to make a call to an engine function, the script bytecodes store
> > the name of the function, it's hash value for quick lookup, and the number of
> > parameters on the stack. The actual call is made by searching through the
> > linked list for the correct function, then calling the function via the
> > function pointer and using the template according to the number of >parameters
>
> Yes, but how do you actually find that pointer to the function?
> Let's say I have this function, find_path(struct vector v1,v2) in my
> engine (which is an alredy compiled EXE using a stack based virtual
> machine or whatever :) and in my script my little guy wants to call this
> function to find a path. The EXE is compiled, I don't have the function
> names in the EXE, how does my bytecode script know how to call it?
In my system, all engine functions that can be called by a script are "registered."
By this I mean I call the routine RegisterEngineRoutine for every compiled routine
that the script can call, and I give it a pointer to the routine, as well as the
ASCII name of the routine which will be used to look it up later. I also pass the
number of parameters in the routine to the RegisterEngineRoutine routine.
> BTW, I was just thinking about this:
> the game engine itself would be just this: a graphics displayer (like
> loading and drawing the tile maps etc) the sound procesor, plus the
> scipt interpreter. The, EVERYTHINg else in controled from scripts, [...]
> Does this sound like a reasonable thing to expect, or should I just get
> some sleep and think about it tomorrow?
Well, you don't want to get TOO carried away with what you do with scripts because
scripts will run a LOT slower than compiled code. Therefore you want to spend as
little time in the scripts as possible if you want to keep your game running at a
decent rate. Currently I use scripts to determine what to do when an "action on" or
"move to" command is given, but the actual movement and animation is handled in
compiled code. Use the flexiblity of scripts when it makes sense. You can use
scripts to define a level in the game and the actions of characters as you said
previously. But I wouldn't try to make scripts so flexible that you would be able
to create an entirely different genre or type of game. To do that you would have to
spend a lot of time in your scripts, and your game would slow to a crawl.
Ja Ne,
Michael Duffy
mdu...@ionet.net
>Hello...there have been some threads about AI and scripting languages
>lately...So I started thinking about it...
>How should one do this? How can you make your game interact with the
>scripts and the scripts with the game?
>How do you control a guy with a script?
>How modular do you make your game? Should you be able to add a
>completely new guy, with graphics etc? or just to modify the behaviour
>of currently available guys?
>I know there are a lot of questions here :). I'd appreciate it if you
>(real time strategy gurus :) could answer at least some of my questions,
>or point me to more resources on the net about this.
>thanx :)
What I did with my language is make it so the script can call "system"
functions. Since my language is quite similar to C, it works a lot
like library functions in C, such as strcmp(), getch(), strcpy(), etc.
You can pass variables into the system functions, and it can return a
value back to your script. I also have this sort of alias thing like
C++ has (though it works the opposite way.. You specify an alias in
the function call rather than the function declaration). If you
design your scripting language right, you should be able to expand it
easily, adding more system functions or removing some, or changing
what is passed to some, etc. I think it should work out great for
what I'm doing.
-Jason
>In my system, all engine functions that can be called by a script are
>"registered." By this I mean I call the routine RegisterEngineRoutine
>for every compiled routine that the script can call, and I give it a
>pointer to the routine, as well as the ASCII name of the routine which
>will be used to look it up later. I also pass the number of
>parameters in the routine to the RegisterEngineRoutine routine.
Why not just place pointers to your engine's functions in an array and
preprocess the script to replace text function references with array
index tokens? It does require keeping a list of #defines or enums
updated to match the pointer array, but if your preprocessor can handle
a C header file, you at least remove the problem of keeping the script
preprocessor and executable code in synch. Make the array entries
structures and you can add the argument count, return type, etc. to
it.-Wm
Although, one thing that most people don't consider is to write a
scripting language -> C compiler. Given that you've already got the
parser, it should be quite easy to write a C code generator. Given that
you can do this, you can have your function registration understand C
callable functions and script functions.
This gives you the advantages of easy and fast development and doesn't
give you much of a slow down.
Cheers,
Chris.
--
Mail: crpa...@undergrad.uwaterloo.ca
Homepage: http://www.undergrad.math.uwaterloo.ca/~crpalmer/
This is sort of what I did. I wrote my scripting engine on Windows 95, so I
had DLLs to work with. What I did was created a DLL that contained the
script commands as function names for various objects. For example, "Move"
was the name of the function. If it was a tank I was moving, the TANK.DLL
had a Move command. In my script I would write TANK.Move( x, y ) and it
would call the Move function in the TANK dll. I resolved the names at load
time into lookup tables. This seemed to work okay. This way I could add
objects easily enough to the engine by simply supplying new DLLs. Graphics
and sounds were contained in the same DLL with predefined resource ids.
The main engine handled physics, graphics, input, and sound. The AI was
basically contained in the scripts. My AI was reactionary for the most
part. I had preset events that could happen to objects, which routines
would be called for. The model was similar to how JavaScript and VBScript
respond to events in an HTML page. Interestingly enough, this model is
similar to what MS has done with ActiveX Scripting, although I can't vouch
for this completely since I've only read about it and not actually used it.
A project I have in mind for the future would be to actually use Java as a
scripting language. The engine would create a JVM at startup and load a
predetermined class and call a method in it. This way, people could write
extensions/scripts in a standard development environment and take advantage
of whatever optimizations a JVM might have (such as JIT or pretranslation).
Jay
P.S. I'm still interested in pursuing rule and goal based scripts as
opposed to event driven procedural types. Still, that's even further in the
future :).