Sunday, August 1, 2010

Pull my finger

Again a busy week. Long days at work, and our little daughter got two years old yesterday. Just like any Muslim has to visit Mecca at least once, every Dutch family has to visit the "Efteling", our variant on Disney World. So that’s what we did with family and friends. Including our long lost Indiana Jones friend that finally came home this week. After travelling around the world for a year. From Ecuador to Argentina, from India to Bali, from Neptune to the Andromeda solar system, and who knows where else he has been. Looking forward to hear all the stories next week, when he joins us at another “well deserved” vacation in the Ardennes (a stunning 250 kilometer from here). Yeah I know, besides the neighbor countries, Poland and Prague, I haven’t seen much from the world yet.

Anyway, not much programming, but a fun weekend nevertheless. Lovely how that little girl is still completely fascinated by chunky moving robot dragons and plastic pirates on strings. Beautiful to see how pure children still are. Untouched, unprejudiced, still clean from all the bad things in this world. Then to think I never really was a childrens man. Not that I don’t like them, I do, but I just didn’t know how to behave when they are around. I’m too serious for doodoo-daada conversations, scared to break them / make them cry, or scared to get a slap by a concerned mother that thinks I’m a pedophile or something. But there you go, things can radically change in a few years :)

Thank God this train only moves about 3 miles per hour, without loopings. One of the fears that comes with being a daddy is, besides chasing away 16 year old boyfriends on scooters, having to ride the rollercoaster with your daughther one day.

Okidoki. Game programming then. I spend the scarce free hours this week on making a trigger system. I wrote about scripting several times before, but in case you don’t really know what they are… Scripts are adjustable pieces of text/code that can tell what to do. Usually written in a higher (somewhat “easier”) level programming language. Just like with any other programming language, you can apply all kinds of logic. However, in this case the actual work is still done by the underlying engine. Script tells “play sound” or “walk to point B”. Then the engine does the actual (difficult) work. Compare it to cartoons where you have the Muscle and the Brain. The engine is the dumb guy that does all the dirty jobs, the script is the evil genius that makes the plans.

One of the biggest pro’s about using scripts is that they are A: relative easy to write. And B: you can change them afterwards without having to change/recompile the engine code. This makes it perfectly possible to separate specific game stuff (rules, events, behavior) from the engine. But there is also a downside; script runs slower. Although computers are fast these days, it’s still not recommended to perform complex routines inside a script, and certainly not every cycle. Which is why scripts are usually just small pieces of code that instruct the engine. Engine asks what to do, script briefly instructs.

The ping-pong communication between the two can be a little bit chaotic sometimes. And although scripts are great, I still try to avoid them as much as possible in order to keep things simpler and faster. Since I’m quite familiar with PLC’s, AND/OR/NOT’s, pulses and delays, I thought “why not making a trigger system?”. Here a trigger is a set of conditions and events.

After doing it 54259 times, I'm starting to hate designing forms with lots of checkboxes and such. I looked for an "Object Inspector" component for Delphi7, but couldn't find a free one... Maybe I should make one myself... or maybe not.

The picture above shows an example. A set of engine built-in conditions and events can be used to compose a trigger. For example, check if the player is inside a certain part of the map, is looking at object B for at least 2 seconds, and has a screwdriver in its inventory. IFSO, play a sound, spawn an object, change the weather, or whatever.  
- Test if entity is inside a region. Eventually filter on group, velocity, etc.
- Test if entity A can see entity or point B
- Compare entity property or global variable (health / battery less, equal or more than X)
- Do a date/time or weather check (handy for populating streets in GTA kind of games)
- Test if person has item X inside inventory
- …
- Play sound
- Hide/Show objects
- Give something
- Spawn object
- Start cinematic script
- Adjust entity property or global variable (health += 10, … )
- Change light / atmosphere, day/time or weather
- Open or close doors
- …
Now it’s possible to construct quite complex logic, without having to use scripts. All the items above are common checks and do not cover specific game code either. And otherwise scripts can still be used to define specific conditions or events.

Last but not least, the trick is to know which triggers to check and which not. In an open roaming world like this one, you could have thousands of triggers in total. Although the checks are fairly simple, you still don’t want to evaluate that whole shitload. Especially not if 99.9% of the conditions will turn out false anyway. Therefore I made an “active list”. Each sector (a room or corridor for example) carries its own set of triggers. As soon as you get nearby enough, it will put its triggers into that “active list”, from where they get evaluated every cycle. The few triggers that are not bound to a specific location can still be inserted/removed manually via a script as well.

Now this stuff didn’t bring me nice new pics for this week, so you’ll have to do with this dusty crap. Same old apartment room, but decorated with some of the newer objects I added last months. Nice to have a growing library of garbage to put in that world. If the horror idea fails, we can still turn it into The Sims go Soviet.


  1. What scripting language are you using? Or is it homebrewn?

  2. Python. Also tried Pascal script a long time ago. I liked the syntax more, but the results were somewhat slower. Maybe LUA is worth a try as well, but I'm happy the way it works now.

    Basically each sector and object gets its own class inside one huge script (which is build at the start-up). Then when calling an event such as "onDialog", "onCollision", "onUse" or "onSecondElapsed", the right script function of that object will be called. If there is one.

    Other components such as GUI buttons, cinematic events or the triggers I wrote about can pass a piece of Python code right away, and let it execute.

  3. This comment has been removed by the author.