Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Cutscene engine

This thread is locked; no one can reply to it. rss feed Print
 1   2 
Cutscene engine
alethiophile
Member #9,349
December 2007
avatar

I am currently working on a cutscene engine for my Psychopyretic game. Does anyone have any idea how to do this? My current thought is to use functions that take a pointer to int and pass the "frames" variable that is incremented by your timer function to it. Does anyone have any better approaches, and are there any bad problems with that one?

--
Do not meddle in the affairs of dragons, for you are crunchy and taste good with ketchup.
C++: An octopus made by nailing extra legs onto a dog.
I am the Lightning-Struck Penguin of Doom.

Schyfis
Member #9,752
May 2008
avatar

It depends entirely on what kind of cutscene you want.
Is your cutscene a movie (think FFVII)?
Is your cutscene an in-game scene acted out by sprites (think FFVI, Chrono Trigger)?
Is your cutscene a series of images (.bmp, .jpg, .png...)?

If your cutscene is a movie, just play the movie. ;)
If your cutscene is an in-game scene, a series of triggers and events would be best. Alternatively, you could use clever timing to get it done (after 20 frames, sprite turns left. after 60 frames, sprite moves diagonally.).
If your cutscene is a series of images, something like what you suggested would probably work.

________________________________________________________________________________________________________
[freedwill.us]
[unTied Games]

OnlineCop
Member #7,919
October 2006
avatar

If #2 (an in-game scene), others have set it up so the NPCs and players' characters can be controlled by script (move up, then left, then right...). There should be something like:

1 map->NPCs[0].set_script("U3R2W50");
2 map->NPCs[1].set_script("U2R2W50");
3 map->NPCs[2].set_script("U1R2W50");
4 map->NPCs[3].set_script("R2W50");
5 map->NPCs[4].set_script("D1R2W50");
6 
7 map->process_scripts(0, 1, 2, 3, 4); // This waits while they all move and their scripts finish
8 
9 map->NPCs[0].set_text("Lower your shields!");
10 map->NPCs[4].set_text("Surrender!");
11 map->process_scripts(0, 4); // Wait while they say their individual threats
12 
13 map->NPCs[5].set_script("R1");
14 map->process_scripts(5); // Move the "enemy" right 1 tile
15 
16 map->NPCs[5].set_facing(FACE_LEFT); // Face the "enemy" to the left
17 map->NPCs[5].set_text("Never! You shall all die now!");
18 map->NPCs[5].set_script("W50"); // After the witty comeback, wait 50 cycles
19 map->process_scripts(5); // Do all the above
20 
21 map->NPCs[5].set_text("Attack! All your base are mine!");
22 map->NPCs[5].set_movement_speed(SPEED_FASTEST);
23 map->NPCs[5].set_script("L2");
24 map->process_scripts(5); // Lunge at the enemies, spewing threats!

So now you can totally control all of the characters by simple scripts, waiting for one or more actions to finish, then doing other actions after it, etc.

Is that what you had in mind?

alethiophile
Member #9,349
December 2007
avatar

That would be nice, but I'm not sure how it's supposed to work. What is map?

--
Do not meddle in the affairs of dragons, for you are crunchy and taste good with ketchup.
C++: An octopus made by nailing extra legs onto a dog.
I am the Lightning-Struck Penguin of Doom.

bamccaig
Member #7,536
July 2006
avatar

I think it would actually work best if you could use a script to process the entire cutscene. Rather than executing short bursts in script and then hard coding the rest, it would be much easier I think if the talking, for example, was also handled by the script. This way, rather than having hundreds of little scripts, you could just have one script per cutscene with all the information it needs.

I've never attempted anything like a cutscene or actually implemented a scripting engine before, but it should be possible and will probably make cutscenes really easy when done. :)

OnlineCop
Member #7,919
October 2006
avatar

