VehicleController.gd 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. extends RigidBody
  2. class_name VehicleController
  3. signal query_driver(driver)
  4. signal update_motor_sound(vehicle_controller)
  5. export var force_curve: Curve
  6. export var force_max_value: float = 20000
  7. export var vmax: float = 20
  8. export var vmin_grip: float = 2
  9. export var vmax_wheel_spin: float = 6
  10. export var omega_curve: Curve
  11. export var omega_max: float = 0.6
  12. export var spring_distance_max: float = 0.14
  13. # Hard spring.
  14. export var spring_constant: float = 42214
  15. export var spring_damping: float = 7904
  16. onready var steering_controller: Node = get_node("SteeringController")
  17. onready var omega_controller: Node = get_node("OmegaController")
  18. onready var fl: WheelController = get_node("FL")
  19. onready var fr: WheelController = get_node("FR")
  20. onready var rl: WheelController = get_node("RL")
  21. onready var rr: WheelController = get_node("RR")
  22. var driver = Driver.new()
  23. var vehicle_state = VehicleState.new()
  24. var wheel_state = WheelState.new()
  25. var drift_angle_max_degree: float = 1
  26. var brake_value: float = 20000
  27. var has_grip: bool = false
  28. var grip_force: float
  29. var driving_force_position: Vector3 # The force to move the car is applied at this position (local to the car).
  30. var offset_drive: Vector3
  31. var omega_reference: float
  32. var wheelbase: float
  33. var turn_radius: float
  34. var velocity_measurement: float
  35. var acceleration_measurement: float
  36. var acceleration_force: float
  37. func _ready():
  38. wheelbase = rl.transform.origin.z - fl.transform.origin.z
  39. driving_force_position = Vector3(0, -rl.wheel_radius, wheelbase * 0.5) # At the rear axis and at the contact point of the wheel.
  40. fl.init_suspension(weight / 4, spring_distance_max, spring_constant, spring_damping)
  41. fr.init_suspension(weight / 4, spring_distance_max, spring_constant, spring_damping)
  42. rl.init_suspension(weight / 4, spring_distance_max, spring_constant, spring_damping)
  43. rr.init_suspension(weight / 4, spring_distance_max, spring_constant, spring_damping)
  44. func _physics_process(delta: float):
  45. var torque: float
  46. var torque_vector: Vector3
  47. var vehicle_velocity_magnitude: float = linear_velocity.length()
  48. var vehicle_rotation = Quat(transform.basis)
  49. var on_ground = update_suspension(delta, vehicle_rotation)
  50. if !on_ground:
  51. has_grip = false
  52. grip_force = steering_controller.reset()
  53. omega_controller.reset()
  54. return
  55. offset_drive = vehicle_rotation * driving_force_position
  56. vehicle_state.update(vehicle_rotation, linear_velocity)
  57. acceleration_measurement = (vehicle_velocity_magnitude - velocity_measurement) / delta
  58. velocity_measurement = vehicle_velocity_magnitude
  59. var steering: float = vehicle_state.drift_angle_measurement
  60. turn_radius = get_turn_radius(vehicle_velocity_magnitude)
  61. if vehicle_velocity_magnitude < vmin_grip:
  62. has_grip = false
  63. else:
  64. if driver.did_accelerate:
  65. if vehicle_state.drift_angle_measurement > deg2rad(-drift_angle_max_degree) && vehicle_state.drift_angle_measurement < deg2rad(drift_angle_max_degree):
  66. has_grip = true
  67. if has_grip:
  68. adjust_steering(vehicle_rotation)
  69. steering = asin(wheelbase / turn_radius)
  70. else:
  71. grip_force = steering_controller.reset()
  72. if driver.did_accelerate:
  73. accelerate()
  74. if vehicle_state.velocity_rear_axis < vmax_wheel_spin:
  75. vehicle_state.velocity_rear_axis = vmax_wheel_spin
  76. else: if driver.did_reverse:
  77. reverse()
  78. else:
  79. acceleration_force = 0
  80. if driver.did_brake:
  81. brake(vehicle_velocity_magnitude)
  82. control_omega(delta, vehicle_velocity_magnitude)
  83. torque = omega_controller.adjust(omega_reference, angular_velocity.y)
  84. torque_vector = vehicle_rotation * Vector3.UP * torque
  85. add_torque(torque_vector)
  86. emit_signal("query_driver", driver)
  87. emit_signal("update_motor_sound", self)
  88. wheel_state.update(delta, vehicle_state.velocity_front_axis, vehicle_state.velocity_rear_axis)
  89. update_wheel_rotation(delta, steering)
  90. func adjust_steering(vehicle_rotation: Quat):
  91. grip_force = steering_controller.adjust(0, vehicle_state.velocity_sideways)
  92. var direction = vehicle_rotation * Vector3.LEFT
  93. var grip_force_vector: Vector3 = direction * grip_force
  94. add_force(grip_force_vector, offset_drive)
  95. func control_omega(delta: float, velocity: float):
  96. var arg: float = velocity / vmax
  97. var extent: float = omega_curve.interpolate(arg)
  98. var direction: float
  99. if driver.did_steer_left:
  100. direction = 1
  101. if driver.did_steer_right:
  102. direction = -1
  103. if vehicle_state.velocity_rear_axis > velocity: # Obstacle detected ?
  104. extent = 1
  105. else:
  106. if !vehicle_state.vehicle_moving_forward:
  107. direction = -direction
  108. if driver.did_steer:
  109. omega_reference = extent * lerp(omega_reference, omega_max * direction, 2 * delta)
  110. else:
  111. omega_reference = lerp(omega_reference, 0, 2 * delta)
  112. func update_wheel_rotation(delta: float, steering: float):
  113. fl.rotate_wheel(delta, wheel_state.total_movement_front, steering)
  114. fr.rotate_wheel(delta, wheel_state.total_movement_front, steering)
  115. rl.rotate_wheel(delta, wheel_state.total_movement_rear, 0)
  116. rr.rotate_wheel(delta, wheel_state.total_movement_rear, 0)
  117. func accelerate():
  118. acceleration_force = force_max_value * force_curve.interpolate(velocity_measurement / vmax)
  119. var force_vector: Vector3 = vehicle_state.vehicle_direction * acceleration_force
  120. add_force(force_vector, offset_drive)
  121. func reverse():
  122. var velocity_max_reverse: float = 7
  123. if velocity_measurement < velocity_max_reverse:
  124. acceleration_force = force_max_value * 0.5
  125. var force_vector: Vector3 = vehicle_state.vehicle_direction * acceleration_force
  126. add_force(-force_vector, offset_drive)
  127. func brake(vehicle_velocity_magnitude: float):
  128. var brake_force: Vector3
  129. vehicle_state.brake()
  130. omega_reference = 0
  131. if vehicle_velocity_magnitude < 0.5:
  132. brake_force = brake_value * vehicle_velocity_magnitude * vehicle_state.velocity_direction
  133. else:
  134. brake_force = brake_value * vehicle_state.velocity_direction
  135. add_force(-brake_force, offset_drive)
  136. func get_grip() -> bool:
  137. return has_grip
  138. func get_grip_force() -> float:
  139. return grip_force
  140. func get_velocity_rear_axis() -> float:
  141. return vehicle_state.velocity_rear_axis
  142. func get_omega_reference() -> float:
  143. return omega_reference
  144. func get_turn_radius(vehicle_velocity_magnitude: float) -> float:
  145. var radius: float
  146. var radius_min: float = 1.1 * wheelbase
  147. if angular_velocity.y > 0:
  148. radius = min(999, vehicle_velocity_magnitude / angular_velocity.y)
  149. if radius < radius_min:
  150. radius = radius_min
  151. else: if angular_velocity.y < 0:
  152. radius = max(-999, vehicle_velocity_magnitude / angular_velocity.y)
  153. if radius > -radius_min:
  154. radius = -radius_min
  155. else:
  156. radius = 999
  157. if radius > -radius_min && radius < radius_min:
  158. print_debug("turn radius?")
  159. return radius
  160. func get_vmax() -> float:
  161. return vmax
  162. func get_acceleration_force_relative() -> float:
  163. return acceleration_force / force_max_value
  164. func update_suspension(delta: float, vehicle_rotation: Quat) -> bool:
  165. var contact_front: bool
  166. var contact_rear: bool
  167. contact_front = fl.add_spring_force(delta, self, vehicle_rotation)
  168. contact_front = fr.add_spring_force(delta, self, vehicle_rotation) && contact_front
  169. contact_rear = rl.add_spring_force(delta, self, vehicle_rotation)
  170. contact_rear = rr.add_spring_force(delta, self, vehicle_rotation) && contact_rear
  171. return contact_front && contact_rear
  172. class VehicleState:
  173. var velocity_front_axis: float
  174. var velocity_rear_axis: float
  175. var velocity_sideways: float
  176. var vehicle_direction: Vector3
  177. var velocity_direction: Vector3
  178. var vehicle_moving_forward: bool
  179. var drift_angle_measurement: float
  180. func update(vehicle_rotation: Quat, vehicle_velocity: Vector3):
  181. var vehicle_direction_sideways: Vector3 = vehicle_rotation * Vector3.LEFT
  182. vehicle_direction = vehicle_rotation * Vector3.FORWARD
  183. velocity_front_axis = vehicle_velocity.length()
  184. velocity_rear_axis = vehicle_velocity.dot(vehicle_direction)
  185. velocity_sideways = vehicle_velocity.dot(vehicle_direction_sideways)
  186. if velocity_front_axis > 0:
  187. velocity_direction = vehicle_velocity.normalized()
  188. else:
  189. velocity_direction = vehicle_direction
  190. vehicle_moving_forward = vehicle_direction.dot(velocity_direction) > 0
  191. var cross_product: Vector3
  192. if vehicle_moving_forward:
  193. cross_product = vehicle_direction.cross(velocity_direction)
  194. else:
  195. cross_product = velocity_direction.cross(vehicle_direction)
  196. if velocity_front_axis > 0.1:
  197. drift_angle_measurement = asin(cross_product.y)
  198. if !vehicle_moving_forward:
  199. velocity_front_axis = -velocity_front_axis
  200. func brake():
  201. velocity_front_axis = 0
  202. velocity_rear_axis = 0
  203. class WheelState:
  204. var total_movement_front: float
  205. var total_movement_rear: float
  206. func update(delta: float, velocity_front_axis: float, velocity_rear_axis: float):
  207. total_movement_front += delta * velocity_front_axis
  208. total_movement_rear += delta * velocity_rear_axis
  209. class Driver:
  210. var did_steer: bool
  211. var did_steer_left: bool
  212. var did_steer_right: bool
  213. var did_accelerate: bool
  214. var did_brake: bool
  215. var did_reverse: bool
  216. func start_query():
  217. did_steer = false
  218. did_steer_left = false
  219. did_steer_right = false
  220. did_accelerate = false
  221. did_reverse = false
  222. did_brake = false
  223. func turn_left():
  224. did_steer_left = true
  225. did_steer = true
  226. func turn_right():
  227. did_steer_right = true
  228. did_steer = true
  229. func accelerate():
  230. did_accelerate = true
  231. func brake():
  232. did_brake = true
  233. func reverse():
  234. did_reverse = true