Advanced camera scripting

by snYpir

Main Menu

 

 

 






 

 

 

 


Advanced camera scripting

 

The remainer of testcam2.sqs is considered advanced because we are essentially going to force the camera to do some things that are beyond the one-line commands that are available to us. We are going to make the camera zoom in and out incrementally, and also rotate around. If you have not checked out the example mission for all this yet download it here.

The zooming is done in script via a couple of loops, and the rotation will be done using rotate.sqs (a script designed to rotate a camera around an object).

Zooming

Let's firstly examine the zooming operation. Ignore the lines concerning rotation for now, and take a look at the following lines of code in the script:

; zoom speed (the bigger the number the faster)
_speed = 0.005

; --- advanced - field of view tricks - zoom in ---
_fov = 0.7
#loop1
_fov = _fov - _speed
_cam CamSetFOV _fov
_cam camCommit 0
~0.01
? _fov > 0.1 : goto "loop1"

This loop, in plain english, simply decreases the cameras field of view (increases the zoom) in tiny increments, so tiny that the human eye assumes that the zoom operation is smooth.

The '_speed' that we define is the size of the increment that will occur every 0.01 seconds. By making this number smaller we are increasing the total number of increments that must be made to zoom the camera and hence slowing down the entire zoom operaion.

'_fov = 0.7' sets the initial field of view. 0.7 is about the default value.

The next six lines perform the 'zooming' operation. Every loop we decrease the camera's field of view by '_speed', gradually zooming the camera in. Once the field of view has reached 0.1 the loop will exit and the zooming operation is complete.

The loop to zoom back out is very similar. Rather than decreasing field of view each loop, we increment it by the same amount. The second loop exits when field of view reaches what we started with (before the zoom in) at 0.7.

If you wanted to use a slow zoom in your camera scripts simply copy out one of these loops and change the values to suit your needs. If you wanted a loop similar to the 'zoom in' one above, but wanted the zoom to be twice as fast and stop when the field of view is 0.3 you would use:

_speed = 0.01
_fov = 0.7

#loop1
_fov = _fov - _speed
_cam CamSetFOV _fov
_cam camCommit 0
~0.01
? _fov > 0.3 : goto "loop1"

Rotating

The other tricky thing that happens in testcam2.sqs is the the camera rotation that spins the camera around the player unit. This is a really cool effect, and quite easy to do.

I wrote a utility script to do it, named rotate.sqs. If you ever want to do camera rotation in a script, you are going to have to use this file. You can open it up and check it out if you want, but don't be too concerned with the contents of the script. It just takes an object and makes it move around another, even if the object in the center of the rotation is moving.

Take a look at the following lines in testcam2.sqs:

; --- advanced - camera rotation ---
[_cam,player,0.02,360,true] exec "rotate.sqs"

; wait until the rotation is finished
rotateexited = false
@rotateexited

; realign camera (required after every call to rotate.sqs)
_cam = newcamobj

The script call to rotate.sqs will take the camera named _cam (our camera), and make it rotate around the player. The rotation will occur at an interval of 0.02 and continue for a full 360 degrees. The 'true' simply identifies to rotate.sqs that we are rotateing a camera object.

The 'interval' specified there is the distance that the camera will be moved each 0.01 seconds (similar to in the zoom loop presented above). Don't worry about this number to much, it is sort of a trial and error thing. Increasing this number makes the camera rotate faster.

The '360' could be any number. If we specified 720 the camera would rotate twice around the player. If we specified -360 the camera would rotate anti-clockwise. If we had specified 0 the camera would have rotated indefinitely.

Ok, so that script call has sent the camera off on a circle from wherever it was around the player.

The next two lines force this script to wait until the rotation script has finished. When rotate.sqs is finished, the global variable rotateexited will be flipped to true and our script will continue.

The last line above is required after any call to rotate.sqs. The documentation for rotate.sqs specifies exactly why this is needed. All you really need to know is that after a call to rotate.sqs you need to make whatever camera object you passed rotate.sqs in the first parameter (in this case _cam) equal to the global variable (set by rotate.sqs) newcamobj.

Full documentation for rotate.sqs can be found here, along with documentation for move.sqs (another camera utility script).

Ok, that about wraps up testcam2.sqs. By now you have at your fingertips a bunch of very powerful scripts and commands. With time and practice you will become a camera scripting master, able to make extremely high quality and precise cutscenes that will leave editor created cutscenes for dead.


How to make an intro

Finally I am going to quickly explain is how to make an intro using a scripted cutscene. This is not that hard. We are going to use the second camera script I introduced above, testcam2.sqs. We are going to convert this script for use as an intro. I will now step through the things that you have to do in order for this script to work as an intro.

