GMLscripts.com

Discuss and collaborate on GML scripts
Invert

You are not logged in.

#1 2019-08-27 14:47:27

lostdarkwolf
Member
Registered: 2015-11-19
Posts: 23

good car physics, old physics engine

I made a nice car physics script. The script inputs are what control the car. There are many adjustable settings in the script. The script includes reactions to objects flagged as solid.
EDIT: bugfix. (position correction needed to come before collision detection.)

///car_physics(do_handbrake, turn_left, turn_right, gas, brake)
//
// Simulates car physics for an object.
// Has 2 required variables (listed below).
// Should be called in a step event.
//
// do_handbrake   true if using handbrake, real (boolean)
// turn_left      magnitude of turning left, real (normal)
// turn_right     magnitude of turning right, real (normal)
// gas            magnitude of acceleration, real (normal)
// brake          magnitude of brake, real (normal)
//
/// GMLscripts.com/license
/* 
 - - - ABOUT crash_damage: - - -
- "crash_damage" ranges from 0 to 2.
It is not used for anything, just
provided to help with calculating
crash damage, should you need it.
- "crash_damage" does not account for 
the motion of the object that is
crashed into. 
- "crash_damage" is a local variable.
- "crash_damage" can exceed 2 if speed
is somehow greater than max_speed.
 - - - REQUIRED VARIABLES: - - -
All listed variables are local.
- input_deadzone
- is_skidding (set to false)
*/
// - - - HANDLING - - -

// vehicle stats:
var veer_return_strength, acceleration, max_speed, braking_strength, 
reverse_acceleration, max_reverse_speed, handbrake_slowdown_rate, 
natural_deceleration_rate, veer_left_strength, drift_left_strength, 
drift_left_angular_bonus, veer_right_strength, drift_right_strength, 
drift_right_angular_bonus, drift_return_strength, veer_return_strength,
drift_angle_pullback, veer_angle_pullback, minumum_drifting_speed, 
crash_bounce_back, skid_start_threshold, ii;
veer_return_strength=0.75; // normal (0-1)
acceleration=1;
max_speed=12;
braking_strength=2;
reverse_acceleration=1;
max_reverse_speed=4;
handbrake_slowdown_rate=0.5;
natural_deceleration_rate=0.08; // normal (0-1)
veer_left_strength=3;
drift_left_strength=1.7;
drift_left_angular_bonus=2;
veer_right_strength=3;
drift_right_strength=1.7;
drift_right_angular_bonus=2;
drift_return_strength=0.2; // normal (0-1)
veer_return_strength=0.75; // normal (0-1)
drift_angle_pullback=0.04; // normal (0-1)
veer_angle_pullback=0.2; // normal (0-1)
minumum_drifting_speed=6;
crash_bounce_back=0.25; // normal (0-1)
skid_start_threshold=1.2;

// ricochet settings:
var ricochet_precision, ricochet_speed_loss, max_ricochet_angle;
ricochet_precision=5;
ricochet_speed_loss=0.3; // normal (0-1)
max_ricochet_angle=55;

// position correction settings:
var pos_corr_distance_precision, pos_corr_distance,
pos_corr_angular_precision, pos_corr_distance_precision;
pos_corr_distance_precision=1;
pos_corr_distance=18;
pos_corr_angular_precision=2;
pos_corr_distance_precision=1;

var do_handbrake=argument0;
var turn_left_magnitude=argument1;
var turn_right_magnitude=argument2;
var gas_magnitude=argument3;
var brake_magnitude=argument4;

// "skid_threshold" is a precise angualar threshold that the veering rate can meet, but not pass.
var skid_threshold = (1/(-veer_return_strength+1))*max(veer_right_strength,veer_left_strength);
if speed=0 direction=image_angle;
if do_handbrake is_skidding=true;
var do_gas=gas_magnitude>input_deadzone
var do_brake=brake_magnitude>input_deadzone
var do_left=turn_left_magnitude>input_deadzone;
var do_right=turn_right_magnitude>input_deadzone;
// if angular difference is somehow in the range of skidding, enable skidding.
if abs(angle_difference(direction,image_angle))>skid_threshold*skid_start_threshold is_skidding=true;
// acceleration
if not do_handbrake and do_gas {
 var raw_speed_gain=lerp(gas_magnitude*acceleration,0,min(abs(angle_difference(direction,image_angle)),90)/90);
 speed+=lerp(raw_speed_gain,0,abs(speed)/max_speed);
}
// brake and reverse
if not do_handbrake and do_brake {
 if speed>0 speed-=brake_magnitude*braking_strength;
 else { // reverse
  speed-=lerp(reverse_acceleration,0,abs(speed)/max_reverse_speed);
 }
}
if do_handbrake {
 speed+=-sign(speed)*handbrake_slowdown_rate;
}
// natural deceleration
if not do_brake and not do_gas {
 speed+=-sign(speed)*natural_deceleration_rate;
 if abs(speed)<=natural_deceleration_rate speed=0;
}

