Not yet a new release (I've been snowed under with other stuff!), but if any of you played the first act of
Chronicle of Mars, you probably will have noticed the cutscenes - which use the battle engine with the same tileset/elevation combination as the battles themselves, with pre-set movements and actions for the fighters.
Well, as part of
Chronicle's development I wrote this lightweight cutscene coordinator, which means that instead of having to type out every single movement as a series of skill PerformAction calls or having to move the fighter sprites around individually, it's relatively simple to set up sequences of cues that the engine will then play out in parallel. I've already included it in the next release of the engine, but since I was recently asked about it, I figured I should put the code up in this thread in case people want to play around with it in advance of the next release. (Since that's taking much longer to get to than I expected!)
If you want to use this code, simply download the attached file and place it alongside all the other engine files. Then call 'CutsceneMove' with a dict of fighters mapped to lists of cues, and it'll play them all out for you.
If you want to see it working in a simple way, then in the elevation demo code, replace the bit that says:
with the following:
Code: Select all
battle.Show()
battle.Pause(0.1)
CutsceneMove( {
steve: [("move", 3, 4), ("move", 0, 0)]
}, battle )
battle.Start()
Firstly, we're not calling 'battle.Start()' straight away because that will implicitly give control to the player. Calling 'battle.Show()' displays everything on-screen as it will be at the start of the battle, but doesn't actually start taking battle turns and giving the player action choices and running the AI or anything.
What the CutsceneMove call above does is queue up two cutscene commands for the 'steve' fighter: Move to coordinates (3, 4), then move to coordinates (0,0). It'll start executing them immediately, and only return from CutsceneMove and carry on with the rest of the script once all the queued commands are finished. The first parameter is a dictionary mapping fighters to lists of cues for that fighter (queues of cues, heh), so you can add extra cues for other fighters by simply inserting those other fighters into the same dict with lists of instructions of their own. The system will run them all in parallel so far as it can.
There are four commands you can use as cues:
- ("move", x y) will move the fighter to the coords specified.
- ("wait", n) will wait n 'turns' before carrying on with the next item. One 'turn' in this context is one space worth of movement, which takes 0.5 seconds.
- ("remove") will remove the fighter from the scene entirely
- ("state", "statename", "facing") will change the fighter's state (have a look at the directional-animated-sprites demo and for more examples of sprite state and facing)
also:
- ("state", "statename", "facing", "soundfile") will do the same as above, but also play the stated sound at the same time.
The thing to be wary of is that fighters move according to the normal rules of moving in a battlefield, so it's possible for them to get stuck. Generally they just wait a turn and try again, but if - say - you have two fighters moving in opposite directions, and they run into each other and each wants to move into the other's space, then they may get permanently stuck and the cutscene will never end.
If you know that it's going to be quite likely, or you want to avoid awkward situations where the order that moves resolve causes the scene to look funny*, then you can pass the optional 'passThrough' parameter to the call to CutsceneMove, which will mean that it doesn't apply the normal rules of collision and people can walk thorough each other:
Code: Select all
CutsceneMove( {
steve: [("move", 3, 4), ("move", 0, 0)]
}, battle, passThrough=True )
It's probably a good idea to check your cutscenes with the passThrough param set to True anyway, and if they work without collisions then you can go on and turn it off for the finished game.
This code is far from perfect, 'cause it was knocked up as part of NaNo for a particular purpose - if anyone uses this and finds it lacking, I'd be interested in hearing what you need from it.
* in Chronicle at some point there's a patrol of five mecha walking along a road, so I set them up, five fighters in a 5-square-long line, then ran a CutsceneMove cue list which told them to move to new positions, further along the road, equally-spaced. The first time I ran it, the first two walked off while the back three waited until they were a step ahead, then the next two move and the last one waited another step, /then/ the last one moved off. What was happening was that the code was checking each fighter's next step in a different order to the order in which I'd lined them up on the screen. The first one was cued to move forwards, there was nothing in the space in front of it, so it could. But then instead of processing the second one next, it processed the third one - it was cued to move forwards, but so far the second one was still in that space, so it couldn't move - and waited a turn. Then it checked the second one, which was cued to move into the space the first one had already vacated, so it was fine to go. The same thing happened the next turn further down the line.
This was when I added the 'passThrough' parameter - with the passThrough set, each fighter didn't care whether there was anything in the space it was moving to... but since they were all moving in the same direction at the same rate, they never actually passed through each other.
The opposite situation occurs earlier in the game - five fighters all walk out of a room through the same doorway at the same time. With passThrough on, they'd merge into two or three fighters as they walked through the same spaces on their way to the door; with it off, they politely wait for other fighters to move out of their way before proceeding, and it actually looks more like five people walking through the same door.