Creating an Intro

From BiaSDK
Jump to: navigation, search

Scripted Sequences - Creating an Intro to the level

In the map 'Sample_scriptedSequences' the player starts out with two squads, each with two soldiers, who are all in the AI Mind class of Character Controller. In this section of the tutorial we are going to have our squad start out using the ScriptedController class so that we can manipulate them through script.

You may be wondering what Mind and ScriptedController are, these are the two main Controller Classes that level designers use on characters in BIA EIB. 'Mind' is the default, it permits USA and German characters to behave as you'd expect when playing in combat; finding cover, shooting at enemies, running from grenades, etc. 'ScriptedController' removes the ability to behave automatically, basically any character in that mode will stand around using relaxed idle animations and not react or interact with anything. But we can deliberately tell our characters to do certain tasks, which make the 'ScriptedController' class very powerful when creating scripted sequences.

Step 1

We are going to first make a new TriggeredScript named TS_IntroScene. This script will handle setting up and controlling the intro scene.

Create a new TriggeredScript the same way as before, and then copy and paste the following lines into the newly created TS_IntroScene. Compile changes, then drop it into the level near the `TS_TitleCard script and save the map.

You may also want to tab out the lines as shown below to help keep things organized, also if you double-click on a script in the left column, it will format it with the proper colors (when pasted it usually is all one color).

//state Triggered, this is the default state that runs when a Script is triggered
//the first time

State Triggered { Begin: GotoState('PreFade'); //as soon as 'TS_IntroScene' is triggered, this says to jump to the 'PreFade'\\ //state below }

//state PreFade, this can be called whatever we want.. even 'MonkeyDances', but //I've named them PreFade, PostFade, and IntroEnd since it is logical for //the purposes. State PreFade { //function OnTrigger, now when we trigger 'TS_IntroScene' again, instead of //it running the 'State Triggered' above, it will run this function //instead, and step through to the next state Function OnTrigger() { GotoState('PostFade'); } Begin: //scripting that should happen as soon as the map starts, while the title //card is displayed //usually this area is just used for spawning and setting up our characters


State PostFade { //again when triggered and in this state, we want it to step through //to the next one Function OnTrigger() { GotoState('IntroEnd'); } Begin: //all scripting that will happen after the TitleCard fades out
State IntroEnd { //this OnTrigger does nothing, but we need it so that there is no //chance of our script running the 'State Triggered' again and looping around Function OnTrigger() { //do nothing } Begin: //this is scripting that should run to 'clean up' our intro scene stuff, //and switch our squad into Mind

Now to explain how we will be using this outline, when this script is triggered initially, 'State Triggered' fires off, the first command it gets (after Begin:) is 'GotoState('PreFade'); So it immediately switches to 'State PreFade' and sits there.

We will be placing our commands to spawn and setup our characters inside that PreFade state, which will be happening right as the level starts.

There is a 'Function OnTrigger()' placed inside of the PreFade state, that’s there so we can trigger TS_IntroScene a second time, and it will know to do the OnTrigger() function, which has the command 'GotoState('PostFade');

This means that once our TitleCard script ends, we can add a line to trigger `TS_IntroScene again, and it will cause that script to switch over to the PostFade state, and begin running our actual intro scene scripting...

Then you may notice we have yet another state 'IntroEnd' which will operate the same way, and allow us to clean up our intro scene when needed.

So let’s get started!

Step 2

First thing to do is change the CharacterSpawners at the intro so that they start in ScriptedController mode. Select all 4 CharacterSpawnerUSA's, and in the Property Inspector (f4) expand CharController and then select ScriptedController from the drop down list next to ControllerClass.

Now let’s edit our scripts a bit..

Let’s start by moving the line for spawning our squad into the TS_IntroScene script, so put the following line into the PreFade state, right under Begin:


Now TS_TitleCard needs to be altered, change the TriggerEvent under the disable battle dialog command to:


Then remove the following lines from the end of TS_TitleCard:

ACTION_CheckPointSave( 1 );

Copy and paste the lines listed above into TS_IntroScene, in the IntroEnd state, below Begin: *(so they are removed from TS_TitleCard and added to TS_IntroScene)

