class_name SeatedVehicle extends VehicleBody3D const CRASH_EFFECT: Resource = preload("res://effect/crash/crash.tscn") const MINIMAL_CRASH_SPEED: float = 1.0 # m2/s2 var _current_commander: LocalInput = null var _current_driver: Walker var _has_collided: bool = false @onready var _seat: Node3D = find_child("*Seat") @onready var _doors: Array = find_children("*Door", "Node3D") # Array[Node3D] func _init() -> void: body_shape_entered.connect(_on_body_shape_entered) func _ready() -> void: assert(_doors.all(func(door): return door is Node3D)) ## Signal a new driver func become_driven_by(driver: Walker) -> void: _current_driver = driver ## Make the vehicle responds to driver commands func drive_with(commander: LocalInput) -> void: commander.dir_changed.connect(_on_dir_changed) commander.main_action.connect(_on_main_action) commander.stop_action.connect(_on_stop_action) commander.analog_action.connect(_on_analog_action) _current_commander = commander func get_out() -> void: _current_commander.dir_changed.disconnect(_on_dir_changed) _current_commander.main_action.disconnect(_on_main_action) _current_commander.stop_action.disconnect(_on_stop_action) _current_commander.analog_action.disconnect(_on_analog_action) _current_commander = null _current_driver = null func _integrate_forces(state: PhysicsDirectBodyState3D) -> void: if state.get_contact_count() <= 0: return if _has_collided and linear_velocity.length_squared() > MINIMAL_CRASH_SPEED: _crash_on(state.get_contact_collider_position(0)) _has_collided = false func _on_body_shape_entered(_body_rid, body: Node, _body_shape_index, _local_shape_index) -> void: if body.is_in_group("walker"): return _has_collided = true func _crash_on(pos: Vector3) -> void: var crash_effect: CrashEffect = CRASH_EFFECT.instantiate() crash_effect.position = pos get_parent_node_3d().add_child(crash_effect) func get_free_seat() -> Node3D: return _seat ## Can be overridden to return a specific door func get_door() -> Node3D: return _doors[0] as Node3D func get_closest_door(from: Vector3) -> Node3D: var distance = func distance_lambda(door: Node3D) -> float: return (door.get_position() - from).length_squared() var closest = func closest_lambda(previous_closest: Node3D, maybe_closest: Node3D) -> Node3D: if distance.call(maybe_closest) < distance.call(previous_closest): return maybe_closest else: return previous_closest return _doors.reduce(closest) ## Return current walker who is driving the vehicle, null if none func get_current_driver() -> Walker: return _current_driver ## Need to be overridden to react to direction changed func _on_dir_changed(_dir: Vector2) -> void: pass ## Need to be overridden to react to main action func _on_main_action(_pressed: bool) -> void: pass ## Need to be overridden to react to stop action func _on_stop_action(_pressed: bool) -> void: pass ## Need to be overridden to react to analog actions func _on_analog_action(_side: int, _value: float) -> void: pass