I know the KQ project did these kinds of cut scenes (this was more-or-less where I borrowed this suggestion from). They use LUA to implement the scripting, and all of their "move up 3 spaces, then right 2 spaces, then wait 50 clicks, then ..." could be applied to all the NPCs (and player's character) simultaneously if all of the IDs were specified in the "process_entities()" list.

alethiophile said:

That would be nice, but I'm not sure how it's supposed to work. What is map?

NPCs had several states: WALK_RANDOM, WALK_SCRIPTED, WALK_STANDSTILL. When their state was "WALK_SCRIPTED", it took a string of inputs as cues to fulfill.

The main Map would contain all of the NPCs positions, including "current_tile, target_tile, current_[xy]". So if you start an NPC moving in a certain direction, its current_tile may be (10,7) and its target_tile may be (10,8). Its current_x would be 160 (10 tiles * 16-pixel tile width) and current_y would be 112 (7*16), then 113 (7*16 + 1), then 114 (7*16 + 2), ...

So "map" is just whatever map you're drawing to the screen. It's the main controller for all the NPCs contained in it. It's responsible for all the bounds-checking to ensure an NPC doesn't step on an invalid tile (or one occupied by another NPC).

Archon
Member #4,195
January 2004
avatar

If you're doing movie cutscenes, then take a look at APEG.

There is lots of support available since it's made by one of the members in this forum ;)

Neil Black
Member #7,867
October 2006
avatar

How does someone go about making a movies that APEG can play?

Thomas Fjellstrom
Member #476
June 2000
avatar

Quote:

How does someone go about making a movies that APEG can play?

Record a video, and save it as an mpeg1 or ogg theora video.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Neil Black
Member #7,867
October 2006
avatar

It's the recording a video part that I don't get. I know I can use CamStudio or the like to record a video, but how would I make a cutscene video?

Thomas Fjellstrom
Member #476
June 2000
avatar

Quote:

but how would I make a cutscene video?

A video is a video. All games with pre rendered cutscenes do is play back a video file.

One way is to render it in a 3d app, and then encode that, or use a special higher quality scriptable version of your engine to render each frame, and encode that (if its not higher quality, or special in any way, you might as well just use in game scripted cutscenes).

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Neil Black
Member #7,867
October 2006
avatar

I guess my real question is how would I animate a video for a cutscene, but I think Ive hi-jacked this thread for long enough.

Thomas Fjellstrom
Member #476
June 2000
avatar

I do believe I gave two options :)

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Næssén
Member #5,025
September 2004
avatar

Me and my friend Per have implemented a really simple cut scene system for one of our games that yet hasn't been finished. It might give you some ideas. The cut scene is an entity in our engine just as an enemy or the player. You initialize the cut scene by pushing events to it and the events are carried out in the order they were pushed.

Each entity has a logic function that is called each logic frame. The cut scene counts frames and draws itself accordingly.

You can look at the code here (sorry for the formatting):
cutscene.hpp
cutscene.cpp
entityfactory.cpp

If the player is to be animated, the player is simply disabled and replaced by an animation. When the cut scene is over the player is put back in place and enabled.

_____________________
darkbits.org | Google+

alethiophile
Member #9,349
December 2007
avatar

My current idea is to make a scriptable NPC framework, then run cutscenes by passing the right scripts to the NPCs. I can also use the scripts for simple AI actions. Some people have mentioned Lua as a scripting addition; is that a good idea, or should I use something different? I could probably make a scripting engine myself, but I would rather use an already-created one.

--
Do not meddle in the affairs of dragons, for you are crunchy and taste good with ketchup.
C++: An octopus made by nailing extra legs onto a dog.
I am the Lightning-Struck Penguin of Doom.

Simon Parzer
Member #3,330
March 2003
avatar

For an action based system I would make two general types of actions:
blocking actions
and non-blocking actions

A blocking action blocks the action queue and unblocks it when it's finished.
A non-blocking action, well, doesn't block.
Note that at one point in time there can be only one blocking action getting executed.

So you have one action queue (your cutscene), a list of actions "in progress" and a main thread like this (pseudo-code):

do:
  if script.ready:
    Action nextAction = script.nextAction()
    currentActions.add(nextActions)
    if nextAction.blocking:
      script.ready = false
  foreach action in currentActions:
    action.advance() // Process 1 frame
    if action.finished: //Action has finished
      if action.blocking:
        script.ready = true
      currentActions.remove(action)

An action could be a simple command ("Move char A to (X,Y)") or even a sequence of actions, though this could be difficult to implement.
If you want to do several things simultaneously you would just insert a few non-blocking actions to the queue and add another one that is blocking (e.g. "move A to (X,Y) non-blocking", "move B to (X,Y) non-blocking", "move C to (X,Y) non-blocking", "wait 1000 blocking").

Just an idea. On a second thought it is similar to Næssén's system.

alethiophile
Member #9,349
December 2007
avatar

What I'm implementing currently is that all actions block, you call npc.update() in your main loop to update the current action, and you have to call npc.setscript() every time an action finishes and you want a new one. I may add a queue and non-blocking actions later, but that's all I need for now.

--
Do not meddle in the affairs of dragons, for you are crunchy and taste good with ketchup.
C++: An octopus made by nailing extra legs onto a dog.
I am the Lightning-Struck Penguin of Doom.

OnlineCop
Member #7,919
October 2006
avatar

alethiophile said:

