Game Development Community

dev|Pro Game Development Curriculum

Events, Cinematics & Easy Control of it all!

by Dave Calabrese · 09/30/2008 (3:07 pm) · 8 comments

With a solid knowledge of Torque and a little ingenuity, one can do quite a lot. However, like any game engine, Torque doesn't have everything one might need in producing a game. One of the first projects that Gaslight Studios was contracted to do was a small game that was primarily cinematics, sort of like a real-time Dragon's Lair. As Torque does not ship with any kind of cinematic builder, this brought forth a challenge, especially with a timeframe to complete the project in no more than a month and a half.

Looking over the timeline, it was determined we really didn't have the time to build a full, GUI driven cinematic editor for Torque (although I have been working on one in my spare time). In the past, with less experience, I would probably have solved this problem with a series of very large Switch / Case statements. These got to be very ugly and very hard to work with.

For an example of that, let's say we had a simple scene where we want the camera to pan across a few objects in a room - things we want to highlight to the player - then return control. We may write that like this:

function previewRoomObjects(%key)
{
  switch(%key)
  {
     case 1: camera.followPath(previewObjectA);
                 schedule(2000,0, previewRoomObjects,2);
     case 2: camera.followPath(previewObjectB);
                 schedule(2000,0, previewRoomObjects,3);
     case 3: camera.followPath(previewObjectC);
                 schedule(2000,0, previewRoomObjects,4);
     case 4: givePlayerControl();
  }
}

Does this work? Of course! However, imagine if you had a long cinematic sequence, like something from a Final Fantasy game. That switch/case could get up to 50 or more keys, even if you split it into multiple functions. Then, if you changed one key, or needed to add an event in the sequence, suddenly your ordering is all messed up. This is the exact system I've used in the past - and it led to headaches, fursteration, and my never wanting to do cinematics or complex event-driven sequences again.

So here I am, older and wiser, stuck with a project that is almost entierly cinematics. Clearly, I'm no longer going to use many very large switch/case statements, and I don't have the time to finish or implement my cinematic builder. So I come up with a very simple, script-driven system, that can easily manage and control events.

With the system I devised, which is about a page of script-code, we were able to create each event in the scene individually, have events call other events, and keep each event entirely self-contained. This shaved potentially weeks off our development schedule, and allows us to with incredible ease, and in a very short amount of time, assemble anything from a quick placeholder cinematic sequence to a full and complex cinematic sequence. While the system isn't perfect - it was written in about 2 hours out of necessity, and it could use a lot of polish and some solid GUIs to drive it - the system still proved to be a solid gold tool.

Here's the code for it:

function addEventToSystem(%eventName)
{
	%scriptHolder = new ScriptObject(){};
	%eventObject = new ScriptObject(%eventName)
                                  {
                                     scriptLines = %scriptHolder;
                                     scriptLineCount = 0;
                                  };
}

function addScriptlineToEvent(%eventname,%scriptLine)
{
	(%eventname).scriptLines[ (%eventname).scriptLineCount++ ] = %scriptLine;
}

function processEventObject(%eventName)
{
	for(%i = 1; %i <= (%eventname).scriptLineCount; %i++)
	{
		eval((%eventname).scriptLines[%i]);
	}
}

The system is incredibly simple. With the knowledge that a ScriptObject can contain other ScriptObjects, however a ScriptObject cannot hold an array unless it is part of another ScriptObject, the system was built. Each event is an object, which contains a variable, scriptLineCount, of how many lines of script this event contains. Each event object then contains a second object, scriptHolder, which acts as an array which holds all of the lines of script.

Now, let's look at the above event again, and build it using this simple event system...

addEventToSystem(previewObjects);
addScriptlineToEvent(previewObjects,"camera.followPath(previewObjectA);");
addScriptlineToEvent(previewObjects,"camera.schedule(2000,followPath,previewObjectB);");
addScriptlineToEvent(previewObjects,"camera.schedule(4000,followPath,previewObjectC);");
addScriptlineToEvent(previewObjects,"schedule(6000,0, givePlayerControl);");

Now you can easily move things around without affecting other items, and begin the event with a single line of code: processEventObject(previewObjects);

We do, however, still have the issue of schedules to deal with - and moving around a schedule can still affect other items. In practice, we found this was actually not that painful - but we still found a work around for it. I won't get too in-detail for the workaround here, as it is best for another post, but I will give some quick details...

When working with an event system, almost every reason you would need to schedule something can be boiled down into 3 categories:

- Waiting for a camera or object to finish following a path.
- Waiting for a sound effect (possibly character dialog) to finish playing.
- Waiting for an animation to finish playing on an object.

Knowing that simplifies things incredibly. The trick to do, and what we did, is to add an engine-level callback to each of these 3 events so that when they complete their cycle, they run a command that is placed within the callback.

So if I wanted to have one of our events created with 'addEventToSystem();' to play whenever a sound effect finished playing, I could run: alxPlay(mySound,"processEventObject(myEvent);".

And with our modifications, the event would play after the sound finished playing. Obviously, this is all good for a whole post of its on, which is a topic for another time, and another day. =)

Hope you enjoyed this, and I hope that everyone is able to take away some spiffy information from this! That event system is very basic, and can be built upon quite a lot, and have some wonderful interfaces built around it to be able to construct your cinematic sequences and events all while the game is running, without ever opening your scripting IDE - which is the ideal way to build them.

Until next time!

#1
09/30/2008 (3:53 pm)
[big_thumbs_up]

Nice work!

[/big_thumbs_up]
#2
10/01/2008 (7:03 am)
Very cool! And much more elegant than some of things I've come up with in the past!
#3
10/01/2008 (10:24 am)
I agree with the 'big thumbs up'!
#4
10/01/2008 (12:25 pm)
Woohoo! Thanks for all the thumbs! =D
#5
10/03/2008 (2:19 am)
nice!
#6
10/03/2008 (4:45 am)
Wow Dave, really interesting... I hope someday you'll have the time to turn it out in a full cinematics system gui driven... This would be a fantastic addiction to Torque and I will be amongs the firsts customers for such a thing :-)

JoZ :)
#7
10/07/2008 (9:08 pm)
Great stuff as always Dave!
#8
12/24/2008 (8:24 pm)
Very interesting. :)