walker.gd 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. class_name Walker
  2. extends CharacterBody3D
  3. signal focus_required(me: Node3D)
  4. signal got_in
  5. signal got_out
  6. ## How fast the player moves in meters per second.
  7. @export var speed = 14
  8. ## Convert an axis from [-1, -1] to rad
  9. @export var turn_to_rad: float = 0.020
  10. ## The downward acceleration when in the air, in meters per second squared.
  11. @export var fall_acceleration = 75
  12. ## Vertical impulse applied to the character upon jumping in meters per second.
  13. @export var jump_impulse = 20
  14. @export_group("Seat", "seat_")
  15. @export var seat_min_dist: float = 0.0005
  16. @export var seat_access_speed: float = 2.0
  17. @export var seat_rotation_duration: float = 1.0
  18. var target_velocity := Vector3.ZERO
  19. var target_rotation: float = 0.0
  20. var _vehicle: Node3D = null
  21. var _seat: Node3D = null
  22. @onready var _vehicle_range: RayCast3D = $VehicleRange
  23. func _ready() -> void:
  24. focus_required.emit(self)
  25. func trigger_jump() -> void:
  26. if is_on_floor():
  27. target_velocity.y = jump_impulse
  28. func trigger_direction(dir: Vector2) -> void:
  29. target_rotation = -dir.x * turn_to_rad
  30. var ground_velocity: Vector2 = Vector2.UP.rotated(-global_rotation.y) * dir.y * speed
  31. target_velocity.x = ground_velocity.x
  32. target_velocity.z = ground_velocity.y
  33. ## Return true if inside a vehicle
  34. func is_onboard() -> bool:
  35. return _vehicle != null
  36. func _physics_process(delta: float) -> void:
  37. if is_onboard():
  38. _get_on_driver_seat()
  39. else:
  40. _move_with_feet(delta)
  41. func _move_with_feet(delta: float):
  42. rotate_y(target_rotation)
  43. # Gravity
  44. if not is_on_floor():
  45. target_velocity.y = target_velocity.y - (fall_acceleration * delta)
  46. # Moving the Character
  47. velocity = target_velocity
  48. move_and_slide()
  49. func _get_on_driver_seat() -> void:
  50. if _seat == null :
  51. return
  52. if position.distance_squared_to(_seat.position) < seat_min_dist:
  53. return
  54. var rotation_tween: Tween = create_tween()
  55. rotation_tween.tween_property(self, "quaternion", _seat.quaternion, seat_rotation_duration)
  56. var local_velocity = (_seat.position - position).normalized() * seat_access_speed
  57. velocity = get_parent().get_transform().basis * local_velocity
  58. move_and_slide()
  59. func _on_dir_changed(dir: Vector2) -> void:
  60. trigger_direction(dir)
  61. func _on_main_action(pressed: bool) -> void:
  62. if pressed:
  63. trigger_jump()
  64. func _on_get_in_action(commander: LocalInput) -> void:
  65. if is_onboard():
  66. _get_out_vehicle()
  67. else:
  68. _get_in_vehicle(commander)
  69. ## Seek the first vehicle in front of the player
  70. ## and get in to it
  71. ## and take the wheel !
  72. func _get_in_vehicle(commander: LocalInput) -> void:
  73. var closest_vehicle: Node3D = _get_closest_vehicle()
  74. if closest_vehicle == null:
  75. return # No vehicle to get inside
  76. _vehicle = closest_vehicle
  77. reparent(_vehicle)
  78. add_collision_exception_with(_vehicle)
  79. _vehicle.drive_with(commander)
  80. _seat = _find_seat_on(_vehicle)
  81. got_in.emit()
  82. ## Get out of the current vehicle
  83. func _get_out_vehicle() -> void:
  84. _vehicle.get_out()
  85. remove_collision_exception_with(_vehicle)
  86. reparent(_vehicle.get_parent())
  87. _vehicle = null
  88. _seat = null
  89. _get_head_up()
  90. got_out.emit()
  91. ## Make the player stand up
  92. func _get_head_up():
  93. set_rotation(Vector3(0.0, rotation.y, 0.0))
  94. ## Return closest vehicle within reach
  95. ## or null if there are none
  96. func _get_closest_vehicle() -> Node3D:
  97. _vehicle_range.force_raycast_update()
  98. var object_within_range: Object = _vehicle_range.get_collider()
  99. if object_within_range is Node3D:
  100. var node_within_range: Node3D = object_within_range as Node3D
  101. if node_within_range.is_in_group("vehicle"):
  102. print("Get in ", node_within_range)
  103. return node_within_range
  104. print("No vehicle found")
  105. return null
  106. ## Have a seat on the driven vehicle if a seat
  107. ## is available
  108. func _find_seat_on(vehicule: Node3D) -> Node3D:
  109. if vehicule.has_method("get_free_seat") :
  110. return vehicule.get_free_seat()
  111. return null