if do_left and do_right do_left=false;
// turn left
if do_left {
 if is_skidding {
  image_angle+=drift_left_angular_bonus+min((speed/max_speed)*(drift_left_strength*turn_left_magnitude),drift_left_strength)
 }
 else image_angle+=min((speed/max_speed)*(veer_left_strength*turn_left_magnitude),veer_left_strength)
}
// turn right
if do_right {
 if is_skidding {
  image_angle-=drift_right_angular_bonus+min((speed/max_speed)*(drift_right_strength*turn_right_magnitude),drift_right_strength)
 }
 else image_angle-=min((speed/max_speed)*(veer_right_strength*turn_right_magnitude),veer_right_strength)
}
// veer return and skid return
if not do_left and not do_right {
 if is_skidding direction=lerp(direction,direction-angle_difference(direction,image_angle),drift_return_strength)
 else direction=lerp(direction,direction-angle_difference(direction,image_angle),veer_return_strength)
}
// veering and drifting
else { 
 if is_skidding direction=direction-lerp(0,angle_difference(direction,image_angle),drift_angle_pullback)
 else direction=direction-lerp(0,angle_difference(direction,image_angle),veer_angle_pullback)
}
// stop skidding
if (not do_handbrake and abs(angle_difference(direction,image_angle))<=skid_threshold) or abs(speed)<minumum_drifting_speed {
 is_skidding=false;
}

// - - - POSITION CORRECTION - - -

if not place_free(x,y) {
 ii=pos_corr_distance_precision;
 var ii2=0;
 while ii<=pos_corr_distance {
  while ii2<360 {
   if place_free(x+lengthdir_x(ii,ii2),y+lengthdir_y(ii,ii2)) {
    x=x+lengthdir_x(ii,ii2)
    y=y+lengthdir_y(ii,ii2)
    ii=9999;
    ii2=9999;
   }
   ii2+=pos_corr_angular_precision;
  }
  ii2=0;
  ii+=pos_corr_distance_precision;
 }
}

// - - - COLLISION DETECTION - - -

// ricochet and head-on collision
if abs(speed)>0 {
 // ricochet
 if speed>0 {
  ii=ricochet_precision;
  if not place_free(x+hspeed,y+vspeed) move_contact_solid(direction,speed);
  while not place_free(x+hspeed,y+vspeed) and ii<=max_ricochet_angle {
   var free_minus = place_free(x+lengthdir_x(speed,direction-ii),y+lengthdir_y(speed,direction-ii))
   var free_plus = place_free(x+lengthdir_x(speed,direction+ii),y+lengthdir_y(speed,direction+ii))
   if free_minus and free_plus { // if both places are free, choose one randomly.
    if irandom(1) free_minus=false;
    else free_plus=false;
   }
   if free_plus and not free_minus {
    direction+=ii;
    speed=lerp(speed,speed*ricochet_speed_loss,ii/max_ricochet_angle);
    ii=9999;
    crash_damage=ii/max_ricochet_angle;
   }
   if free_minus and not free_plus {
    direction-=ii;
    speed=lerp(speed,speed*ricochet_speed_loss,ii/max_ricochet_angle);
    ii=9999;
    crash_damage=ii/max_ricochet_angle;
   }
   ii+=ricochet_precision;
  }
 }
 // head-on collision
 if not place_free(x+lengthdir_x(speed,direction),y+lengthdir_y(speed,direction)) {
  speed=-speed*crash_bounce_back;
  crash_damage=1+(abs(speed)/max_speed);
  //stop skidding
  direction=image_angle+median(skid_threshold,-skid_threshold,angle_difference(image_angle,direction))
  is_skidding=false;
 }
}

Last edited by lostdarkwolf (2019-08-27 21:55:22)

Offline

Board footer

Powered by FluxBB