Load up the example mission provided above (if you don't have it download it here). To make an intro, click on the area that says 'mission' just below the 'Clear' button. Select 'Intro'. The map screen will clear. Do not panic. You now need to add the units that you want to appear in your intro to this map screen. We will do this now.

Add a player unit named 'object1'. We need to name the player's unit (unlike when the cutscene was part of the mission) because for some reason the global variable 'player' is not recognised in intros.

In the init field of 'object1' place:

[] exec "testcam2.sqs"

Add a second unit to the intro screen named 'object2'.

We need to define when the cutscene is going to end. We do this with a trigger that activates end1. Create a trigger anywhere on the map, and set 'type' to 'end1'. Now we will make this trigger activate when the global variable 'endcut' equals true. So place the following in the 'condition' field of the trigger (this will mean that when 'endcut' is true the intro will end):

endcut

Ok, so up to this point you have added to units, and named them 'object1' and 'object2'. You have also added a trigger. Your map screen should look something like this (in the 'intro' part of the mission):

Your trigger (if you double-click on it) should look something like this (click to enlarge, note that the 'text' of the trigger (end cutscene) makes absolutely no difference at all):

Now to the script. For the same reason as above (the 'player' variable not being recognised in the intro), open up 'testcam2.sqs' in a text editor and change every reference to 'player' to 'object1'.

Remove the lines that destroy the camera at the end of the intro. This is because when the cutscene ends the intro will end. So, remove the following three lines:

; end cutscene
_cam cameraeffect ["terminate", "back"]
camdestroy _cam

Where those lines were, place the line that will end the intro (ie. activate the tigger we defined above). Simply change 'endcut' to true as follows:

endcut = true

Done! Save the mission by 'exporting to single missions' and exit the mission editor. Hit 'Single Missions', play 'testcam' and enjoy your intro. Not so hard, was it?

Download a completed example mission with an intro (and not much else) here. Or just download the script.


How to make outros

Introduction

'Outros' are, not suprisingly, very similar to intros. Outros occur in a mission after the debreifing. There are two types, outro loose and outro win. They are used to provide a sense of closure to your mission, or lead into the next mission if you are making a campaign.

All the same methods that we used to make the intro apply to outros. You can't use the global variable 'player', and you need to click on the button below 'Continue' to navigate to the seperate map screens where you place the units that will appear in your respective outros.

Determining which type of intro will be played following a mission is easy. At the end of your mission you will have a number of triggers, defining the different ending conditions of your mission. As by now you should know, there are various 'endings' that can be triggered. In the 'type' selection box of a trigger you can see 'end1' through to 'end6' and also the type 'loose'.

If the mission ends because a trigger with a type 'end1' through to 'end6' has been activated, 'outro win' will automatically be shown. If a 'loose' trigger is activated, 'outro loose' will be shown. Remember that outros are shown after the defbriefing.

Example Mission

Rather than stepping through how to make an outro, it will be easier for you to simply check out an example mission showing how it is done. Download the example mission here. Load up the example mission in the editor (after extracting it to a folder named 'camtute4.Intro' in your users/yourusername/missions directory).

On the default 'Mission' map you can see the player unit and two triggers. The triggers will simply be used to activate different types of endings. Double click on each in turn, and observe that the triggers will activate on Alpha and Bravo radio commands and are of type 'end1' and 'loose' respecitively.

Outro Win

Now click on the 'Mission' button (below the 'Continue' button on the right pane) and select 'Outro Win'. The map screen will change. On this map screen there is the player unit, a waypoint and another trigger. In the player unit's init field there is a command to call 'win.sqs'. So as soon as 'outro win' starts this script will be executed. As per the intro, the trigger activates when 'endcut = true' and will trigger the end of the outro. The player is named 'object1' as per the intro.

The waypoint here is a 'talk' waypoint. To observe how the talk waypoint works, double click on the waypoint, click on 'Effects', and click on 'Voice'. You can select what the unit belonging the waypoint will say when the waypoint is activated. Back to the main screen for the waypoint, and in the 'Condition' field I have 'talk'. So when talk (a global variable, nothing special) equals true the unit will say whatever has been selected in the 'Effects:Voice' selection box.

Alt-tab out of the mission editor and look at win.sqs. There are many similarities to 'testcamintro.sqs' (the example script used for the intro section above). Here are the similarities in brief:

 

  • 'object1' referred to throughout
  • the script ends with 'endcut = true', which will cause the 'end1' trigger to activate and the outro to end

     

    By now you should feel fairly comfortable with scripted cutscenes, and there is not much in win.sqs that you have not seen before. To make the unit talk I use:

    ; flip the variable that will clear the way for object1 to talk
    talk = true

    This simply causes the talk waypoint to activate (remember it was waiting until talk = true), which makes object1 speak.

    In addition, I print some text to the screen using the following command:

    titletext ["You WIN!!!","PLAIN DOWN",2]

    The 'titletext' command simply prints "You WIN!!!" to the bottom of the screen for 2 seconds. If you are wondering about the 'stop' command (near the top of the script), it is just simply a command that will prevent the unit from moving anywhere. Fairly unneccasary, but you will use it alot in your camera scripting to make units hold in position until you want them to move.

    So if you exported this mission to single player missions, and during the mission hit 'radio alpha' (0-0-1) after the debriefing you would see this very short outro.

    Outro Loose

    Click on the button under 'Continue', and select 'Outro Loose'. This outro will be played if the mission ends due to a trigger of type 'loose' being activated. The map screen for this type of outro is set up in a similar manner as per outro win, except I am going to do a slightly more advanced cutscene.

    You can again see the trigger used to end the cutscene when the global variable 'endcut' equals true. There are two units on the screen, an east soldier and a west soldier. Both have talk waypoints, activated by talk1 and talk2 respectively. 'object1' executes 'loose.sqs' in an init field, and the script will be executed as soon as the outro loose starts. Alt-tab out of the mission editor and open up 'loose.sqs'

    Firstly, DON'T PANIC! This may look complicated at first, but remember that all I am doing is executing a sequence of instructions that will occur in order. This cutscene will show the east soldier shooting a west soldier. There is a bit of dialog and some music. The script can be broken down into three areas: setting the scene, dialog and the killing.

    To set the scene I remove all weapons from object1 and make that soldier a captive. I make object1 put his hands on his head and look sad. Object2 (the east soldier) is made to watch object1. Now the scene is set, and I start the cutscene. Notice I am also playing some music. The following command will commence playing 'track4' (one of the musical tracks shipped with the game):

    ; firsty specify a music track to be played
    playMusic "track4"

    ; zero volume at start
    0 fademusic 0;

    Notice that I have adjusted the volume of the music right away. At first no music will be heard at all. Later on I will use the fademusic command to fade the music up to a higher volume. The syntax of the fademusic command is as follows:

    time to fade fademusic volume

    You can see that later on in the script I increase the volume to normal (1) using the following command (fading in over a number of seconds):

    ; fade the music in over 4 seconds
    4 fademusic 1;

    Further on, object1 is made to talk with the following command:

    ; this will clear object1 to speak
    talk1 = true

    This activates object1's only waypoint, making the unit say whatever has been selected.

    The camera flys over to the east soldier, whose talk waypoint is activated with:

    ; clear object2 to speak
    talk2 = true

    After I move the camera into a position behind object2 (so that both units are visible) I clear the east soldier to shoot the west soldier. The following lines of code are all that are required to cause the bloodbath:

    ; let her rip - clear object2 to fire
    object1 setcaptive false
    object2 dofire object1

    ; wait until object1 is dead
    @NOT(alive object1)

    ; play a dying animation for object1

    object1 switchmove "FXStandSurDead"

    This code causes object2 to kill object1, and the script will wait until this occurs. I then play an animation of object1 dying, which just about wraps it up. The camera will begin to rotate around object1 and the text "You LOOSE!!!" will be printed to the bottom of the screen.

    The last thing that I want you to notice is how I fade the music out at the end of the scene, rather than just cutting the music off when the scene ends (sounds alot nicer this way.)

    And that wraps up outros. If you could follow that last script you are well on your way to becoming a scripting guru. It takes time, I know, but the results are worth it. The possibilities are endless. Have fun making outros!

    In case you missed the example mission for the above examples, the outro example mission can be downloaded here. Or you can seperately check out win.sqs or loose.sqs.


  • Hints and tips

    This section will detail camera scripting hints and tips not covered above.

    Attaching a camera to a vehicle

    This is not so different from zooming the camera in and out (detailed above). It involves moving the camera in a loop in time with the vehicle. A very powerful script has been written to accomplish this, relatively easily to use, get it here.

    Camera shake

    If you want to add some more realism to your cutscenes, why not add the ability to shake the camera (like when explosions go off near by). Find out how to do it here (Thanks Drak).

    Make your own death scene

    It is possible to use your own camera script for when the player dies. Make a script called 'onplayerkilled.sqs' and place it in your mission folder prior to export. This script will be automatically executed when the player dies. (Thanks SelectThis).

    Slow Motion

    By using the 'SetTimeAcc' command you can do slow-motion cutscenes. The format is:

    setacctime time acceleration

    Where time acceleration is the multiplyer for how fast time passes. A value of 0.5 will halve the passage of time. If you want to prevent the user from time-accelerating through your cutscene, place 'setacctime 1' right at the start of your script.

    Disable User Input

    Don't want the player to be able to screw up your cutscene by using the keyboard? Use this command:

    disableuserinput true or false

    A value of false prevents the user's input from being recognised by the game (use right at the start of your cutscene). A value of true enables user input (use at the end of your cutscene).


    Camera Scripting Wizards

    'Camera Scripting Wizards' are scripts that are designed to make the process of creating cutscenes easier.

    The Cutscene Wizard

    GPA has completed his wizard for creating cutscenes. It uses markers and units to define the path that a camera will move along in a cutscene. It includes an example mission and a tutorial. Check it out here.

    This wizard is worth a look! I know it is kind of complicated, but once you get the hang of it's use you will be a camera scripting master! Check out the example mission.

    Camera Movement Script

    I wrote this script to enable you to use game logic units in the editor as quasi-waypoints for a scripted camera to follow.

    This allows you to change the path of the camera by simply moving the game logic units, rather than worrying about exact coordinates.

    Be aware that this script is not for those new to camera scripting. If you have used and/or understand how to use rotation.sqs (used for zooming and rotation above) this script should be not problem.

    Check here for more information.

    The End. If you have any questions, plz hit the forum.

    snYpir