There should be a sleep(0.5; remaining at the end of TS_Title_Card, add the following line under it:


Now when the TitleCard is over it triggers our TS_IntroScene again, causing it to switch states.

Step 3

Inside TS_IntroScene we need to add a line that declares some variables, at the top before State Triggered, add this line:

var pawn Pawn_Corrion, Pawn_Doyle, Pawn_Friar, Pawn_Paddock;

What this will do is give us 4 pawn variables to work with, we can now define what each one should equal (or be related to) in the PreFade state. Under the line ACTION_TriggerEvent('USASpawnCheckpoint_Intro'); add these 4 lines:

Pawn_Corrion = GetPawn('Corrion');
Pawn_Doyle = GetPawn('Doyle');
Pawn_Friar = GetPawn('Friar');
Pawn_Paddock = GetPawn('Paddock');

Now we have a way to access the members of our squad in the TS_IntroScene script. (GetPawn uses each Character Spawner’s PawnTag )

We should now think about how our squad will get switched back into Mind, this should happen inside the IntroEnd state that we created, so lets add these 4 lines just above the ACTION_CheckPointSave( 1 ); :

ACTION_ChangeControllerDirect( Pawn_Corrion, class'Mind' );
ACTION_ChangeControllerDirect( Pawn_Doyle, class'Mind' );
ACTION_ChangeControllerDirect( Pawn_Friar, class'Mind' );
ACTION_ChangeControllerDirect( Pawn_Paddock, class'Mind' );

At this point if you test the map, you will notice that your squad is just standing around, not responding to orders, this is because currently the TS_IntroScene script is sitting in the PostFade state, and nothing has triggered it a third time, causing it to move to the IntroEnd state. If this were an intro where the player was locked in place, we could simply add a Sleep( ) inside our PostFade state, and have it trigger itself again, resulting in the script changing states; But instead we want it to be player-controlled, so lets set up a volume and a trigger in the level!

Step 4

Lets add a gbxTrigger to the level (found in the Actor Class Browser, right column), somewhere near the intro area, in it's properties, under Event, change it's Tag to TRIG_IntroStop and it's event to TS_IntroScene. Now, down under Trigger, change the TriggerType to TT_HumanPlayerProximity (from the drop down list), and also set bTriggerOnceOnly to True.

Once that is done, create a regular volume that stretches across from hedge to hedge, so if the player walks too far from where his squad starts he will have to pass through it. Once the volume is created, select it, and in its properties under Volume set the AssociatedActorTag to TRIG_IntroStop. This volume will now work as the trigger’s collision for detecting when the player passes through it!

Test it out!, remember to save your map, after it loads, walk ahead through the volume and see if it saves a checkpoint, you will also want to watch your squad members, they will shift from relaxed animations into a combat ready pose as the transition from ScriptedController to Mind completes.

Step 5

Let’s take a look at what animations are available to us, click on View -> Show Animation Browser, or just click the Animations tab if you have the Actor class Browser open. (there is also the icon of the bouncing ball up along the top menu bar)

In the nimation Browser click on File -> Open... and select the a_hold_rifle.ukx animation package.

After that, click and drag the vertical bar on the left side of the animation browser, as it might not be showing the left column of animations. There is also a right column for adjusting animations’ properties within *.ukx animation packages.

You should have a list of animations, starting with “crouched_” ones. Usually when viewing the animations I just turn on bones, so I can get an idea of all the parts that are moving. To do this, just click up on View -> Bones, now scroll around in the animation browser viewport and get the skeleton into view. If you can’t find the skeleton in the viewport, try clicking up on the “FPS” button , which will zero the camera. Along the bottom of the window you have your play controls and a playback bar for scrubbing through the animation.

The reason for opening this particular package is that it contains a lot of “standing_idle_” animations, along with reactions and gestures that can be blended together for use in moments.

The first thing we are going to do is set up a queue of “standing_idle_relaxed” animations for one of our characters, leaving the animation browser open, switch back to the TS_IntroScene script.

Step 6

In the PreFade state, under where we defined our Pawns, let’s add some lines to give Doyle a queue of idle animations to play. Copy and Paste these lines:

ACTION_SetAnimSet( 'Doyle', "a_hold_rifle.a_hold_rifle" );
ACTION_ClearPawnIdleQueue( 'Doyle' );
ACTION_AddAnimToPawnIdleQueue( 'Doyle', 'crouched_idle_relaxed_1' );
ACTION_AddAnimToPawnIdleQueue( 'Doyle', 'crouched_idle_relaxed_2' );
ACTION_AddAnimToPawnIdleQueue( 'Doyle', 'crouched_idle_relaxed_3' );
ACTION_AddAnimToPawnIdleQueue( 'Doyle', 'crouched_idle_relaxed_4' );
ACTION_AddAnimToPawnIdleQueue( 'Doyle', 'crouched_idle_relaxed_5' );
ACTION_PlayAnimFromPawnIdleQueue( 'Doyle', FALSE );

The first line, SetAnimSet, is referencing our CharacterSpawner that has the PawnTag “Doyle”, we are simply telling the game to load up the animation package a_hold_rifle and also animation set a_hold_rifle on that character. (The period separates the animation set from package, as some animation packages have multiple animation sets)

Next, ClearPawnIdleQueue, is clearing out any existing animations in Doyle's queue, after that line we are adding names of animations into the queue to be chosen from.

The last line, PlayAnimFromPawnIdleQueue, is telling the game to start playing whatever animations are in the queue, on Doyle, the False (Boolean) is used for telling the game if the animations should be played randomly or in the order they were added to the queue. (False being in order, True being random)

If you test the map now (after compiling the script), Doyle should be crouched using idle relaxed animations.

Step 7

While crouching is nice, let’s make one of our other characters sitting on something in the environment. There is a tree stump near Corrion, and a couple animations in the a_cin_d00_Action_at_StMartin package which would work.

Copy these lines into the same spot under our last IdleQueue related commands.

ACTION_SetAnimSet( 'Corrion', "a_cin_d00_Action_at_StMartin.a_cin_d0_Action_at_StMartin" );
ACTION_ClearPawnIdleQueue( 'Corrion' );
ACTION_AddAnimToPawnIdleQueue( 'Corrion', 'AAS_sitting_on_crate_idle_1' );
ACTION_AddAnimToPawnIdleQueue( 'Corrion', 'AAS_sitting_on_crate_idle_3' );
ACTION_PlayAnimFromPawnIdleQueue( 'Corrion', FALSE );

Now when testing the map you will see he is sitting there on the stump, neat!

One issue that you might be noticing, is now when Corrion and Doyle switch into Mind, their animations pop from crouched / sitting into the standing “combat ready” animations... To fix this we will add a couple lines which play some dismount animations so the pop isn't noticeable.

Add these lines into the IntroEnd state, before the ACTION_ChangeController lines:

ACTION_ClearPawnIdleQueue( 'Corrion' );
ACTION_PlayAnim( 'Corrion', 'AAS_sitting_on_crate_dismount', 0.2, 1.0, False, 0.0, ,0 );
ACTION_PlayAnim( 'Doyle', 'standing_idle_relaxed_2', 0.6, 1.0, True, 0.0, ,0 );
Sleep( 2.5 );

PlayAnim (alternative is PlayAnimDirect) have a lot of properties, they’re formatted something like this:

PlayAnim( 'name' pawnTag, 'name' BaseAnim, 'float' BlendInTime, 'float' AnimRate, 'optional bool' bLoopAnim, 'optional float' StartFrame, 'optional string' MeshAnimName, 'optional byte' bTeleportAtAnimEnd );

- this is the name of your character, if using PlayAnim, we supply the name of the PawnTag on the CharacterSpawner, if using PlayAnimDirect, we supply the variable we defined, ex; Pawn_corrion. (Most of the 'Direct' commands are new to BIA EIB, so if you’re following this tutorial using BIA RTH30 you will have to fall back to non-direct commands, they both do the same thing, the Direct commands are just faster since they reference variables we define only once at the top of our scripts. This can mean better performance during complex scenes, ex; if the timing starts to lag)
- the name of the animation to use, found in the left column of the animation browser
- how long the blend between the frame of the prior animation and the new animation should be, very useful to experiment with.
- the speed to play the animation (default 1.0 )
- should we loop the animation (True = yes)
- the frame we should start the animation on, good for piecing together multiple animation segments.
- optional value, this was never used AFAIK
- this is important when using animations that have changes in start and end location, use a number to designate what to do (see below):

0: No teleport
1: Teleport to relative offset of last animation
2: Teleport and rotate to relative offset of last animation
3: Teleport to relative offset between first and last frame of next animation
4: Teleport and rotate to relative offset between first and last frame of next animation

Now, prior to switching into Mind, Corrion and Doyle will transition into a suitable standing pose, for the combat ready animations to play.

Back to Main Page