Code Snippet #1
April 15th, 2008 Michael Schwarz and categorized as 3DGS
Hereby I introduce the new code snippets section. Today serving you a Half-Life like movement script.
This script works different than most movement scripts, as it uses vec_accelerate instead directly passing the speed to the c_move parameters, thus creating a move natural movement.
More after the click:
First off we want to set a few constants, aswell as a few dynamic variables which we will later use in the script. Using defined constants makes it easier to read the script as it does make it easier to later modify a specific value without having to crawl through the whole script to find a specific value.
1: define true, 1;
2: define false, 0;
3:
4: define relSpeed_x,skill7;
5: define relSpeed_y,skill8;
6: define relSpeed_z,skill9;
7: define absSpeed_x,skill10;
8: define absSpeed_y,skill11;
9: define absSpeed_z,skill12;
10: define P_Speed,skill13;
11: define P_AngSpeed,skill14;
12: define P_Weight,skill15;
13: define P_Friction,skill16;
14:
15: var GLOB_BkgColor[3];
16: var PHY_Gravity[3];
17: var MOV_Playerspeed = 25;
18: var MOV_Turnspeed = 10;
19: var MOV_MaxUpAngle = 90;
20: var MOV_MaxDownAngle = -90;
21: var MOV_ShiftFactor = 1.35;
So, I use the opportunity to set up my standard defines for true and false, which I prefer to use over 1/0 or on/off respectively.
We store the player input in an imaginary vector called “relSpeed” in the skills of the entity, for the sake of being able to have a better accessibility for external events.
Global acceleration, like gravity, is passed by the absSpeed vector.
Then we have the values P_Speed, P_AngSpeed, P_Weight and P_Friction. P_Speed indicating the current speed the player is moving and P_AngSpeed indicating the speed the player is turning around.
Now we have some dynamic variables that are part of the movement system:
- GLOB_BkgColor[3] : Actually just for defining the sky color.
- PHY_Gravity[3] : We will define the values for this at game start. It’s as the name says the gravity.
- MOV_Playerspeed : You will have to play with this value, as it defines how fast your player will move.
- MOV_Turnspeed : You have to play with this value too. Defines the speed you will turn/look around.
- MOV_MaxUpAngle : The maximal angle you can look upwards.
- MOV_MaxDownAngle : The maximal angle you can look downwards.
- MOV_ShiftFactor : The factor the MOV_Playerspeed gets multiplied by when holding the shift key. Use a value over 1.00 to accelerate the movement when pressing this key, or a value below 1.00 if you want the player to slow down when you press the shift key.
Now comes the main function for the whole thing, it is actually this function that does most of the difference to other movement codes:
1: function FNC_ApplyPhysics(ent, enablePoly)
2: {
3: me = ent;
4: vec_set(me.absSpeed_x, PHY_Gravity.x);
5:
6: while(me)
7: {
8: c_move(me, nullvector, me.absSpeed_x, IGNORE_SPRITES);
9: c_move(me, me.relSpeed_x, nullvector, IGNORE_SPRITES|GLIDE);
10: wait(1);
11: }
12: }
As the commentary says, we use c_move twice here. One time for the absolute speed and one time for the relative speed. This is necessary as for the normal “movement” we need the GLIDE flag, or else we would become stuck in edges; and honestly you would actually not even move without it. Then we need the second c_move without the GLIDE flag because else you wouldn’t be able to walk up stairs or ledges.
And finally, the main movement code:
1: function FNC_MoveWASD(ent)
2: {
3: // :: Assign ME pointer to entity.
4: me = ent;
5:
6: // :: Main loop
7: while(me)
8: {
9: // :: Rotate camera
10: camera.pan += -((mouse_force.x * MOV_Turnspeed) * time_step);
11:
12: // :: Assign camera pan to entity pan
13: me.pan = camera.pan;
14:
15: // :: Camera Tilting
16: // : If Camera tilt is over or under maximal tilt angles
17: if(camera.tilt > MOV_MaxUpAngle || camera.tilt < MOV_MaxDownAngle)
18: {
19: if(camera.tilt > MOV_MaxUpAngle)
20: {
21: // :: If it is over the maximal upper limit
22: camera.tilt = int(camera.tilt - 2*time_step);
23: // : Limit mouse movement
24: if(mouse_force.y < 0){camera.tilt += ((mouse_force.y * MOV_Turnspeed) * time_step);}
25: }
26: else
27: {
28: // :: If it is over the maximal lower limit
29: camera.tilt = int(camera.tilt + 2*time_step);
30: // : Limit mouse movement
31: if(mouse_force.y > 0){camera.tilt += ((mouse_force.y * MOV_Turnspeed) * time_step);}
32: }
33: }
34: else
35: {
36: // :: Else
37: // : Free tilting
38: camera.tilt += ((mouse_force.y * MOV_Turnspeed) * time_step);
39: }
40:
41: // :: If camera roll is not equal to 0°
42: if(camera.roll != 0)
43: {
44: // :: And if camera roll is higher or equal to 180°
45: if(camera.roll >= 180)
46: {
47: // : Roll clockwise
48: camera.roll = int(camera.roll + 2*time_step);
49: }
50: else
51: {
52: // :: else
53: // : roll counter-clockwise
54: camera.roll = int(camera.roll - 2*time_step);
55: }
56: }
57:
58: vec_accelerate(my.relSpeed_x, my.P_Speed, vector(((key_w-key_s)*MOV_Playerspeed*(1+key_shift*MOV_ShiftFactor))*time_step, ((key_a-key_d)*MOV_Playerspeed*(1+key_shift*MOV_ShiftFactor))*time_step, me.relSpeed_z), 0.5);
59: wait(1);
60: }
61: }
62:
63: function FNC_AttachCam(ent, z_offset)
64: {
65: me = ent;
66: vec_set(camera.x, vector(me.x, me.y, me.z));
67: if(!key_ctrl){ camera.z += z_offset; }
68: }
69:
70: action ACT_Player
71: {
72: player = me;
73: FNC_ApplyPhysics(player, false);
74: FNC_MoveWASD(player);
75:
76: camera.genius = player;
77:
78: while(1)
79: {
80: FNC_AttachCam(player, 35);
81: wait(1);
82: }
83: }
In the action ACT_Player you might want to change the second parameter of the FNC_AttachCam inside the while-loop, it defines the height of the camera from the origin of the player, so depending of the size of your player model this value can vary.
Inside your main function, you will also need to include the following BEFORE loading any level:
1: PHY_Gravity[0] = 0;
2: PHY_Gravity[1] = 0;
3: PHY_Gravity[2] = (-9.8);
4:
5: camera.arc = 75;
6: fps_max = 60;
7: fps_min = 35;
8: fps_lock = on;
This defines the Gravity. The value of (-9.8) should be adequate to the real earth gravity when using the Warlock/Cbabe/Guard model as reference. The FOV is set to 75, as it gives the whole thing a more natural feeling overall and we set an FPS lock so the movement doesn’t get jumpy or jerky whenever your FPS should rise or fall unexpectedly.
Now just attach the ACT_Player action to your player model in WED and have some Half-Life-Movement-Fun !
Stay tuned for the upcoming issue #2 of Code Snippets!
This article has been read 173 times