1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
|
extends RigidBody2D
var velocity #How fast car is moving
var velVector #What direction the car is moving
var velUnitVector #Direction vector, but in a single unit(no magnitude)
var velAngle #The angle of the velocity(relative to world)
var carAngle #The angle to car is facing(relative to world)
#Skidmarks on floor
onready var skidObj = preload("res://4WheelCar/Skid/Skidmark.tscn")
#Reduces steering strength when braking
var steerDampBase = 1
var steerDamp = 1
#Steering Curve Vars
var steerSplitA = 20
var steerSplitB = 40
var steerHeight = 2.6
var steerLimit = 73
var steerMinimum = 1
var gripDelay = 0
var wheelSlip = Vector2(0,0)
var isSkid = false #this one is used when user presses shift. Initially called in this function
var isSkidOverride = false #this one is used when driving over sand, initially called in carbody
signal slip
signal end
var elapsed = 0
var isForward = true
# Called when the node enters the scene tree for the first time.
func _ready():
pass
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
#Variable Setup
#---
velocity = measure_velocity()
velVector = get_node("../../../CarBody").get_linear_velocity()
velUnitVector = velVector.normalized()
velAngle = atan2(velVector.y,velVector.x)
carAngle = get_node("../../../CarBody").get_transform().get_rotation()
isForward = is_forward()
#---
set_rotation(carAngle)
# gripDelay = has_grip(0.4,delta)
isSlip(delta)
if(!isSkidOverride):
isSkid = Input.is_action_pressed("grip")
#Determines if drifting
if Input.is_action_pressed("grip") || Input.is_action_pressed("brake"):
null_slide(max(5,velocity/7),delta)
else:
null_slide(1,delta)
#Braking
if Input.is_action_pressed("brake"):
if velocity > 20:
linear_damp = 3
steerDamp = 0.7
else:
linear_damp = 6
steerDamp = 0.4
else:
linear_damp = 0.01
steerDamp = 1
#Steering
if Input.is_action_pressed("steer_left"):
apply_central_impulse(steerDamp*Vector2(0,steer_curve(steerSplitA, steerSplitB, steerHeight, steerLimit,steerMinimum)).rotated(steer_angle())*delta*5000)
if Input.is_action_pressed("steer_right"):
apply_central_impulse(steerDamp*Vector2(0,-steer_curve(steerSplitA, steerSplitB, steerHeight, steerLimit,steerMinimum)).rotated(steer_angle())*delta*5000)
func null_slide(var strength, var delta):
#strength is how strong you would like the nullify to be
#higher is less sliding/drifting
var movementUnitVector = get_linear_velocity().normalized()#the direction of the velocity
var directionAngle = carAngle + (PI/2.0)#the angle the car is facing(relative to the world)
var directionUnitVector = Vector2(cos(directionAngle),sin(directionAngle)).normalized()#the direction the car is facing
var nullify = directionUnitVector * movementUnitVector.dot(directionUnitVector)
wheelSlip = (-(movementUnitVector - nullify))*strength
apply_central_impulse(wheelSlip*delta*5000)
#func has_grip(var tractionDelay, var delta):
# var movementUnitVector = get_linear_velocity().normalized()#the direction of the velocity
# var directionAngle = carAngle#the angle the car is facing(relative to the world)
# var directionUnitVector = Vector2(cos(directionAngle),sin(directionAngle)).normalized()#the direction the car is facing
# if velocity > 10:
# if Input.is_action_pressed("grip"):##if pressing shift
# gripDelay = tractionDelay
# elif (gripDelay <= 0 && abs(movementUnitVector.dot(directionUnitVector)) > 0.4):#if not drifting but past steering point
# gripDelay = tractionDelay
# elif gripDelay > 0 && abs(movementUnitVector.dot(directionUnitVector)) > 0.3:#if drifting and past steering point
# gripDelay = tractionDelay
# elif gripDelay > 0:#if at recovery point and drifting
# gripDelay -= delta
# else:
# gripDelay = 0
# return gripDelay
#Determines if skidmarks should be creted, or stopped
func isSlip(time):
if (wheelSlip.length() > 0.6):
if(elapsed/4 > time):
emit_signal("end")
elapsed = 0
else:
emit_signal("slip")
else:
elapsed += time
func measure_velocity():
return floor(sqrt(get_linear_velocity().dot(get_linear_velocity()))/12)
#determines if the car is driving forward, or backward
func is_forward():
var carVector = Vector2(cos(carAngle + PI/2),sin(carAngle + PI/2))
if velVector == Vector2(0,0) || carVector == Vector2(0,0):
return true
if velVector.dot(carVector) <= 0:
return true
else:
return false
#returns the angle the car is facing, relative to the direction it is moving
func steer_angle():
if isForward:
return carAngle + (PI/2.0)
else:
return carAngle - (PI/2.0)
#Determines strength of steering as a function of the speed
func steer_curve(var splitA, splitB, var height, var limit, var minimum):
#Rules:
# splitA < splitB < limit
# height > 0, limit >= 0
# ---
#Desmos: SteerCurve
#Link: https://www.desmos.com/calculator/jkrd8zzoj9
# splitA = a
# splitB = b
# height = h
# limit = f
#note: minimum is not in the graph, it is simply the minimum y value you want when x > splitB
# ---
if(velocity >= splitB):
return max((-pow((velocity-splitB)/((limit-splitB)/sqrt(height)),2)+height)*abs(cos(abs(velAngle-carAngle)+PI/2)),minimum)
elif velocity >= splitA:
return height
else:
return max((-pow((velocity/(splitA/sqrt(height)))-sqrt(height),2)+height)*abs(cos(abs(velAngle-carAngle)+PI/2)),0)
|