class_name Boat extends FloatingBody ## All force values are per-kilogram (they get multiplied by mass), so the ## boat handles the same if you change its mass later. @export var engine_power := 12.0 # forward thrust, m/s² at full throttle @export var reverse_ratio := 0.4 # reverse is weaker, like a real prop @export var throttle_response := 1.5 # how fast the engine spools up/down @export var rudder_strength := 2.5 # turning torque at speed @export var keel_grip := 3.0 # resistance to sliding sideways var desired_throttle := 0.0 var throttle := 0.0 func _physics_process(delta: float) -> void: super(delta) if Input.is_action_pressed("throttle_increase"): desired_throttle = move_toward(desired_throttle, 1, 0.005) elif Input.is_action_pressed("throttle_decrease"): desired_throttle = move_toward(desired_throttle, -1, 0.006) elif Input.is_action_pressed("throttle_stop"): desired_throttle = 0.0 throttle = move_toward(throttle, desired_throttle, throttle_response * delta) if submerged_ratio <= 0.0: return # airborne: no thrust, no rudder, no keel # boat's forward direction, flattened onto the water plane var forward := -global_basis.z forward.y = 0.0 forward = forward.normalized() # --- engine --- var power := engine_power * (reverse_ratio if throttle < 0.0 else 1.0) apply_central_force(forward * throttle * power * mass * submerged_ratio) # --- rudder: only bites when water flows past it --- var steer_input := Input.get_axis("rudder_right", "rudder_left") var forward_speed := linear_velocity.dot(forward) var rudder_bite := clampf(forward_speed / 3.0, -1.0, 1.0) apply_torque(Vector3.UP * steer_input * rudder_strength * rudder_bite * mass * submerged_ratio) # --- keel: kill sideways sliding --- var right := global_basis.x right.y = 0.0 right = right.normalized() var lateral_speed := linear_velocity.dot(right) apply_central_force(-right * lateral_speed * keel_grip * mass * submerged_ratio)