I may add a queue and non-blocking actions later, but that's all I need for now.

I would agree with Simon's approach of the list of non-blocked (followed by the blocked) action, because if you have three or four NPCs that you want to march out of a room, or fly away in a set formation, or whatever, you can't do that: you have to send one away, followed by the next, then the next.

The queue would be a bit of a better approach as you wouldn't need to code in too much extra to implement it, and it would make program flow a lot easier...

alethiophile
Member #9,349
December 2007
avatar

No, there would just be one "currently executing" action for each NPC. I could call npc1.update(), npc2.update(), etc. in my main loop, and all execute at once.

--
Do not meddle in the affairs of dragons, for you are crunchy and taste good with ketchup.
C++: An octopus made by nailing extra legs onto a dog.
I am the Lightning-Struck Penguin of Doom.

Matt Smith
Member #783
November 2000

Triggers are often more convenient than co-ordinating scripts manually. e.g. Set a trigger such that "When npc1 is at positon x, npc2.action = walkto y". The active triggers are kept in a list and each of their conditions is tested every frame, after the updates.

Activating and deactivating the triggers is defined in the script, so a mixture of direct commands and triggers can be used in any script.

alethiophile
Member #9,349
December 2007
avatar

That's probably a good idea, but right now I'm just trying to implement simple scripts.

--
Do not meddle in the affairs of dragons, for you are crunchy and taste good with ketchup.
C++: An octopus made by nailing extra legs onto a dog.
I am the Lightning-Struck Penguin of Doom.

OnlineCop
Member #7,919
October 2006
avatar

I think a simple script would be a char[] array:

To move in any four direction, specify "UDLR" (or if you want compass coordinates, "NEWS"), followed by the number of steps in that direction:

char script_buffer[128];
// ...
strncat(script_buffer, "U10", 3);
// ...

Then, step through each character of the array until you hit the '\0'-terminator. If the character is a letter, call the appropriate case __: statement to start collecting the important information afterward (usually, this just means to check the NEXT characters to see if they're numbers, and if so, parse the actual int value from them).

It may be easiest to actually turn this into an expanded string once you have made all of the movement adjustments, such as turning "U4D3" into "UUUUDDD", if it makes the process loop easier for you.

monkeyCode
Member #7,140
April 2006

I'll assume that you're referring to acting out scenes within the game engine, ala Warcraft 3 cut-scenes.

In the past I've been lazy a few times and implemented cut-scenes as scripts.

Player.Perform(Move(19, 20))
Player.Perform(Attack(true))

This however, although very powerful and can provide lot of detail to your cut-scenes , is still coding. Which means it's very hard to write any intuitive tools to create and edit cut-scenes. So a better way could be to implement it in the same manner as you implement macro's in an application, as a sequence of commands/actions.

Jonatan Hedborg
Member #4,886
July 2004
avatar

An XML (or whatever) based system might be nice;
This is probably how I would design it (not giving it to much thought right now though)

1<script start="start">
2 <section name="start" type="parallel">
3 <act type="execute" target="enemy_advance"/>
4 <act type="execute" target="player_advance"/>
5 <act type="execute" target="conditional_move1"/>
6 </section>
7 
8 <section name="player_advance" type="serial">
9 <act type="move" target="player" x="5" y="19"/>
10 <act type="move" target="player" x="9" y="1"/>
11 </section>
12 
13 <section name="conditional_move1" type="serial"> <!-- if a section has a condition, it will continuously check if it's true -->
14 <condition type="reached_area" target="player" area="area_01"/> <!-- where area_01 is defined in the map editor -->
15 <condition type="variable_equals" target="conditional_move1_done" value="0"/>
16 <act type="set_variable" target="conditional_move1_done" value="1"/>
17 <act type="move" target="player" x="1" y="1"/>
18 </section>
19
20 <section name="enemy_advance" type="parallel">
21 <act type="execute" target="enemy1_advance"/>
22 <act type="execute" target="enemy2_advance"/>
23 <act type="execute" target="enemy3_advance"/>
24 <act type="execute" target="enemy4_advance"/>
25 </section>
26
27 <section name="enemy1_advance" type="serial">
28 <act type="move" target="enemy1" x="80" y="90"/>
29 <act type="move" target="enemy1" x="75" y="95"/>
30 </section>
31
32 ...
33</script>

Should be fairly easy to implement; You'd need an action factory and a condition factory, and some semi-clever logic to make it all work together ;)

bamccaig
Member #7,536
July 2006
avatar

Rather than trying to implement an XML-based system, I think you'd probably be better off integrating with an existing scripting engine (i.e. Lua).

 1   2 


Go to: