Sunday, July 5, 2015

Oh Behave!

A different post was planned, but I can't take screenshots since I'm on an old back-up station. The keyboard of my laptop suddenly stopped working partially, so I could only write half a story. Probably a cable rupture or something, though it wouldn't surprise me if the repair-assholes decide to swap hard-drives and reset everything anyway (as they did before at HP for no reason).

So anyway, let's fill the gap with a post that doesn't require spectacular screenshots then; Scripting.

One of the many features that has to be brought back alive again in the Engine22 rebuild, is Scripting. The ability to run your custom code without needing a programming environment or recompiling the project. The old engine used Python for that in a dark past, the new engine will use LUA. Why the swap? Hmm, no extravaganza arguments really. I just didn't like the Python syntax personally, people say LUA is a little bit faster due its simplistic basis. And maybe the most important reason, I don't have a recent Python-wrapper for Delphi XE. Most likely there is one out there, but nevertheless you can't pick just any library with Delphi, as there often isn’t an up-to-date header file due the limited userbase of Delphi. You can make your own wrappers of course, but... it's not that I don't have anything else to do.


Well, LUA then. What can you do with it, and how is it integrated in Engine22? Let's explain the difference between a script and regular code. Say we have an enemy soldier, hanging around, minding his own business, till we enter the scene. Upon sight he should start doing things. Erh, soldier things, like drawing a gun and throwing grenades. But this particular soldier shall run towards an alarm-button first. First of all, note that this type of behavior isn't accepted in an Engine. Not that we don't tolerate grenade-throwing soldiers, but engines shouldn't be involved with such game-specific things in the first place. Engine22 doesn't know if your game includes smart soldiers, stupid zombies, or peace-loving Gummi bears. The engine doesn't have the grenade-throwing or run-to-alarm thing hardcoded. It only provides various functions to achieve this. Like finding the path to that button, testing if guy-A can see guy-B, or enabling a grenade-throw animation. Engines are abstract in this; a higher layer should decide what to do, when to do, and how to do.



This higher layer is *your* code, pasted on top of the engine. Basically the engine does the deeper "standard" stuff, and triggers events. Your code tells our soldier to keep an eye open for our other player character(s). On detection, the engine throws an "onSight" event. This event provides some technical arguments, such as who can be seen and how far away. But what will happen next completely relies on your custom code inside that event. Ignore the player? Start shooting? Say hello? Run and hide? You tell.


onShitHappens( x )
Each "entity" (could be a monster, could be a lightsource, could be a peeled banana) can carry a "Behavior" object. Often simple entities like junk or furniture share the same standard Behavior. This Behavior is a collection of events that can be called by the engine. Whether you use them or not is up to you. To give an idea what kind of events- onSpawn, onKilled, onUpdate, onSight, onCommand, onGetInterfaceOptions, onCollision, onPhysicsUpdate, and so on. When not filling in any behavior, your entity will fall back to standard engine code. Which is fast, but doesn't do much more than basic physics. For example, if your can-of-paint falls on the ground, it won't make clunky sounds, nor leave a paint decal. To do so, you should override its "onCollision" event. This event tells you the velocity, the angles, what kind of materials made contact (metal versus skull), which hitzone (knee, head, balls, rear-wheel), et cetera. Based on that data, do whatever is necessary.

Now you may think, why doesn't the engine just handle this by default, for the sake of simplicity? Making a hit-sound, putting a decal and bouncing back is quite obvious right? Well yeah, but what IF you want something more spicy? Absurd bouncing physics, increasing the score when hitting X, breaking the object in smaller bits... maybe the object shouldn't collide at all if it's a ghost. See, the engine can't predict your wicked plans, which is exactly why you should be able to override things with your own code.


This can be done in three ways; via Compiled Code, Scripts, or "Engine22 Triggers". Compiled Code means you override the Behavior class with your own class in Delphi, code whatever needs to be coded, and compile your project. Note that it will also be possible to let a Behavior point to another DLL as well, allowing you to write a C++ DLL. Either way, this means the behavior is hard-coded; each change requires a re-compilation of either your ProjectCode or DLL.

