2024-11-03 18:16:30 +00:00
extends CharacterBody2D
#Tutorial: https://www.youtube.com/watch?v=mJ1ZfGDTMCY t=15s
2024-11-06 06:38:44 +00:00
signal car_finished ( playerid , finalTime )
2024-11-04 20:56:07 +00:00
2024-11-03 18:16:30 +00:00
const COLLISIONMASK_FINISH = 3 #set in road_overlay
const COLLISIONMASK_CHECKPOINT = 4 #set in road_overlay
2024-11-05 07:18:14 +00:00
var checkpoints : Array [ String ] = [ ] #gets set on car creation
var checkpointtimes : Array [ float ] = [ ]
2024-11-03 21:37:15 +00:00
const ROAD_R_NAME = " road_r "
const ROAD_L_NAME = " road_l "
2024-11-06 06:38:44 +00:00
const COLLISION_SLOWDOWN_CAR = 1.01
const COLLISION_SLOWDOWN_WALL = 1.2
2024-11-03 18:16:30 +00:00
const STANDSTILLSPEED = 0.5
var wheel_base = 60 * 0.5
2024-11-06 18:46:47 +00:00
var engine_power = 350
2024-11-03 18:16:30 +00:00
var friction = - 0.5
var drag = - 0.0005
var braking = - 200
var max_speed_reverse = 100
2024-11-09 13:38:26 +00:00
var slip_speed = 150
var traction_fast = 0.05 #traction when above slip_speed
2024-11-03 18:16:30 +00:00
var traction_slow = 0.5
#Automatic Steering settings
2024-11-09 09:32:12 +00:00
var steering_speed_slow = 150 #speed for slow steering
2024-11-03 18:16:30 +00:00
var steering_angle_slow = 50 #maximum angle slow speed
var steering_distance_far_slow = 200
var steering_distance_close_slow = 20
2024-11-09 09:32:12 +00:00
var steering_speed_fast = 400 #speed for fast steering
2024-11-09 13:38:26 +00:00
var steering_angle_fast = 1 #maximum angle fast speed
2024-11-03 18:16:30 +00:00
var steering_distance_far_fast = 256
var steering_distance_close_fast = 128
# resetCar
2024-11-06 18:46:47 +00:00
var resetcar_stoppedspeed = 50 #activate timer when below this speed
2024-11-03 18:16:30 +00:00
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
2024-11-06 06:38:44 +00:00
var running = false
2024-11-03 18:16:30 +00:00
var acceleration = Vector2 . ZERO
var steer_direction = 0
var autoreset = false
2024-11-04 20:56:07 +00:00
var autosteer_enabled = false
2024-11-03 18:16:30 +00:00
@ 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
2024-11-04 20:56:07 +00:00
@ onready var collision_shape : CollisionShape2D = $ CollisionShape2D
@ onready var collision_enable_timer : Timer = $ collisionEnableTimer
2024-11-03 18:16:30 +00:00
var playerid = 0
2024-11-06 06:38:44 +00:00
var finalTime = - 1
2024-11-03 18:16:30 +00:00
2024-11-04 20:56:07 +00:00
func _ready ( ) - > void :
collision_shape . disabled = true #disable collisions on start. also to avoid collision when initially setting position
2024-11-06 06:38:44 +00:00
finalTime = - 1
2024-11-05 07:18:14 +00:00
2024-11-04 20:56:07 +00:00
2024-11-03 18:16:30 +00:00
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 ( )
2024-11-06 06:38:44 +00:00
for i in get_slide_collision_count ( ) :
var collision = get_slide_collision ( i )
#if $".".name==collision.get_collider().name: #collided with another car
# velocity-=COLLISION_SLOWDOWN_CAR
if ROAD_R_NAME == collision . get_collider ( ) . name or ROAD_L_NAME == collision . get_collider ( ) . name : #collided with road
velocity /= COLLISION_SLOWDOWN_WALL
2024-11-09 13:38:26 +00:00
#if get_slide_collision_count()>0:
# velocity/=2
2024-11-03 18:16:30 +00:00
#for i in get_slide_collision_count():
# var collision = get_slide_collision(i)
# print("Collided with: ", collision.get_collider().name)
2024-11-04 20:56:07 +00:00
if velocity . length ( ) < resetcar_stoppedspeed and autosteer_enabled : #moving slow, possibly crash?
2024-11-03 18:16:30 +00:00
if reset_timer . is_stopped ( ) :
reset_timer . start ( )
if velocity . length ( ) > resetcar_movingspeed :
reset_timer . stop ( )
func _on_reset_timer_timeout ( ) - > void :
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 )
2024-11-03 21:37:15 +00:00
var collision_object = ray_cast_fl . get_collider ( )
#if collision_object.name==ROAD_R_NAME:
2024-11-03 18:16:30 +00:00
#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 )
2024-11-04 20:56:07 +00:00
if autosteer_enabled :
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
2024-11-03 18:16:30 +00:00
2024-11-06 06:38:44 +00:00
if running :
if Input . is_action_pressed ( Gamestate . userinput_prefix + str ( playerid ) ) :
#velocity = transform.x * 500
acceleration = transform . x * engine_power
if not autosteer_enabled : #start autosteer when accelerate is pressed
autosteer_enabled = true
collision_enable_timer . start ( )
if autoreset :
print ( " Cancel autoreset " )
autoreset = false
#if Input.is_action_pressed("ui_down"):
#acceleration = transform.x * braking
2024-11-03 18:16:30 +00:00
2024-11-06 06:38:44 +00:00
if autoreset and running :
2024-11-03 18:16:30 +00:00
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 ( )
2024-11-09 13:27:34 +00:00
func getRound ( ) :
var i = getNextCPindex ( ) / checkpoints . size ( )
return i
2024-11-03 18:16:30 +00:00
2024-11-10 00:06:25 +00:00
2024-11-03 18:16:30 +00:00
func check_markers ( ) :
if ray_cast_car . is_colliding ( ) :
#print("Marker: "+str(ray_cast_car.get_collider()))
2024-11-05 07:18:14 +00:00
#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):
var rcc_collidername = ray_cast_car . get_collider ( ) . name
if rcc_collidername == " area_finish " :
2024-11-09 13:27:34 +00:00
$ label_round . showRounds ( getRound ( ) )
2024-11-05 07:18:14 +00:00
#print("Player "+str(playerid)+" drove through Finish")
2024-11-09 13:27:34 +00:00
if getNextCPindex ( ) == - 1 and finalTime == - 1 : #all checkpoints have times and did not finish = Finished
2024-11-05 07:18:14 +00:00
print ( " Player " + str ( playerid ) + " Finished " )
2024-11-06 06:38:44 +00:00
print ( " Final Time: " + str ( Gamestate . getTimeElapsed ( ) ) )
running = false
finalTime = Gamestate . getTimeElapsed ( )
car_finished . emit ( playerid , finalTime )
elif rcc_collidername . begins_with ( " area_cp " ) :
var nextcp_i = getNextCPindex ( )
2024-11-05 07:18:14 +00:00
var checkpoint_i = checkpoints . find ( rcc_collidername )
2024-11-06 06:38:44 +00:00
if checkpoint_i > = 0 and nextcp_i > = 0 : #found and there is a next checkpoint time free
if ( nextcp_i % checkpoints . size ( ) ) == checkpoint_i : #this cp is next cp
checkpointtimes [ nextcp_i ] = Gamestate . getTimeElapsed ( )
2024-11-10 00:06:25 +00:00
#print("Player "+str(playerid)+" Checkpoint "+str(ray_cast_car.get_collider().name))
#print("New CP array "+str(checkpointtimes))
2024-11-03 18:16:30 +00:00
func constrain ( val , a , b ) :
var vmin = min ( a , b )
var vmax = max ( a , b )
return min ( vmax , max ( vmin , val ) )
2024-11-04 20:56:07 +00:00
2024-11-06 06:38:44 +00:00
func getNextCPindex ( ) :
#returns index of first 0 value in times array
#-1 if all cps have times
#[10.2,15.5,12.2,0,0,0,0] -> 3
var i = 0
for cpt in checkpointtimes :
if cpt == 0 :
return i
i += 1
return - 1
2024-11-04 20:56:07 +00:00
func _on_collision_enable_timer_timeout ( ) - > void :
collision_shape . disabled = false