|
Page 4 of 6
Since cinemas were the original reason that I designed the system, let's start there. Looking back at the example from MadStone. , we can divide the first chunk of the cinema into two parts. First, the MadStone plays an animation as it moves toward the ground and fades halfway. Then, as the MadStone touches the ground, the background lights up and the MadStone finishes sinking while fading away completely. We'll build each part individually and then combine them in the script.
Part 1- Fall + Animate
# This ActionList is the first part of the script.
# The MadStone sinks using a RobotFunction and starts
# to fade using a RobotFunction on its alpha. An
# AnimationBehavior causes the MadStone to play
# its animation one time. The whole thing ends when the
# MadStone touches the ground (in 3 seconds).
local RobotFunction fall1 = SlideFn(mad.yPtr, 280, 3, this)
local RobotFunction fader1 = SlideFn(mad.alphaPtr, 125, 3, this)
local AnimationBehavior animator =
AnimationBehavior(mad, mad.anim, 0.22, null)
local ActionList part1 = ActionList()
part1.addFirst(fall1, true)
part1.addFirst(fader1, false)
part1.addFirst(animator, false)
Part 2- Fade + Lighting
# This ActionList is the second part of the script.
# It "lights up" the dark blackground image by turning
# up its RGB values from 0 to 255 using RobotFunctions.
# At the same time, the MadStone slides into the ground
# and fades away (using RobotFunctions on its y value
# and alpha). The script ends when the MadStone has
# finished fading. All of this happens in 3 seconds.
local RobotFunction fall2 = SlideFn(mad.yPtr, 364, 3, this)
local RobotFunction fader2 = SlideFn(mad.alphaPtr, 0, 3, this)
local ActionList part2 = ActionList(null)
part2.addFirst(fader2, true)
part2.addFirst(fall2, false)
part2.addFirst(SlideFn(fground.rPtr, 255, 3, null), false)
part2.addFirst(SlideFn(fground.gPtr, 255, 3, null), false)
part2.addFirst(SlideFn(fground.bPtr, 255, 3, null), false)
Putting it into a script
# We have parts 1 and 2 of the script, both of
# which are ActionLists. Now we just need to put
# them together, in order, using a script.
# The script should start with a sound effect
# Command that plays the sinking tune while
# the script is running.
local ActionQueue script = ActionQueue(this)
script.enqueue(PlaySfxCommand(Sounds.Sink))
script.enqueue(part1)
script.enqueue(part2)
Incorporating it into the cinema
We've now got the code for about 6 dazzling seconds of cinema, and it didn't require us to write any special RobotFunctions or Behaviors. But how does it all work in context? What do we do with these code snippets? Well, how you organize and connect the pieces of a cinema is up to you, but I'll show you how I did it here.
All of the parts of the cinema that we have done so far are closely related: they represent the chunk of the cinema when you defeat the MadStone and it "restores tranquility" to the area. The next chunk of the cinema is totally different--the landscape starts to move, and you go to the next area, meeting your future opponent. Since the first part is all so related, I decided to make that an Effect object (called TranquilEffect) that would represent one chunk of a larger script. Here's the basic layout of the cinema as a whole:
-CinemaScene class declares master script.
-Master script is composed of a couple large chunks.
-CinemaScene runs master script.
-Master script item 1 is a TranquilEffect.
-TranquilEffect runs a script of two parts (which we just wrote).
-When the script is done, it invokes callback() on its
listener, which is the TranquilEffect.
-TranquilEffect then invokes listener.callback() as well,
where its listener is the master script.
-This callback triggers the master script to move to the next chunk.
That's all there is to it! The whole cinema process is just a matter of combining tiny pieces into bigger and bigger pieces until the whole cinema is done. You start with your smallest pieces, ActionEvents (Behaviors, RobotFunctions, and small Effects). You put these together into ActionLists or larger Effects to make script pieces. Once you've got all the parts of the script written, you choose how to organize them and combine the entire thing into a cinema. Remember, a whole script can be just a single item in another script. This gives you an easy way to divide up long cinemas.
|
Good job!
Thanks for sharing this nice iformation. I have implemented the ideo on c# but there's something I can´t find out to do it in a clean way. Imagine this script (Each step is one EventAction):
1) Play Anim
2) Create Particle system
3) Animate with a robot the Particle system position.
How do you handle the third point? You need the particle system instance the robot funcion needs to animate?
Thanks in advance,
HexDump.
The easiest way to do this is basically what you said: instantiate the particle system while you are creating the script and pass it to the command (or behavior, or whatever) that is responsible for the animation. You can organize the particle system's code so that it doesn't load any data just for instantiating it. That way, it isn't taking up much memory until it is supposed to actually run, at which point some item in the script can call particleSystem.load(), and start things running. I almost always use this approach because it is the simplest.
If you really don't want to instantiate the particle system before hand, there are a few options. One is to set up a "global" variable somewhere and pass a reference of it to the parts of the scripts in step 2 and 3. That way, when step 2 creates the system, it's already ready for step 3, which knows to look at the same object. The particle system could be placed into any kind of data structure, as long as both parts of the script know how to access the particle system once its created.
Option 3 would be to create a special command that encompasses steps 2 and 3, generating a particle system and passing to the animation. Again there are quite a few choices for how to do this, but probably the easiest way would be to create a step 2.5 command that facilitates communication between steps 2 and 3, making sure that both have the same data. You could make the input parameters for this communication command general enough so that you can reuse it in other situations (it doesn't have to be completely specific to this problem).
Would any of those solutions work in your case?
Well, I solved the problem more ore less, I have to rethink about it, thanks for the options you offered.
I´m noticing that things are getting complicated. I for example waht to create an effect that is like a meteor rain. This leads me to think that I will need something to do loops, and if you add to this that you want to listen to collisions in the script things get more and more complicated.
For the collision thing I managed to create a WatColliison action that could do the job, but for the loop thing (because you need to create lota of balls that are particle system and do same for all, it is like having 1 script thread per particle system) I can´t get a good solution.
My game is something like Robot Wars where cinematics are really important.
Thanks in advance,
HexDump.
Usually for complicated cinematics, I have an ActionList that encompasses and runs the main script (because scripts can be added to ActionLists, and vice-versa). The script adds ongoing effects (such as a meteor rain) to the list when necessary, and then the script tells it to stop when it is supposed to be done.