195 lines
6.1 KiB
GDScript3
195 lines
6.1 KiB
GDScript3
|
|
extends RigidBody3D
|
||
|
|
|
||
|
|
@export var joy_device_id: int = -1
|
||
|
|
|
||
|
|
@export var pitch_axis: int = 1
|
||
|
|
@export var pitch_invert: bool = true
|
||
|
|
@export var pitch_device_id: int = -1
|
||
|
|
@export var roll_axis: int = 0
|
||
|
|
@export var roll_invert: bool = false
|
||
|
|
@export var roll_device_id: int = -1
|
||
|
|
@export var yaw_axis: int = 2
|
||
|
|
@export var yaw_invert: bool = false
|
||
|
|
@export var yaw_device_id: int = -1
|
||
|
|
@export var throttle_axis: int = 3
|
||
|
|
@export var throttle_invert: bool = true
|
||
|
|
@export var throttle_signed: bool = true
|
||
|
|
@export var throttle_device_id: int = -1
|
||
|
|
@export var strafe_axis: int = 4
|
||
|
|
@export var strafe_invert: bool = false
|
||
|
|
@export var strafe_device_id: int = -1
|
||
|
|
@export var lift_axis: int = 5
|
||
|
|
@export var lift_invert: bool = false
|
||
|
|
@export var lift_device_id: int = -1
|
||
|
|
|
||
|
|
@export var stick_deadzone: float = 0.08
|
||
|
|
@export var throttle_deadzone: float = 0.02
|
||
|
|
|
||
|
|
@export var max_thrust: float = 7500.0
|
||
|
|
@export var strafe_thrust: float = 3500.0
|
||
|
|
@export var lift_thrust: float = 3500.0
|
||
|
|
@export var torque_strength: float = 2000.0
|
||
|
|
|
||
|
|
@export var throttle_response: float = 3.0
|
||
|
|
@export var stick_response: float = 6.0
|
||
|
|
@export var stick_expo: float = 1.6
|
||
|
|
@export var max_speed: float = 180.0
|
||
|
|
@export var max_angular_speed: float = 2.6
|
||
|
|
|
||
|
|
@export var vector_line_path: NodePath = NodePath("DisplacementVector")
|
||
|
|
@export var vector_scale: float = 0.05
|
||
|
|
@export var max_vector_length: float = 20.0
|
||
|
|
|
||
|
|
var _device_id: int = -1
|
||
|
|
var _current_throttle: float = 0.0
|
||
|
|
var _vector_line: Node
|
||
|
|
var _axis_state := {
|
||
|
|
"roll": 0.0,
|
||
|
|
"pitch": 0.0,
|
||
|
|
"yaw": 0.0,
|
||
|
|
"throttle": 0.0,
|
||
|
|
"strafe": 0.0,
|
||
|
|
"lift": 0.0,
|
||
|
|
}
|
||
|
|
var _axis_smoothed := {
|
||
|
|
"roll": 0.0,
|
||
|
|
"pitch": 0.0,
|
||
|
|
"yaw": 0.0,
|
||
|
|
"strafe": 0.0,
|
||
|
|
"lift": 0.0,
|
||
|
|
}
|
||
|
|
|
||
|
|
func _ready() -> void:
|
||
|
|
_vector_line = get_node_or_null(vector_line_path)
|
||
|
|
_device_id = _resolve_joypad()
|
||
|
|
if _device_id == -1:
|
||
|
|
push_warning("No HOTAS detected. Connect the X56 or set joy_device_id.")
|
||
|
|
|
||
|
|
func _physics_process(delta: float) -> void:
|
||
|
|
_device_id = _resolve_joypad()
|
||
|
|
if _device_id == -1:
|
||
|
|
_update_vector_line()
|
||
|
|
return
|
||
|
|
|
||
|
|
var roll = _shape_axis(_read_axis(_resolve_axis_device(roll_device_id), roll_axis, stick_deadzone, roll_invert))
|
||
|
|
var pitch = _shape_axis(_read_axis(_resolve_axis_device(pitch_device_id), pitch_axis, stick_deadzone, pitch_invert))
|
||
|
|
var yaw = _shape_axis(_read_axis(_resolve_axis_device(yaw_device_id), yaw_axis, stick_deadzone, yaw_invert))
|
||
|
|
var strafe = _shape_axis(_read_axis(_resolve_axis_device(strafe_device_id), strafe_axis, stick_deadzone, strafe_invert))
|
||
|
|
var lift = _shape_axis(_read_axis(_resolve_axis_device(lift_device_id), lift_axis, stick_deadzone, lift_invert))
|
||
|
|
var raw_throttle = _read_axis(_resolve_axis_device(throttle_device_id), throttle_axis, throttle_deadzone, throttle_invert)
|
||
|
|
|
||
|
|
var target_throttle: float
|
||
|
|
if throttle_signed:
|
||
|
|
target_throttle = clamp(raw_throttle, -1.0, 1.0)
|
||
|
|
else:
|
||
|
|
target_throttle = clamp((raw_throttle + 1.0) * 0.5, 0.0, 1.0)
|
||
|
|
|
||
|
|
_current_throttle = lerp(
|
||
|
|
_current_throttle,
|
||
|
|
target_throttle,
|
||
|
|
clamp(throttle_response * delta, 0.0, 1.0)
|
||
|
|
)
|
||
|
|
|
||
|
|
roll = _smooth_axis("roll", roll, delta)
|
||
|
|
pitch = _smooth_axis("pitch", pitch, delta)
|
||
|
|
yaw = _smooth_axis("yaw", yaw, delta)
|
||
|
|
strafe = _smooth_axis("strafe", strafe, delta)
|
||
|
|
lift = _smooth_axis("lift", lift, delta)
|
||
|
|
|
||
|
|
_axis_state["roll"] = roll
|
||
|
|
_axis_state["pitch"] = pitch
|
||
|
|
_axis_state["yaw"] = yaw
|
||
|
|
_axis_state["throttle"] = _current_throttle
|
||
|
|
_axis_state["strafe"] = strafe
|
||
|
|
_axis_state["lift"] = lift
|
||
|
|
|
||
|
|
var basis = global_transform.basis
|
||
|
|
var forward = -basis.z
|
||
|
|
var right = basis.x
|
||
|
|
var up = basis.y
|
||
|
|
|
||
|
|
var thrust_force = forward * (_current_throttle * max_thrust)
|
||
|
|
var strafe_force = right * (strafe * strafe_thrust)
|
||
|
|
var lift_force = up * (lift * lift_thrust)
|
||
|
|
apply_central_force(thrust_force + strafe_force + lift_force)
|
||
|
|
|
||
|
|
var local_angular = basis.inverse() * angular_velocity
|
||
|
|
var desired_angular = Vector3(pitch, yaw, -roll) * max_angular_speed
|
||
|
|
var torque_local = (desired_angular - local_angular) * torque_strength
|
||
|
|
apply_torque(basis * torque_local)
|
||
|
|
|
||
|
|
if max_speed > 0.0 and linear_velocity.length() > max_speed:
|
||
|
|
linear_velocity = linear_velocity.limit_length(max_speed)
|
||
|
|
if max_angular_speed > 0.0 and angular_velocity.length() > max_angular_speed:
|
||
|
|
angular_velocity = angular_velocity.limit_length(max_angular_speed)
|
||
|
|
|
||
|
|
_update_vector_line()
|
||
|
|
|
||
|
|
func get_axis_debug_text() -> String:
|
||
|
|
if _device_id == -1:
|
||
|
|
return "No HOTAS detected"
|
||
|
|
return "Roll: %.2f (d%d) Pitch: %.2f (d%d) Yaw: %.2f (d%d)\nThrottle: %.2f (d%d) Strafe: %.2f (d%d) Lift: %.2f (d%d)" % [
|
||
|
|
_axis_state["roll"],
|
||
|
|
_resolve_axis_device(roll_device_id),
|
||
|
|
_axis_state["pitch"],
|
||
|
|
_resolve_axis_device(pitch_device_id),
|
||
|
|
_axis_state["yaw"],
|
||
|
|
_resolve_axis_device(yaw_device_id),
|
||
|
|
_axis_state["throttle"],
|
||
|
|
_resolve_axis_device(throttle_device_id),
|
||
|
|
_axis_state["strafe"],
|
||
|
|
_resolve_axis_device(strafe_device_id),
|
||
|
|
_axis_state["lift"],
|
||
|
|
_resolve_axis_device(lift_device_id),
|
||
|
|
]
|
||
|
|
|
||
|
|
func get_joypad_id() -> int:
|
||
|
|
return _device_id
|
||
|
|
|
||
|
|
func _resolve_joypad() -> int:
|
||
|
|
if joy_device_id >= 0:
|
||
|
|
return joy_device_id
|
||
|
|
var pads = Input.get_connected_joypads()
|
||
|
|
if pads.is_empty():
|
||
|
|
return -1
|
||
|
|
return pads[0]
|
||
|
|
|
||
|
|
func _resolve_axis_device(axis_device_id: int) -> int:
|
||
|
|
if axis_device_id >= 0:
|
||
|
|
return axis_device_id
|
||
|
|
return _device_id
|
||
|
|
|
||
|
|
func _read_axis(device_id: int, axis: int, deadzone: float, invert: bool) -> float:
|
||
|
|
if axis < 0 or device_id < 0:
|
||
|
|
return 0.0
|
||
|
|
var value = Input.get_joy_axis(device_id, axis)
|
||
|
|
if invert:
|
||
|
|
value = -value
|
||
|
|
var magnitude = abs(value)
|
||
|
|
if magnitude <= deadzone:
|
||
|
|
return 0.0
|
||
|
|
var scaled = (magnitude - deadzone) / (1.0 - deadzone)
|
||
|
|
return scaled * sign(value)
|
||
|
|
|
||
|
|
func _shape_axis(value: float) -> float:
|
||
|
|
if stick_expo <= 1.0:
|
||
|
|
return value
|
||
|
|
return sign(value) * pow(abs(value), stick_expo)
|
||
|
|
|
||
|
|
func _smooth_axis(name: String, value: float, delta: float) -> float:
|
||
|
|
if stick_response <= 0.0:
|
||
|
|
_axis_smoothed[name] = value
|
||
|
|
return value
|
||
|
|
var t = clamp(stick_response * delta, 0.0, 1.0)
|
||
|
|
_axis_smoothed[name] = lerp(_axis_smoothed[name], value, t)
|
||
|
|
return _axis_smoothed[name]
|
||
|
|
|
||
|
|
func _update_vector_line() -> void:
|
||
|
|
if _vector_line == null:
|
||
|
|
return
|
||
|
|
if not _vector_line.has_method("set_vector"):
|
||
|
|
return
|
||
|
|
var local_velocity = global_transform.basis.inverse() * linear_velocity
|
||
|
|
var clamped = local_velocity.limit_length(max_vector_length)
|
||
|
|
_vector_line.set_vector(clamped * vector_scale)
|