"Cam_Script.txt"  A tour through the Car_Cam C-Script. Version 1.1  April 21, 2002 
============================================================
Line numbers are given to help locate areas of the script.  They will not be exact,
due to script changes from debugging, etc.  The whole Car_Cam.wdl script file
is approximately 136 lines long.
Any time a line of script is displayed here, it will be enclosed in brackets, such as:
     [  This is the line of script you would see;   ]
The brackets do not exist in the actual script.  They are used here only to identify 
the line as having come from the C_Script file.
============================================================
The Move_Car package contains two C-Script wdl files:
"Move_Car.wdl"  and "Car_Cam.wdl"

The "Move_Car.wdl" file contains all C-Script instructions for the "Player_Car" action.
The "Move_Car.wdl" C-Script is explained in the documentation file, "Script.txt".

The "Car_Cam.wdl" file contains all C-Script intructions for the camera views.  
______________________________________________________________
CAR_CAM.WDL

To keep things simple, we are using the main camera view, which is already defined
in WED and 3DGS.  We are just going to take control of this camera view.  
When the "Player_Car" action finishes, the main camera view will revert back
to being controlled by the standard templates.  
NOTE:  The "on_xxx" functions at the end of this script file will still be active.

The Car_Cam script has a single entry point: function "Car_View()" at line 104.
The action script needs to call this function, to update the camera views:
That line, in the Move_Car.wdl C-Script looks like this:   (from line 719)
     [  car_view();   // Update the main camera view (Car Cam)  ]

This function really has two missions:
  1.  Decide which view has been selected, and 
  2.  Call a second function to do the actual work.

It does this with only 10 lines of scripting.  Here is the main part of this function:

  line 114  [  if (car_view_switch = = 0) {Ahead_View();}      ]
  line 115  [  if (car_view_switch = = 1) {Tail_view();}           ]
  line 116  [  if (car_view_switch = = 2) {Helo_View();}         ]
  line 117  [  if (car_view_switch = = 3) {Follow_View();}      ]
  line 118  [  if (car_view_switch = = 4) {Overhead_View();}  ]

Near the beginning of the Car_Cam.wdl C-Script, we have defined a variable,
"Car_View_Switch" (line 009).  Each of the five different camera views is 
numbered, from 0 to 4.  The "IF" statements in lines 114 through 118 select which
of the five views we will display, based on the value in  "Car_View_Switch".
________________________
Let's take a little side trip, and see how  the value in "Car_View_Switch" gets set. 
Look at the very end of the Car_Cam.wdl C-Script file, around line 134.
There you will find assignments for the three buttons (or keys) for each of the three 
different input devices:
   [ on_v  cycle_car_view();   // Change "on_v" to use a different key to select views  ]
   [ on_joy4 cycle_car_view(); // Change "on_joy4" to use a different joystick button   ]
   [ on_mouse_middle   cycle_car_view();    ]

You can change which button (or key) controls switching the camera views, by
changing the assignments in these three lines of script.
It doesn't matter which button (or key) gets pressed, each of them will execute the
same function,  "cycle_car_view()" (line 124 - which is located just above them).

The "Cycle_Car_View" function is only six lines long, and only does two things:
1.  Add one to the value in our variable "Car_View_Switch", and 
2.  If the value in "Car_View_Switch" is greater than 4, set it back to zero.
___________________________
So now that we know how "Car_View_Switch" gets it's value, let's go back to the
function "Car_View()", and see what happens when the "IF" statement executes one
of the functions.  For starters, let's say the value of "Car_View_Switch" is equal to 0.
The "IF" statement will be "TRUE" for "car_view_switch = = 0", and will execute the
function, "Ahead_View()"   (line 020).
_________________________
FUNCTION Ahead_View()    (line 020)

The "Ahead_View" looks out of the windshield of the vehicle.  That is, the camera is 
positioned at the origin of the model.  We first make the camera tiny (0), so it will pass
through objects.  Next, we use "camera.genius" so we don't display any parts of the
vehicle.

The next two lines of script put the camera right at the origin of the model. It is not
offset by the driver's position, but is in the center of the model, or where ever the 
origin is.  These lines look like this:
  [    camera.x = player.x;    // place camera at player's location   ]
  [    camera.y = player.y;           ]

The camera is now at the right horizontal place, but is it the right height?
(Probably not!)  So now let's adjust how high the camera is, with these lines:
  [  camera.z = player.z + player.MIN_Z;  // start at 'feet', move up later... ]
  [  camera.z += (player.MAX_Z-player.MIN_Z) - 5;  ]

The first line (above) positions the camera at the "feet" of the model.
The second line subtracts the height of the bottom of the model, from the height
of the top of the model, and adds it to the height ( camera.z ) of the "feet" of the
model.  The camera would now be positioned at the top of the model (or vehicle).
This is a little too high, so we subtract 5 from the height, to get the camera below
the roof of the vehicle.  This technique, (which is taken right from the standard
template "camera.wdl" file) will adjust the camera height to five units below the 
top of any vehicle, no matter how short, or tall.
The "-5" is an arbitrary number.  You can make it anything you want!  Experiment
with it, and see what happens.

Finally, we want the camera to point in the same direction as our model (vehicle).
That is accomplished by the next three lines of C-Script:

  [ camera.pan = player.pan;   // Camera faces the same way as the player  ]
  [ camera.tilt = player.tilt;      // Camera tilts with the vehicle     ]
  [ camera.roll = player.roll;    // Camera rolls with the vehicle  ]

We just tell the camera to pan, tilt, and roll the same way as the player (vehicle).

(Remember, the brackets "[" and "]" are not really in the script - they just help 
identify - in this document only! - that the C-Script instructions between the brackets 
came right out of the C-Script file.)

This function is finished, and will return to the "Car_View()" function.  That function is 
also finished, and will return to the script that called the "Car_View()" function.
(We're done!)
_______________________________________________________________
FUNCTION Tail_View()    (line 37)

This function has a lot of the same instructions as the "Ahead_View()" function, 
except we don't use "camera.genius" - we want to see the player (vehicle).

We are going to "offset" the camera 300 quants from the model, by saying we want
to be 300 "X" quants, and 300 "Y" quants, away from the model (the origin, really).

Since we are going to be behind, and a little above, the player (vehicle), we
are no longer positioned at the origin of the model.  This causes a problem, when 
we turn the model.   Let's take a look, and see why we have a problem, when the 
camera is not at the origin of the model:

  _o____o_          Model turns, camera turns    Model turns more - it gets worse!
  |              |                ________________            _______  
  |              |              o|                              |             |            |
  |              |                |                              |             |            |
  |              |              o|                              |             |            |
  |              |                ________________            |            |
  ________                                                            _______
                                                                               o       o
       | |                                   == >  Camera        Camera (looking away!)
       \/                                                                          /\ 
   Camera                                                                    | |

The camera has turned (camera.pan), and is correctly facing the same direction
as the model, but it is still maintaining the same "X" and "Y" distance away from
the model.  But now, the "X" and "Y" offset don't put us behind the model.
Instead, we are at the side the model!  (It's possible we may not even be able to 
see the model, at all.)   Worse, when we turn all the way around, we are no longer
behind the model, we are in front of it, and looking away!  (We are still looking the 
same direction the player/model is.)   This is not good!  So how do we fix that?

We know the angle the model has turned, from the value in "player.pan".
We can use this information to adjust the "X" and "Y" distances:
     1.  multiply the "X" distance by the cosine of the player.pan angle.
     2.  multiply the "Y" distance by the sine of the player.pan angle.
This will automatically adjust the "X" and "Y" distances.

You don't have to understand trigonometry to use the answer to the problem.
Just plug the calculations in to your C-Script instructions, like this:
  [  camera.x = player.x + cos(player.pan) * (-300);  // Offset from player  ]
  [  camera.y = player.y + sin(player.pan) * (-300);  // Offset from player  ]

That will do it!   We finish the function with the following instructions:

We start at the feet, but this time we add "40" to the top of the model.
   [ camera.z = player.z + player.MIN_Z;  // start at 'feet', move up later...  ]
   [ camera.z += (player.MAX_Z-player.MIN_Z) + 40;  ]

Now we turn the camera (no change):
   [ camera.pan = player.pan;   // Camera faces the same way as the player  ]

Then we tell the camera to point down a little bit (-2) since the camera is higher:
    [ camera.tilt = -2;      // Fixed camera tilting  ]

Finally, we tell the camera we do not want it to roll, even if the player rolls:
    [ camera.roll = 0;     // No camera rolling   ]

That ends this function. It will 'return' the same as the "Ahead_View()" function did.
______________________________________________________________
FUNCTION     Helo_View()    (line 58)

This function is identical to the "Tail_View()" function, except for the camera offsets.
This time, we are going to be 800 quants away from the model, and 300 quants higher.
Here are the lines that are different from the previous function:

   [ camera.x = player.x + cos(player.pan) * (-800);  // Offset from player  ]
   [ camera.y = player.y + sin(player.pan) * (-800);   // Offset from player  ]
   [ camera.z = player.z + 300; // Distance above player's origin                 ]

Since the camera is now positioned higher, we need to tilt it down a little more:
    [ camera.tilt = -10;   // Fixed camera tilting  ]

By now, you should see how to make the camera any distance you want, from your
model!  And it will follow your model (vehicle) around, just fine.
_______________________________
FUNCTION Follow_View()     (line 74)

This camera view does a fairly impressive thing, and that is, it lags behind as you
speed up, but zooms right in when you slow down, or stop.  Looks tricky, but it is 
really very simple to program!

Look at the explanation of the previous function, "Helo_View()" (just above this).
All the offset numbers (-800 and 300) are fixed numbers.  All we have to do to
get the "zoom" feature, is to use a variable instead of fixed numbers.  In this case, 
we used "car_velocity".  Let's take a look at one of the lines:
[camera.x = player.x+cos(player.pan) * (-(500+abs(car_velocity*3))); // Offset from player ]

The "500" is how far away we start from the model.  Then we multiply "car_velocity"
by "3" to make the camera move three times as far as the velocity changes.  (We 
could make this "1" or "2" for less effect, or "4" or "5" or "10" or whatever, to make
the effect more powerful.  It's your choice!)

For the height, we start "80" quants up, and climb 2 times as fast as "car_velocity"
changes.  This is what it looks like:
   [camera.z = player.z + 80 + abs(car_velocity)*2; // Distance above player's origin ]

Notice we use "ABS" or "absolute" velocity.  This is because the velocity can go 
negative (if we are backing up), and we don't want the camera going down into the 
ground!

As we are moving the camera around, (especially higher), the camera also needs
to tilt a little more, or less, depending on where it is going.  But we don't want the
tilt angle of the camera to change too much.  So, we divided the tilt angle by 16.
("16" is a number that was picked, by trial and error, until it worked right.)
     [ camera.tilt = -(abs(car_velocity)/16);   // Fixed camera tilting  ]
Notice the negative (-) sign in front of the calculation.  That makes it tilt "down",
rather than tilt "up".

You don't have to use "car_velocity".  You can change the variable to anything else
you might want to use, to move and "zoom" the camera.   Have fun!
________________________________________
FUNCTION Overhead_View()     (line 85)

If you have made it through the other four views, this one is really simple to 
understand.  We start out with the camera at the player's origin, but move (offset)
the camera 2,000 quants above the model.  Here is that line:
[  camera.z = player.z + 2000; // Change this value to raise or lower camera height ]

That gives you the "eye in the sky"!

Now, we just have to tilt it down.  If we tilt it 90 degrees down, the model will be in
the center of the screen.  But since we generally are more interested in where we
are going, rather than where we have been, we tilt it down less than 90 degrees, so 
we see more of what's ahead, than behind.  Here is that line:   (line 101)
    [ camera.tilt = -80;    // Point the camera almost straight down  ]

Tilt down (-) 80 degrees.      The height and the tilt angle are fixed, and do not change.
_________________________________________
That should do it!    I hope you enjoy your photography!

Bill McGonigal  (Willy)
April 21, 2002




