123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182 |
- class_name Walker
- extends CharacterBody3D
- signal focus_required(me: Node3D)
- signal got_in
- signal got_out
- ## How fast the player moves in meters per second.
- @export var speed = 14
- ## Convert an axis from [-1, -1] to rad
- @export var turn_to_rad: float = 0.020
- ## The downward acceleration when in the air, in meters per second squared.
- @export var fall_acceleration = 75
- ## Vertical impulse applied to the character upon jumping in meters per second.
- @export var jump_impulse = 20
- @export_group("Seat", "seat_")
- @export var seat_min_dist: float = 0.0005
- @export var seat_access_speed: float = 2.0
- @export var seat_rotation_duration: float = 1.0
- var target_velocity := Vector3.ZERO
- var target_character_direction := Vector3.ZERO # From command
- var _vehicle: Node3D = null
- var _seat: Node3D = null
- @onready var _vehicle_range: RayCast3D = $VehicleRange
- func _ready() -> void:
- focus_required.emit(self)
- func trigger_jump() -> void:
- if is_on_floor():
- target_velocity.y = jump_impulse
- func trigger_direction(dir: Vector2) -> void:
- target_character_direction = Vector3(dir.x, 0.0, -dir.y)
- ## Return true if inside a vehicle
- func is_onboard() -> bool:
- return _vehicle != null
- func _physics_process(delta: float) -> void:
- if is_onboard():
- _get_on_driver_seat()
- else:
- _move_with_feet(delta)
- func _move_with_feet(delta: float):
- # Walk according to the camera angle
- var camera_basis: Basis = get_viewport().get_camera_3d().get_camera_transform().basis
- var target_world_direction: Vector3 = camera_basis * target_character_direction
- target_world_direction.y = 0.0
- var target_walk_velocity = target_world_direction.normalized() * speed * target_character_direction.length()
- target_velocity.x = target_walk_velocity.x
- target_velocity.z = target_walk_velocity.z
- # Face forward
- _look_forward(target_velocity)
- # Gravity
- if not is_on_floor():
- target_velocity.y = target_velocity.y - (fall_acceleration * delta)
- # Moving the Character
- velocity = target_velocity
- move_and_slide()
- func _get_on_driver_seat() -> void:
- if _seat == null :
- return
- if position.distance_squared_to(_seat.position) < seat_min_dist:
- return
- var rotation_tween: Tween = create_tween()
- rotation_tween.tween_property(self, "quaternion", _seat.quaternion, seat_rotation_duration)
- var local_velocity = (_seat.position - position).normalized() * seat_access_speed
- velocity = get_parent().get_transform().basis * local_velocity
- move_and_slide()
- func _on_dir_changed(dir: Vector2) -> void:
- if is_onboard():
- return
- trigger_direction(dir)
- func _on_main_action(pressed: bool) -> void:
- if is_onboard():
- return
- if pressed:
- trigger_jump()
- func _on_get_in_action(commander: LocalInput) -> void:
- if is_onboard():
- _get_out_vehicle()
- else:
- _get_in_vehicle(commander)
- ## Seek the first vehicle in front of the player
- ## and get in to it
- ## and take the wheel !
- func _get_in_vehicle(commander: LocalInput) -> void:
- var closest_vehicle: Node3D = _get_closest_vehicle()
- if closest_vehicle == null:
- return # No vehicle to get inside
- _vehicle = closest_vehicle
- reparent(_vehicle)
- add_collision_exception_with(_vehicle)
- _vehicle.drive_with(commander)
- _seat = _find_seat_on(_vehicle)
- got_in.emit()
- ## Get out of the current vehicle
- func _get_out_vehicle() -> void:
- _vehicle.get_out()
- remove_collision_exception_with(_vehicle)
- reparent(_vehicle.get_parent())
- _vehicle = null
- _seat = null
- _get_head_up()
- got_out.emit()
- ## Make the player stand up
- func _get_head_up():
- set_rotation(Vector3(0.0, rotation.y, 0.0))
- ## Make the player look forward
- func _look_forward(forward: Vector3) -> void:
- var horizontal_forward: Vector3 = forward.slide(Vector3.UP)
- if horizontal_forward.is_zero_approx():
- return
- else:
- look_at(position + horizontal_forward)
- ## Return closest vehicle within reach
- ## or null if there are none
- func _get_closest_vehicle() -> Node3D:
- _vehicle_range.force_raycast_update()
- var object_within_range: Object = _vehicle_range.get_collider()
- if object_within_range is Node3D:
- var node_within_range: Node3D = object_within_range as Node3D
- if node_within_range.is_in_group("vehicle"):
- print("Get in ", node_within_range)
- return node_within_range
- print("No vehicle found")
- return null
- ## Have a seat on the driven vehicle if a seat
- ## is available
- func _find_seat_on(vehicule: Node3D) -> Node3D:
- if vehicule.has_method("get_free_seat") :
- return vehicule.get_free_seat()
- return null
|