You are not logged in.
Pages: 1
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
Cool. Can you upload an .exe so we can see this in action?
Offline
I mage an example, although it could use a bit more polish. there will be a 2D example as well, but not yet. Example Link GMZ host-a.net
Anyone can feel free to use whatever resources. This includes the provided hover car model. Be aware that I may still use the hover car model in my own project as well. Sharing is caring.
Last edited by lostdarkwolf (2020-09-02 23:31:50)
Offline
Pages: 1