[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Scripting
Steve Baker wrote:
> Gregor Mueckl wrote:
>
>
>>1. Python is slow. I didn't do performance tests on Python before
>>deciding to make this my scripting language of choice. I expected script
>>code to be *way* slower than compiled code (esp. considering the
>>complexity of the Python interpreter). But I had no idea how slow Python
>>actually is.
>>
>
> Python is slow because it's a very full-featured language.
>
That makes it a powerful language.
> Most game's scripting requirements don't need anything like such a
> sophisticated language. Also (as I explained before), I think you
> actually need to use a 'byte-code' approach so that you can interpret
> a little out of each of dozens of programs each frame.
>
The question is whether you actually want this approach. It could be
useful if you have to deal with some very complex AI code (containing
things like recursion and other "nasty" stuff and/or can't guarantee a
constant runtime in case you take an event handler approach).
> I've written a real simple parser to translate a C subset into a very
> simple bytecode - it's not especially fast - but it seems good enough
> for my needs.
>
That's the drawback: I don't know of any open implmentation of a
bytecode interpreter that allows you to specify how many instructions it
should execute from which script. So you would have to take it into your
own hands - with all the problems involved in reinventing the wheel once
again (I don't think that I have to go into detail here).
>
>>2. I've planned to have much more Python script code (i.e. a much lower
>>level interface to the engine) than realistically possible, given that
>>your figures are not too far off from what I use Python for, Steve.
>>Currently I start to think about making compiled plugins, which in turn
>>could act as stubs to script interpreters. So the core engine can become
>>extraordinarily generic while not suffering too much speed penalty by
>>loading additional compiled code instead of slower scripts for those
>>parts that are too slow to remain interpreted.
>>
>
> Yes. If you allow '.so' plugins, they can either be pure C/C++ programs
> or they can be stubs that call an interpreter to interpret Python or
> whatever you need.
>
So IMHO it's best to write the interpreter plugin first and start using
that and only revert to compiled code if the scripts begin to become too
slow to run. This approach is good for AI development, because during
testing you can skip compilation entirely and when it's finished you
rewrite it in C/C++ to give you the time savings you need for the extra
graphics/effects/higher framerate or whatever.
>
>>Btw: Could it be that hard to write a JIT for a interpreted language
>>when the script is already compiled into some bytecode (with preferably
>>very few instructions)? It wouldn't have to really optimise things, but
>>could avoid at least some of the overhead a bytecode interpreter needs.
>>So what thit comes down to is to generate asm code junks for each of the
>>instructions, which are then patched and concatenated together. I just
>>don't understand why this could be so hard to do.
>>
>
> The main problem (as far as I'm concerned) is that you kill any hope of
> portability if you generate machine-code. That's why I use a simple
> byte-code. It's slower - but not unacceptably so for the relatively
> simple things I expect interpreted code to do in my games.
>
Well... how many platforms do you want to support with your code? My
guess is that at least 80-90% of the players will have Intel-compatible
hardware, maybe even more. The rest is far from being an uniform
environment: UNIX Workstations, Macs, PS(/2), etc.
> I don't anticipate interpreting thousands of lines of code per
> frame for each script - I rather expect to execute just a few
> dozen bytecodes for each one.
>
Wouldn't it be better to revert to an event handler system then? If the
scripts are that simple (I'm refering to your emamples below now) it
could be far better to do it this way than letting your scripts loop
within a virtual thread and thereby wasting time *every* frame instead
of wasting time only when really needed. The overhead required to
determine whether and / or which event handler should be called can be
neglected in these examples.
But again, your approach makes perfectly sense if at least some of your
scripts are a *lot* more complex than in your examples.
> But it all depends on what you expect your scripts to be used for.
>
See above.
> I just want behaviours such as:
>
> * If you hit the "use" command while pointing at the light
> switch, the light turns on or off.
>
> * If you hit the "use" command while pointing at a door, the
> door will only open if you own the appropriate key.
>
> ...that kind of thing. Hence, most scripts would be less than a
> dozen lines of code - but there would hundreds or perhaps thousands
> of them in a typical game.
>
> There is also the idea of using scripts for AI - but in that case,
> I envision lots of high level functionality being placed into C/C++
> code with the scripts just linking them together in some way that's
> different for each critter in the game. These scripts would also
> be just a few dozen lines long - with only a handful of those lines
> being executed every frame of the game.
>
OK. Two notes here:
1. It's OK to call compiled helper code in scripts (although that might
depend on one's taste). I believe, however, that the design of such
helper code could become very difficult to get right. It should be
lightweight but at the same time flexible enough to support different
behaviour models, at least different enough so that scripting isn't lead
ad absurdum, because if it's too specific to the creature you're
designing the AI for you could easily have left out the interpreter
entirely. It's difficult to ge this right.
2. If you execute only a certain segment of the code in each game cycle
you end up having yet another problem (it would be one for me if I ever
took that approach in my current project): It's hard to write frame-rate
independent scripting code, i.e. code that does calculations based on
the elapsed time. Consider the following (pseudo-)code that could be in
the AI of a racing simulation:
int time, lasttime;
Pos lastpos, pos; // the car's position
while(some_condition) {
lasttime=time;
lastpos=pos;
time=get_time_since_start();
if(distance(lastpos,pos)/(time-lasttime)<desired_speed) {
accelerate(current_acceleration()+1);
} else {
accelerator(current_acceleration()-1);
}
}
Admittedly it would not be a good driver, but it shows up a problem when
it is interrupted for too long. Asume it's execution is paused for some
10 msecs just after having fetched the time and the physics simulation
of the game calculates another cycle. The result is that the calculated
velocity of the car is out of date and it's likely that the script takes
the wrong action when the car's speed is near desired_speed. This leads
to a somewhat unstable driving behaviour with at worst somewhat random
behaviour from time to time.
This example is somehow constructed. But I bet that similar passages can
be found for real AI code even in shooters and other types of games. You
can't switch to non-time-based code if it's a networked game, but
otherwise a simple step-by-step solution could bring the same results
without those side effects.
Duh, it got late while I wrote this! I think it's better I stop here for
now and go to bed unless I might fall asleep and crash my head into the
keyboard :-)
Good night,
Gregor
--
*****************************************************
* Gregor Mueckl GregorMueckl@gmx.de *
* *
* The ChallengeOS project: *
* http://challengeos.sourceforge.net *
*****************************************************
* Math problems? *
* Call 1-800-[(10x)(13i)^2]-[sin(xy)/2.362x]. *
*****************************************************