🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Scripting systems are event-based?

Started by
3 comments, last by Pxtl 19 years, 12 months ago
Quote: Original post by Kylotan Usually, scripts would be event-based and called by a certain action or situation detected in the host program.
I've been thinking through scripting for a while. Then I noticed this comment and it makes sense. So, every object in the game (weapons, npcs, tiles) have events and to use those, you just plug in your script? Every object is derived from a class (Weapon, Spell, Area, Creature, Item) and those classes describe what events can be used. For example, I have a WeaponRpg-class (derived from Weapon) which has events FireWeapon, ReloadWeapon and then I have two scripts, for example FireRPG.script and ReloadRGP.script. When the weapon is fired, the script is run. Another example. I have a Tile-class which has events WhenPlayerEnter and WhenPlayerLeave. And then I have an individual script for those. I can have as many tiles as needed and everyone can have different script attached to them. So my question is, have I figured this out correctly? Scripting is plugging custom scripts to hardcoded events (like FireWeapon, UseSpell, EnterArea)? I can't figure out how one can make fully script-based engine unless there is some kind of constraints. In my case I think that the constraints are the available public events in the base classes. If my Area-class has OnEnter-event but no OnLeave-event, scripters could do whatever they want into the OnEnter-event but they wouldn't have any control what happens when the players leaves the area. Though this event-based thinking gets little out of control when you consider the fact that many seem to say that creating levels is also scripting. And creating spells, weapons etc. So lets say I'm creating a RPG. Of course I need a (hardcoded) class called Spell. Then I could have couple of more hardcoded classes, derived from this Spell-class, called AreaSpell and PersonSpell (Actually I'm not sure if these are even needed). I'm thinking that you need to hardcode atleast something into game engine, in this case the base classes in which every object in the game is based on. For example, my Spell-class has an event OnCast. Now I could code FireBallSpell.script like this: FireBallSpell derives from Spell when OnCastEvent do FireBallCast.script FireBallCast.script could look like this: DO RemoveMana 20 FROM CASTER DO Damage 50 TO ALL So, does this sound right at all? In my example I used RemoveMana and Damage-method, which should be hardcoded into engine. The engine should have a public list of available methods/commands. Of course FireBallSCast.script could execute another scripts. Am I lost or not? I'm thinking "Yes, I'm lost" :)
Advertisement
It makes a great deal of sense to have scripts to handle events, but that's not the only way.

Simplistically you have some script function which is associated with an object, and gets called frequently, examining the state of things to decide whether to do anything.

Unfortunately this is extremely inefficient and doesn't scale very well.

Event-based scripts are also problematic, as you can run them easily, but you don't always want to have this.

Assume you have a NPC who has some script associated with them, and they need to go to the shop to buy some bread:

Pseudo-code:
Go to shop
ask for bread
give merchant cash
wait for bread to be handed over
go home
stop


If you did this event-based you could end up with (in pseudo-&#106avascript):

function onstartup() {  set destination = shop;  begin walking;}function onreacheddestination() {  if (destination == shop) {    ask for bread;  }  if (destimation == home) {    stop; // yay!  }}function oncommandheard() {  if (command == "give me some money" && source == merchant) {    give mercant the money;    // wait for the bread..  }  // TODO: what if he has no bread?}function onreceiveitem() {  if (item == bread) {    // cool, we have the bread...    set destination = home;    begin walking;  }}


As you can see, doing it event-based is extremely counter-intuitive, and can have a lot of problems: the above implementation would not be sensible, as it doesn't handle various error cases: what if the shop is closed? What if the merchant has no bread?

Adding the events for those things would make it even more difficult.

To get around this problem, I recommend to use coroutines (At the moment I only know they're implemented in lua; the above code is not syntatically similar to lua). With coroutines, you can have a script which maintains context between events, so it can respond in a more sensible fashion.

For example, rather than having to say "begin walking", you can just say "walk to ...".

By the time the coroutine gets resumed, the NPC should be at their destination (unless some error happens). You could of course have some case which causes the script to be abandoned (like the NPC gets attacked on the way to the shop)

Mark
The event-based system can be expanded to provide dynamic events. Eg. you implement the ability to register custom events.
In such a system you would have functions like this:

void AddEvent(char* eventname)
{
// add the event to a array of events
}

void FireEvent(char* eventname)
{
// find the given event it the event array and run the registrated event handlers for it
}

void RegisterEvent(char* eventname,char* scriptname)
{
// find the given event it the event array and add a event handler to it
}

You can export the above functions to the script language you're using so scripts can register/fire/add events themselves.
You can hardcode some base (inheritable) classes into your engine and provide scripts the ability to create their own classes that inherit from the engine's base classes.

For instance, you have a base class defined as follows:

class CWeapon
{
public:

virtual void OnFire();
virtual void OnSelect();
};

In your script you would create a class that would inherit the CWeapon class, name it CBazukaWeapon and add a OnSecondaryFire() function to it and register it as a event. Then in your script that handles a OnKeyDown() event you would do something like this:

(pseudo code)
if key is down LEFT ALT do
if current weapon is CBazukaWeapon do
fire event OnSecondaryFire
Event-based scripts make sense when you're creating a level. For example, when a player enters a specific room, bang the door closed behind him and task the 5 zombies in the room next door to attack. It would be possible to code this in C++, but do you create a new class for the logic each level?

For AI, it is probably better to have a finite state machine, or a scripting language where certain function calls (like walk(), wait(), eat(), etc) occur over several frames.
It helps not to think in terms of conventional Oop when talking about scripting languages. Classes are created and disposed of on the fly in languages like Python and Ruby. But yes, you'll probably be handling your level as a class. If you're using your script for the definition data itself, the script will include a) the source of the geometry data and calls to spawn a level based on it and then b) definitions for all custom event handler functions, and then c) construction calls for all objects within the level, stuffing functions into the even handlers parameters of said constructors (these functions may be custom ones you coded in this script or standard ones pulled from an external module).

So you see, when working with a scripted engine, usually the oopness of it is handled at the engine level - objects are designed and methods are called by the engine. All you (the mapper) writes is the event handler scripts and one startup script that creates all the objects and binds the events to them.

So, if you're working in that (common) way, don't think in terms of "objects" too much. Unless you're planning on a UT-style true-oop scripting system where your actual game characters/objects are defined in script. But the common approach is scripting for mapping.
-- Single player is masturbation.

This topic is closed to new replies.

Advertisement