Scripts are a bit the opposite, as they can be parsed and executed at runtime. Basically you can type a piece of custom code anytime, and let it execute by the Lua Interpreter. If you don't like it, change the code and try again. No need to re-compile and restart. In general Lua is also simpler, which makes it more interesting for non-programmers. The syntax is more relaxed, and since the Engine guides you into filling small logical events ("onHitByBullet", "onPathTargetReached") you don't have to understand the overwhelming behind-the-scenes part.

Only downside is that scripts run slower, as the code needs to be compiled first. Compiled Code is (much) more efficient and powerful than Scripts. But again, they require a programming environment (Delphi, Visual Studio, ...) that not every (artist) user owns or understands. Moreover, it can be tedious to hard-code each and every event. A lot of events in a game will only happen once. Hitting "lightSwitch #634" that toggles "lightSource #1000" and "lightSource #1001", covers a piece of code that is only used by this single instance. If we had to make an overrided Behavior class for each switch or game-map-specific event, we'll end up with a big pile of sh*t, and lose lots of time while prototyping. Scripts are quick & flexible, but require some attention performance wise. Executing a single event is no biggie, but doing calling lots of scripts continously ("onUpdate" event) for many entities may eventually have its impact.

"Engine22 Triggers" is a set of standard conditions and events integrated in the engine. A trigger holds a list of conditions, such as "player stands inside X?", "timer > 60 seconds" or "Z is dead?". If all conditions are true, the trigger will execute its events. Events such as "play sound", "show/hide object", "set animation" or "execute script", where the latter allows you do run some custom Lua code. Engine Triggers are cool because they are efficient, and don't require any programming. But their usage is limited. Very advanced conditions or events may still require script. As said, its a set of common conditions & events.


Preview of the code editor, that allows to (de)activate specific events, and a API browsing tool to help finding the right functions.


API (Application Programming Interface)
One more thing to explain, is the E22 API. Obviously scripts shouldn't be doing too much, regarding performance. Engines are there to help you out, doing the hard stuff. Therefore both scripts, Delphi code, or DLL's in another language can make use of the E22 API, which is basically just a large list of various functions. Functions to move around entities, math & pathfinding functions, playings sounds, doing animations, spawning new entities, killing entities, et cetera.

Doing scripts is the fun part, as you actually define what happens in your game; game-code. All in all you should be able to customize quite a lot without really needing Delphi or another programming environment, which is a good thing. Now this post mainly showed the relation between “entities” (objects in the game world) and scripts, but also notice that scripts can be attached to overall game-rules or UI (“onButtonX-click”).

When are we going to see Engine22 btw? Well, the good news is that I finally bought some webspace so others can download. But before doing so, I want to finish some demo programs first, and moreover, test if another person –a Delphi beginner- can make a project & run things. Of course Engine22 is in a very, VERY, early stage. So releasing to a wider public would be a bit stupid I’d say. Likely I’ll be asking here for some more guinea pigs first.

7 comments:

  1. Interesting article.
    Have you seen this interesting demo? https://www.youtube.com/watch?v=__i_LoRKhJ0

    ReplyDelete
  2. Stunning graphics! Not sure if they intended to copy Silent Hill PT demo elements though, had a "seen that before" feeling hehe.

    ReplyDelete
  3. Unfortunately I haven't played P.T. demo and now it has been taken out of the store :(

    ReplyDelete
  4. Didn't play it either (don't have a PS4 anyway), but the Youtube demo was enough to make me cry like a little girl. Evil That shit is straight evil

    ReplyDelete
  5. Could you provide a link to the one that made such impression on you? I mean, I want to see it without any additional commentary and other sounds / images to get full experience out of it:)

    ReplyDelete
  6. I saw a part of P.T. demo and I know now what you mean by "seen that before". I saw only the part of the demo because my girlfriend was too scared to see the whole thing and I am too scared to watch it alone :)

    ReplyDelete
  7. hehe, what a "fun" game that will be then! I'm not too sure if I would like to play that voluntary either.

    ReplyDelete