// --------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// good working/well tested gravity script with basic player movement controller - free to use
// supports walking up (for example on steps)
// rayp 2024 ...credits are always nice
//
// needs: player.mdl (best is to use a simple "box" model for collision), test.wmb map file
// usage: run this script
// --------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// --- some var's and def's we want to use
// --------------------------------------------------------------------------------------------------------------------
//SOUND* snd_land = "hitfloor.wav";
var player_movement_speed = 5; // speed of player's movement
var mouse_speed = 1; // speed for camera rotation
var std_cam_height = 17; // eye height of the camera
#define myheight skill99 // used by apply_gravity function = distance to ground from c_trace
#define distZ skill98 // used by apply_gravity function = Z movement for c_move in the ent-move-controller
//#define falling skill97
//#define footstep skill96
//#define step_sndconcrete 100
#define group_player 1 // for c_ignore groups
// --------------------------------------------------------------------------------------------------------------------
// --- the simple (and well) gravity part (with example for floor-texture-footstep-detection)
// --------------------------------------------------------------------------------------------------------------------
void apply_gravity (ENTITY* ent){
if (!ent) return;
VECTOR temp_pos;
vec_set (temp_pos, vector(0, 0, -1000)); // 1000 should be enough for most levels
vec_rotate (temp_pos, ent.pan);
vec_add (temp_pos, ent.x);
c_ignore (group_player, 0);
trace_mode = IGNORE_ME | IGNORE_PASSABLE | USE_BOX | IGNORE_SPRITES;// | SCAN_TEXTURE;
ent.myheight = c_trace (vector(ent.x,ent.y,ent.z), temp_pos, trace_mode);
//DEBUG_VAR (ent.myheight, 300);
// -----------------------------------------------------------------------------------------------------------------
// --- footstep example depending on floor texture, needs SCAN_TEXTURE in trace_mode above
/*
if (HIT_TARGET){
if (hit.texname){
//draw_text (hit.texname, 10,200,vector(255,0,0));
if(str_cmpi(hit.texname,"#default") || str_cmpi(hit.texname,"concrete")){
ent.footstep = step_sndconcrete;
}
}
}
*/
// --- footstep surface detection end, rest of gravity part below
// -----------------------------------------------------------------------------------------------------------------
if (ent.myheight > 2 || ent.myheight == 0){
accelerate(ent.distZ, -3 * time_step, -1);
//if (ent.myheight > 15) ent.falling = 1; // in the air!
}
else{
ent.distZ = 0;
/*if (ent.falling){ // in the air ? play land sound
ent.falling = 0;
snd_play (snd_land, 50, 0);
}*/
}
}
// ---------------------------------------------------------------------------------------------------------------------
// --- a simple and basic player controller with gravity (first person cam)
// ---------------------------------------------------------------------------------------------------------------------
action Test_Player(){
VECTOR player_dist; // movement vector used for XY, for Z we use my.distZ calculated in apply_gravity
// ------------------------------------------------------------------------------------------------------------------
// --- collision box
// ------------------------------------------------------------------------------------------------------------------
wait (1);
my.eflags &= ~FAT;
my.eflags &= ~NARROW;
vec_set (my.min_x, vector(-12,-12,-17));
vec_set (my.max_x, vector(12,12,25));
// ------------------------------------------------------------------------------------------------------------------
my.group = group_player;
while (me){ // dont use while(1), this would crash on, for example, level switch when the entity is lost
// ---------------------------------------------------------------------------------------------------------------
// --- use WASD to move
// ---------------------------------------------------------------------------------------------------------------
//if (key_shift) player_movement_speed = 10;
//else player_movement_speed = 5;
player_dist.x = (key_w-key_s)*time_step*player_movement_speed;
player_dist.y = (key_a-key_d)*time_step*player_movement_speed;
// ---------------------------------------------------------------------------------------------------------------
// --- handle camera rotation and movement
// ---------------------------------------------------------------------------------------------------------------
camera.pan -= mickey.x*time_step*mouse_speed;
camera.tilt -= mickey.y*time_step*mouse_speed;
camera.tilt = clamp (camera.tilt, -80, 80);
camera.x = my.x; // or vec_set (camera.x, my.x) instead of setting X and Y
camera.y = my.y;
camera.z = my.z + std_cam_height;
// ---------------------------------------------------------------------------------------------------------------
// --- prepare our XY movement vector now
// ---------------------------------------------------------------------------------------------------------------
vec_rotate (player_dist, vector (camera.pan,0,0));
// ---------------------------------------------------------------------------------------------------------------
// --- calculate the gravity / Z movement for ME (into my.distZ)
// ---------------------------------------------------------------------------------------------------------------
apply_gravity (me);
// ---------------------------------------------------------------------------------------------------------------
// --- finally move the player (best performance because only one c_move call is used for XYZ)
// ---------------------------------------------------------------------------------------------------------------
c_ignore (group_player, 0);
c_move (me, nullvector, vector (player_dist.x, player_dist.y, my.distZ), GLIDE|IGNORE_ME|IGNORE_PASSABLE);
// ---------------------------------------------------------------------------------------------------------------
wait (1);
}
}
// ---------------------------------------------------------------------------------------------------------------------
// --- the main function
// ---------------------------------------------------------------------------------------------------------------------
void main(){
level_load ("test.wmb");
ent_create ("player.mdl", vector (0,0,50), Test_Player);
}
// ---------------------------------------------------------------------------------------------------------------------
// --- end
// ---------------------------------------------------------------------------------------------------------------------