Cutscene system ruled just by time?

Started by
9 comments, last by HexDump 12 years, 4 months ago
Hi,

This is my first time I need to create a cutscene system. I have read a lot on the web about different ways to accomplish this task and have mixed them with my own ideas. Now, it is implementation time, but I need some info from other people with more experience than me in this field. Here we go:

1) Some years ago, I implemented a system that actions could be queued in a serial/parallel way, building a tree of actions that when executed created the final result. This can be sure used as the cutscene system director, but, wouldn't it be so much simple to just have a timeline with actions ran at a certain time? An example:

- playMp3(0, "Song.mp3)
- createObject(0, "Ogre", "Ogre1")
- moveObject(1, "Ogre1", Vector3(100,100,1))

This way everything would be really simple to script. Serial actions are supported buy spreading them correctly in time and parallel actions just need to have shared time ranges.

One problem I have seen is that an action like Sync() (This just waits for all actions to finish before start the other that come afterwards) can't be used because we're using absolute time to trigger our actions. Anyway, a solution could be to have our actions layered based on last "sync()". I mean something like this:


- playMp3(0, "Song.mp3)
- createObject(0, "Ogre", "Ogre1")
- moveObject(1, "Ogre1", Vector3(100,100,1))
- sync()
- moveObject(0,....);
- createObject(1,....);

As you may notice, times after sync() starts again from 0, so, when a sync() is ran, and it determines all previous actions from last sync() are finished, timeLine elapsed time would be 0 again. This can be seen as Little cutscene action groups.

2) The previous explanation needs all actions to be added at the beginning of the cutscene playing. Is this how it usually is done? Or do you usually add actions to the timeline as they are needed?

Well, I could be wrong here, but I think this could be a nice & simple way to lay the actions for a cutscene. What do you think?.

Thanks in advance.
Advertisement
It depends entirely on what you want the cutscene system to do. You can make a cutscene engine that is as simple as a single timeline of fixed events, or one with full feedback scripting ability and dynamic response to an active game simulation. One is many orders of magnitude more work than the other.

You need to nail down your requirements and goals first and then work on achieving them.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

Hi!,

Well it is true that I haven't exposed here the requirements for my game. The question was a bit vague and too general.

My game is a 2D platform game and doesn't need too many bells & whistles related to cutscene capabilities. I will be happy with a bunch of actions like walk from here to here, play animation for game object, create game object at position, say text, and little more. As I have said, don't need a fully featured system. THe problem with my system is that I need to have a class per action. In order to be able to add it to the timeline, it is a bit over bloated for me having to wrap every thing that can be added to the cutscene system into an action class. Don't really know if lua with its coroutines could help with this. Any tip?.

Thanks in advance.
I'm not sure I follow. Why do you need a class for every single action?

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

Well, in my opinion, if I have a time line where actions could be added like I stated before, I need a base class action and then a bunch of concrete action clases like MoveTo, etc... that would know what to do on a object. This actions can be timed like the MoveTo one or inmediate like the setObjectPosition.

Perhaps I'm a bit ofuscated with this. I have spent all day just thinking about the best way to accomplish this.

Hi!,

Well it is true that I haven't exposed here the requirements for my game. The question was a bit vague and too general.

My game is a 2D platform game and doesn't need too many bells & whistles related to cutscene capabilities. I will be happy with a bunch of actions like walk from here to here, play animation for game object, create game object at position, say text, and little more. As I have said, don't need a fully featured system. THe problem with my system is that I need to have a class per action. In order to be able to add it to the timeline, it is a bit over bloated for me having to wrap every thing that can be added to the cutscene system into an action class. Don't really know if lua with its coroutines could help with this. Any tip?.

Lua coroutines can certainly help lot.

I had to make a cutscene system once for a nintendo DS game and since there was only one guy in the team who was available to actually build the cutscenes and less than a month to do it the system had to be super simple both to implement and to use.
So I used lua, made it so that each cutscene was one lua script automatically wrapped into a coroutine, and provided a bunch of functions that would either just install a behavior on an object that persisted until removed or changed (such as camera.lookat( actor )), or that would perform a long running action (such as actor.followpath( somepathobject, duration) )and wait until it was done to continue the script. This was achieved by having the function setup some state or controller that actually performed the action and then yielded to suspend the coroutine, which was resumed once the action was complete.

To allow simultaneous actions, there were functions to group actions together into blocks. There was "beginblock_any()', which meant "beginning of a group of actions that ends when any of them ends", and "beginblock_all()" which was the same but ending once all of the actions were completed. A call to another function, "endblock()", would mark the end of the block and actually perform the yield to hand the execution flow back to the engine.

The block system turned pretty useful for things like allowing partial skipping of cutscenes: the scripter could start a long running action in a block together with a waitbuttonPress() call and if the player pressed the button before the end of the long running action it would jump to the next part of the script without waiting.

This system allowed to construct cutscenes with very simple scripts describing a sequence of actions in a straightforward way, which I suppose is the same as with that system that you described that built an action tree.

But with the coroutine way you don't have to build such a tree, so it's probably more straightforward to implement. And since you can use lua control structures right inside of your cutscene script you can do some more advanced stuff easily such as branching cutscenes (doing different things depending on the outcome of a dialog) or QTEs (press X not to die). For instance we were able to loop the cutscene that was used as the game's title screen just by putting its script into a normal lua loop.
@Zlodo thanks for the answer. It is really clear and instructive.

Right now, after reading comments, etc... I have decided to run actions directly on entities instead of having a CutScene director. The cutscene director will be the lua script as you stated.

Entities will hava a state called ScriptControlled, that will make them to do not check for collisions and do not run their brains. Just animations, etc...will be ran.

There are something that really worries me now and is where to store actions and their data that do not are consumed inmediately. I mean, a playAnimation from script is ok, it calls a exposed class method and the entity doesn't need to worry about it anymore. The problem comes for example with the moveTo command and other actions that can run parallel. I could have a list of actions that has been set on the entity and update it as needed, but it seems a bit overbloated to put a list on every entity for just this. In the other hand this moveTo command needs to know the final destination, so, I should set another var in the entities that support this to keep the final position and let the entity check if it arrived. And this for every supported action.

On the other hand as I said before, I could have a class per action that will contain all the data needed to run, but seems a lot of classes with really little functionality for just that.

Thanks in advance.

@Zlodo thanks for the answer. It is really clear and instructive.

Right now, after reading comments, etc... I have decided to run actions directly on entities instead of having a CutScene director. The cutscene director will be the lua script as you stated.

Entities will hava a state called ScriptControlled, that will make them to do not check for collisions and do not run their brains. Just animations, etc...will be ran.

There are something that really worries me now and is where to store actions and their data that do not are consumed inmediately. I mean, a playAnimation from script is ok, it calls a exposed class method and the entity doesn't need to worry about it anymore. The problem comes for example with the moveTo command and other actions that can run parallel. I could have a list of actions that has been set on the entity and update it as needed, but it seems a bit overbloated to put a list on every entity for just this. In the other hand this moveTo command needs to know the final destination, so, I should set another var in the entities that support this to keep the final position and let the entity check if it arrived. And this for every supported action.


In my system the various behaviors triggered by the cutscene (lookat, follow a path, etc.) weren't implemented by the entities directly. Instead, they were implemented by separate controller objects that were created as a result of calling the various cutscene functions. Those controllers had a pointer to the entity they were supposed to affect, along with whatever parameter they required to do their job.
During cutscenes, instead of calling the various entities update functions, the update functions of those controllers were called. Multiple controllers could affect different things on the same entity. For instance you could give a camera a lookat controller that made it point continuously at some other entity, and at the same time a controller to make it move along a path.

This way we avoided to build too much stuff into the base entity class that was only useful for cutscenes. It was also more extensible, and those controllers also took care upon destruction of restoring the entities that they manipulated into their original state, which was necessary to minimize unwanted interactions between cutscenes and the actual game, especially since the cutscene system had been bolted on late during the development.

[quote name='HexDump' timestamp='1323445793' post='4892220']
@Zlodo thanks for the answer. It is really clear and instructive.

Right now, after reading comments, etc... I have decided to run actions directly on entities instead of having a CutScene director. The cutscene director will be the lua script as you stated.

Entities will hava a state called ScriptControlled, that will make them to do not check for collisions and do not run their brains. Just animations, etc...will be ran.

There are something that really worries me now and is where to store actions and their data that do not are consumed inmediately. I mean, a playAnimation from script is ok, it calls a exposed class method and the entity doesn't need to worry about it anymore. The problem comes for example with the moveTo command and other actions that can run parallel. I could have a list of actions that has been set on the entity and update it as needed, but it seems a bit overbloated to put a list on every entity for just this. In the other hand this moveTo command needs to know the final destination, so, I should set another var in the entities that support this to keep the final position and let the entity check if it arrived. And this for every supported action.


In my system the various behaviors triggered by the cutscene (lookat, follow a path, etc.) weren't implemented by the entities directly. Instead, they were implemented by separate controller objects that were created as a result of calling the various cutscene functions. Those controllers had a pointer to the entity they were supposed to affect, along with whatever parameter they required to do their job.
During cutscenes, instead of calling the various entities update functions, the update functions of those controllers were called. Multiple controllers could affect different things on the same entity. For instance you could give a camera a lookat controller that made it point continuously at some other entity, and at the same time a controller to make it move along a path.

This way we avoided to build too much stuff into the base entity class that was only useful for cutscenes. It was also more extensible, and those controllers also took care upon destruction of restoring the entities that they manipulated into their original state, which was necessary to minimize unwanted interactions between cutscenes and the actual game, especially since the cutscene system had been bolted on late during the development.
[/quote]


Yes this was my first approximation. And I see your point. The only thing that I don't like is the concept of cutscene here (I'm looking at things a bit more generally as I think more about the problem and other's ideas).

I mean, a cutscene is the result of scripted behaviour for a set of entities, etc... Thinking this way, the system could be used for cutscenes (sum of all entity scripted actions) or to execute just a few commands on a entity.

As an example, think of a player that reaches a tile, a scripted sequence will kick in but this sequence doesn't stop the usual gameplay flow. This script for example just instantiate another entity that is instructed to go from here to there, and then removed from the level. The only difference between one (cutscene) and the other (just some command scheduled towards a single entity while game flow keeps running) is that for cutscenes you will just make your entities enter a special state where they consume actions send by script or other source, disable input, etc... But the system from my point of view should be valid to use in both cases.

P.D. I know, I started with a simple idea, and now I'm willing to accomplish something totally different but you guys made me look a little further :).

Thanks in advance.
Yes this was my first approximation. And I see your point. The only thing that I don't like is the concept of cutscene here (I'm looking at things a bit more generally as I think more about the problem and other's ideas).

I mean, a cutscene is the result of scripted behaviour for a set of entities, etc... Thinking this way, the system could be used for cutscenes (sum of all entity scripted actions) or to execute just a few commands on a entity.

As an example, think of a player that reaches a tile, a scripted sequence will kick in but this sequence doesn't stop the usual gameplay flow. This script for example just instantiate another entity that is instructed to go from here to there, and then removed from the level. The only difference between one (cutscene) and the other (just some command scheduled towards a single entity while game flow keeps running) is that for cutscenes you will just make your entities enter a special state where they consume actions send by script or other source, disable input, etc... But the system from my point of view should be valid to use in both cases.

Yes, the system I described is definitely not as generic as this, even though you could always have both a system of controllers temporarily taking over an entity to control its behavior and the ability to just call any entity's method. I didn't go there in my system because it only needed to do cutscenes, and to do them the day before so I kept it rather narrow minded :)

This topic is closed to new replies.

Advertisement