198 lines
6.3 KiB
GDScript
198 lines
6.3 KiB
GDScript
extends CharacterBody2D
|
|
|
|
#Tutorial: https://www.youtube.com/watch?v=mJ1ZfGDTMCY t=15s
|
|
|
|
const COLLISIONMASK_FINISH=3 #set in road_overlay
|
|
const COLLISIONMASK_CHECKPOINT=4 #set in road_overlay
|
|
|
|
const ROAD_R_NAME="road_r"
|
|
const ROAD_L_NAME="road_l"
|
|
|
|
const STANDSTILLSPEED=0.5
|
|
var wheel_base = 60*0.5
|
|
|
|
var engine_power = 350
|
|
|
|
var friction = -0.5
|
|
var drag = -0.0005
|
|
var braking = -200
|
|
var max_speed_reverse = 100
|
|
var slip_speed = 200
|
|
var traction_fast = 0.1 #traction when above slip_speed
|
|
var traction_slow = 0.5
|
|
|
|
|
|
#Automatic Steering settings
|
|
|
|
var steering_speed_slow = 50 #speed for slow steering
|
|
var steering_angle_slow = 50 #maximum angle slow speed
|
|
var steering_distance_far_slow=200
|
|
var steering_distance_close_slow=20
|
|
|
|
var steering_speed_fast = 300 #speed for fast steering
|
|
var steering_angle_fast = 5 #maximum angle fast speed
|
|
var steering_distance_far_fast=256
|
|
var steering_distance_close_fast=128
|
|
|
|
# resetCar
|
|
var resetcar_stoppedspeed = 30 #activate timer when below this speed
|
|
var resetcar_movingspeed=resetcar_stoppedspeed+10 #stop timer when above this speed
|
|
var resetcar_distance=128 #196 is roughly when car is in the middle of a two wide road
|
|
var resetcar_steerangle=120
|
|
|
|
|
|
#Variables
|
|
var acceleration = Vector2.ZERO
|
|
|
|
var steer_direction=0
|
|
|
|
var autoreset=false
|
|
|
|
@onready var ray_cast_fl: RayCast2D = $RayCast_FL
|
|
@onready var ray_cast_fr: RayCast2D = $RayCast_FR
|
|
@onready var reset_timer: Timer = $resetTimer
|
|
|
|
@onready var ray_cast_car: RayCast2D = $RayCast_Car #for tracking markers
|
|
|
|
var playerid=0
|
|
|
|
func _physics_process(delta: float) -> void:
|
|
acceleration=Vector2.ZERO
|
|
check_markers()
|
|
get_input()
|
|
apply_friction()
|
|
calculate_steering(delta)
|
|
velocity +=acceleration*delta
|
|
#velocity = transform.x * 200
|
|
#vel = move_and_slide()
|
|
move_and_slide()
|
|
if get_slide_collision_count()>0:
|
|
velocity/=2
|
|
#for i in get_slide_collision_count():
|
|
# var collision = get_slide_collision(i)
|
|
# print("Collided with: ", collision.get_collider().name)
|
|
|
|
if velocity.length() < resetcar_stoppedspeed: #moving slow, possibly crash?
|
|
if reset_timer.is_stopped():
|
|
reset_timer.start()
|
|
if velocity.length() > resetcar_movingspeed:
|
|
reset_timer.stop()
|
|
|
|
|
|
|
|
func _on_reset_timer_timeout() -> void:
|
|
print("resetting car")
|
|
autoreset=true
|
|
|
|
func apply_friction():
|
|
if velocity.length() < STANDSTILLSPEED: #standstill
|
|
velocity=Vector2.ZERO
|
|
var friction_force=velocity*friction
|
|
var drag_force=velocity*velocity.length()*drag
|
|
|
|
acceleration+=drag_force+friction_force
|
|
|
|
func get_input():
|
|
|
|
|
|
const distance_inf=1000
|
|
var distance_fl=distance_inf
|
|
var distance_fr=distance_inf
|
|
if ray_cast_fl.is_colliding():
|
|
var origin=ray_cast_fl.global_transform.origin
|
|
var collision_point = ray_cast_fl.get_collision_point()
|
|
distance_fl = origin.distance_to(collision_point)
|
|
var collision_object=ray_cast_fl.get_collider()
|
|
#if collision_object.name==ROAD_R_NAME:
|
|
|
|
#print("DistanceFL "+str(distance_fl))
|
|
if ray_cast_fr.is_colliding():
|
|
var origin=ray_cast_fr.global_transform.origin
|
|
var collision_point = ray_cast_fr.get_collision_point()
|
|
distance_fr = origin.distance_to(collision_point)
|
|
#print("DistanceFR "+str(distance_fr))
|
|
|
|
var distance_min= min(distance_fl,distance_fr)
|
|
|
|
var turndirection = 1 if distance_fl<distance_fr else -1
|
|
|
|
|
|
var steering_angle=constrain( remap(velocity.length(),steering_speed_fast,steering_speed_slow,steering_angle_fast,steering_angle_slow),steering_angle_fast,steering_angle_slow) #set maximum steering_angle based on speed
|
|
var steering_distance_far=constrain( remap(velocity.length(),steering_speed_fast,steering_speed_slow,steering_distance_far_fast,steering_distance_far_slow),steering_distance_far_fast,steering_distance_far_slow)
|
|
var steering_distance_close=constrain( remap(velocity.length(),steering_speed_fast,steering_speed_slow,steering_distance_close_fast,steering_distance_close_slow),steering_distance_close_fast,steering_distance_close_slow)
|
|
|
|
|
|
|
|
if distance_min<steering_distance_far: #wall close, start steering away
|
|
steer_direction = turndirection*deg_to_rad(constrain(remap(distance_min,steering_distance_far,steering_distance_close,0,steering_angle), 0,steering_angle))
|
|
else:
|
|
steer_direction=0 #drive straight
|
|
|
|
# Manual steering here
|
|
var turn = 0
|
|
if Input.is_action_pressed("ui_right"):
|
|
turn += 1
|
|
if Input.is_action_pressed("ui_left"):
|
|
turn -= 1
|
|
if turn!=0:
|
|
steer_direction = turn*deg_to_rad(steering_angle)
|
|
|
|
|
|
|
|
|
|
if Input.is_action_pressed("ui_up") or Input.is_action_pressed(Gamestate.userinput_prefix+str(playerid)):
|
|
#velocity = transform.x * 500
|
|
acceleration = transform.x * engine_power
|
|
|
|
if autoreset:
|
|
print("Cancel autoreset")
|
|
autoreset=false
|
|
if Input.is_action_pressed("ui_down"):
|
|
acceleration = transform.x * braking
|
|
|
|
|
|
if autoreset:
|
|
acceleration = transform.x * braking #drive backwards
|
|
|
|
if distance_min>=resetcar_distance: #nothing in front of car
|
|
steer_direction=resetcar_steerangle #keep steering so turn around if standing in the middle of a track
|
|
else:
|
|
steer_direction*=-1 #invert steering
|
|
else:
|
|
if steer_direction>1:
|
|
resetcar_steerangle=max(-resetcar_steerangle,+resetcar_steerangle) #calculate steering direction for next autoreset
|
|
if steer_direction<1:
|
|
resetcar_steerangle=min(-resetcar_steerangle,+resetcar_steerangle) #calculate steering direction for next autoreset
|
|
|
|
|
|
func calculate_steering(delta:float):
|
|
var rear_wheel = position - transform.x *wheel_base/2.0
|
|
var front_wheel = position + transform.x *wheel_base/2.0
|
|
rear_wheel += velocity*delta
|
|
front_wheel += velocity.rotated(steer_direction)*delta
|
|
var new_heading = (front_wheel-rear_wheel).normalized()
|
|
|
|
var traction = traction_slow
|
|
if velocity.length() > slip_speed:
|
|
traction = traction_fast
|
|
|
|
var d = new_heading.dot(velocity.normalized())
|
|
if d > 0:
|
|
velocity = velocity.lerp(new_heading * velocity.length(), traction)
|
|
elif d<0:
|
|
velocity = - new_heading * min(velocity.length(),max_speed_reverse)
|
|
rotation = new_heading.angle()
|
|
|
|
|
|
func check_markers():
|
|
if ray_cast_car.is_colliding():
|
|
#print("Marker: "+str(ray_cast_car.get_collider()))
|
|
if ray_cast_car.get_collision_mask_value(COLLISIONMASK_FINISH):
|
|
print("Player "+str(playerid)+" Finished")
|
|
if ray_cast_car.get_collision_mask_value(COLLISIONMASK_CHECKPOINT):
|
|
print("Player "+str(playerid)+" Checkpint")
|
|
|
|
func constrain(val,a,b):
|
|
var vmin=min(a,b)
|
|
var vmax=max(a,b)
|
|
return min(vmax,max(vmin,val))
|