Scripting:
Lesson 3: Moving Cameras
For this tutorial...
Make a folder in user/ds called "cam"
so now you have a user/ds/cam folder and we will put our script in it later. The script will be called "cams.os"
Make a large room map - maybe 512x512x256 and save it as "cams.map". You will need to make 3 func_remote cameras - put them about 128 units apart near the centre of the room and above the floor (64 units)
In the entity properties of each camera (press "N") set the flags/ tick the boxes where it says "SCRIPTED" and "NO_DELETE"
SCRIPTED makes the player invisible and invincible while the camera is on
NO DELETE just makes the camera remain in the map after a script has finished - maybe to be used a second time
ACTIVATOR_ON makes the camera show its picture only to the person who triggered it - not to all players in a map/game
Give each camera a targetname - cam1,cam2,cam3
Make 3 info_nulls for the cameras to point at - with targetnames - null1,null2,null3 and place them about 128 units from their cameras and above the floor (64 units)
target each camera to its correct null ( cam1 is targetted to null1 etc)
Don't forget to set a "volume" for the camera or else it will not work - volume = 2 is good
Don't forget to put some lighting in the map
I like to put something in the map as an indicator that the camera is moving - so, near the nulls, put items such as a vehicle or maybe a weapon or healthpack etc - it is also useful to texture each wall of the room with a contrasting texture
You will need your info_player_deathmatch and/or info_player_start and near these you will need a trigger_once targetted at a script_runner
Our script will be called cams.os and will be put in the ds folder called "cam" so our script_runner needs to have a key of script set to a value of cam/cams
ie in the script runner properties put the values...
key: script
value: cam/cams
When the script runner is triggered it will run the script called cams.os in the user/ds/cam folder
Let us make the script...
-------------------------------------------------
DECLARE / ASSIGN
As usual, every script begins with...
#include "../common/header.ds"
output "C://sample/ds/test"
For every camera we have 2 possible entities to manipulate - the camera itself and also the info_null that it is pointing at.
You will get different effects if you move the null or the camera - or if you move both together, maybe at different speeds etc
We have 6 entities to declare - namely all the cams and all the nulls...
local entity cam1
local entity cam2
local entity cam3
local entity null1
local entity null2
local entity null3
These are the names to be used in the script and just happen to be the same as the targetnames in the map
We now assign the names from the script to the actual targetnames in the map
cam1 = find entity with targetname "cam1"
cam2 = find entity with targetname "cam2"
cam3 = find entity with targetname "cam3"
null1 = find entity with targetname "null1"
null2 = find entity with targetname "null2"
null3 = find entity with targetname "null3"
Now for a special command - it makes the camera move with no clip - ie through walls etc and smoothly to its destination
If this command is not present the camera will "jerk" to it's destination
We need to write it for each camera and null
cam1.movetype = MOVETYPE_NOCLIP
cam2.movetype = MOVETYPE_NOCLIP
cam3.movetype = MOVETYPE_NOCLIP
null1.movetype = MOVETYPE_NOCLIP
null2.movetype = MOVETYPE_NOCLIP
null3.movetype = MOVETYPE_NOCLIP
That's it! - all the cameras are now set up and ready to move wherever you would like them to go - let us look at the whole script so far...
---------------------------------------------------
#include "../common/header.ds"
output "C://sample/ds/test"
local entity cam1
local entity cam2
local entity cam3
local entity null1
local entity null2
local entity null3
cam1 = find entity with targetname "cam1"
cam2 = find entity with targetname "cam2"
cam3 = find entity with targetname "cam3"
null1 = find entity with targetname "null1"
null2 = find entity with targetname "null2"
null3 = find entity with targetname "null3"
cam1.movetype = MOVETYPE_NOCLIP
cam2.movetype = MOVETYPE_NOCLIP
cam3.movetype = MOVETYPE_NOCLIP
null1.movetype = MOVETYPE_NOCLIP
null2.movetype = MOVETYPE_NOCLIP
null3.movetype = MOVETYPE_NOCLIP
----------------------------------------------------
MOVEMENT
For movement - everything is referred to by x,y,z co-ordinates that can easily be found from within Radiant when studying your map
There are 2 very different methods of moving something in a script - You can move something BY a certain amount - ie. move object by 10 units up - or you can move the object TO a very specific co-ordinate ie. move object to [0,0,0]
so if you move your camera BY [128,0,0] you will get a different result if you move your camera TO [128,0,0]
You first need to switch on a camera in the script - so type the line...
use entity cam1
Now we will move it forward (if you are looking at the top view of your map in Radiant then the camera will move up the screen)
move entity cam1 by [0,128,0] at 30 speed
Notice obviously the speed parameter which can be changed for practically any number
speed 30 is reasonably slow - up to 100 is good for most camera work- sometimes I have found it necessary to move a null at 1200 speed
We now need to switch off cam1 and switch on cam2 - by "using" cam1 for a second time, it is switched off
use entity cam1
use entity cam2
..and now we will move cam2 to the left (in same Radiant view)
move entity cam2 by [-128,0,0] at 30 speed
But wait... here is an important point - the script has not been told to wait for cam1 to finish it's movement before it switches off and then cam2 is switched on
We need to delay the next command to give the camera time to complete the move
So-we add a simple wait command of say 3 seconds
The whole script now looks like this...
-----------------------------
#include "../common/header.ds"
output "C://sample/ds/test"
local entity cam1
local entity cam2
local entity cam3
local entity null1
local entity null2
local entity null3
cam1 = find entity with targetname "cam1"
cam2 = find entity with targetname "cam2"
cam3 = find entity with targetname "cam3"
null1 = find entity with targetname "null1"
null2 = find entity with targetname "null2"
null3 = find entity with targetname "null3"
cam1.movetype = MOVETYPE_NOCLIP
cam2.movetype = MOVETYPE_NOCLIP
cam3.movetype = MOVETYPE_NOCLIP
null1.movetype = MOVETYPE_NOCLIP
null2.movetype = MOVETYPE_NOCLIP
null3.movetype = MOVETYPE_NOCLIP
move entity cam1 by [0,128,0] at 30 speed
wait 3 seconds
use entity cam1
use entity cam2
move entity cam2 by [-128,0,0] at 30 speed
wait 3 seconds
use entity cam2
exit
----------------------------------------------
If you understand so far you should be able to try switching on / moving / switching off cam3
Also try this in your script - the camera and null moving together...
---------------------------
use entity cam1
move entity cam1 by [256,100,128] at 30 speed
move entity null1 by [0,256,0] at 10 speed
wait 10 seconds
use entity cam1
exit
------------------------------------
SIGNALLING
Now - you may have noticed in the above scripts that if you alter the speed of movement of the camera, that you would also need to change the delay time to give the camera the correct amount of time to complete it's movement
Well - there is a much easier way to control the delay - we can tell the script to wait for the camera to finish moving
This is done with a "signal". A signal is just a number or integer that is used to signal something - ie the signal is 0 (zero) if it is unset, and if it is set then it changes to a 1 (one) - same as on/off
we need to create the integer signal in the script by typing in the declaration section (near the top of the script)
local int sig1
So we now have a signal we can use called "sig1"
if we now put...
move entity cam1 by [128,0,0] at 30 speed signaling sig1
wait for all clearing sig1
...then the camera changes sig1 from zero to one during its movement
After it has finished moving,it will "unset" sig1 and return it to zero
The script is told to wait on the next line until sig1 is reset and then it gets sig1 ready for use again in the script - the same signal is used over and over again if needed
So - notice that we do not need to know any timings. If the speed is changed to 80 thus...
move entity cam1 by [128,0,0] at 80 speed signaling sig1
wait for all clearing sig1
Then the script will still wait until the camera has finished moving before carrying out the next command
NB - Signalling is spelt with 1 letter L in the script ie signaling NOT signalling - it is the same with Targetting and Targeting
We can now write a much better movement script - try this for one camera....
--------------------------------------------------
#include "../common/header.ds"
output "C://sample/ds/test"
local entity cam1
local int sig1
cam1 = find entity with targetname "cam1"
cam1.movetype = MOVETYPE_NOCLIP
move entity cam1 by [0,128,0] at 30 speed signaling sig1
wait for all clearing sig1
move entity cam1 by [128,0,0] at 50 speed signaling sig1
wait for all clearing sig1
move entity cam1 by [0,-128,0] at 80 speed signaling sig1
wait for all clearing sig1
move entity cam1 by [-128,0,0] at 20 speed signaling sig1
wait for all clearing sig1
move entity cam1 by [0,0,128] at 30 speed signaling sig1
wait for all clearing sig1
move entity cam1 by [128,0,0] at 60 speed signaling sig1
wait for all clearing sig1
move entity cam1 by [0,0,-128] at 80 speed signaling sig1
wait for all clearing sig1
move entity cam1 by [-128,0,0] at 40 speed signaling sig1
wait for all clearing sig1
exit
-----------------------------------------------
Notice I am not moving the null in the above script so I have not bothered to declare it at all - even though the camera will be pointing to a info_null in the map
Use the above script but try changing the speed and the co-ordinates - you can try them all in one script by just repeating many many lines in the script and moving the cameras all over the place....don't forget to experiment with moving the nulls also
You move both the null and camera together by only putting the signal on one line like so....
move entity null1 by [0,256,0] at 30 speed
move entity cam1 by [-128,0,0] at 50 speed signaling sig1
wait for all clearing sig1
So the null begins moving, then the camera begins moving, then the script waits for the camera to finish moving
The signal is used in the same way in other scripts to control the timing of movements/animations or events
Hope this helps
Have Fun !
Demise RDAM
|