Particle FX fix
particles on kestrel are working, landing gear and hatch animations are not
This commit is contained in:
+175
-106
@@ -10,11 +10,12 @@ extends CharacterBody3D
|
||||
@onready var pause_menu: Control = get_node_or_null("/root/Node3D/HUD/PauseMenu")
|
||||
@onready var body_collision: CollisionShape3D = get_node_or_null("CollisionShape3D")
|
||||
@onready var flight_label: Label = get_node_or_null("/root/Node3D/HUD/FlightLabel")
|
||||
@onready var kestrel: Node3D = get_node_or_null("Kestrel")
|
||||
@onready var kestrel: Node3D = get_node_or_null("kestrel_body")
|
||||
|
||||
var player_inside: bool = false
|
||||
var player_ref: CharacterBody3D = null
|
||||
var using_third_person: bool = false
|
||||
var f_was_down: bool = false
|
||||
|
||||
var mass: float = 6500.0
|
||||
var thrust_force: float = 180000.0
|
||||
@@ -63,12 +64,12 @@ var _hatch_crew_open: bool = false
|
||||
var _hatch_dock_open: bool = false
|
||||
var _ladder_out: bool = false
|
||||
var _cabin_dim: bool = false
|
||||
var _thrust_input: float = 0.0
|
||||
var _instruments_on: bool = false
|
||||
var _v_was: bool = false
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
GameplayInput.command_requested.connect(_handle_vehicle_command)
|
||||
GameplayInput.transient_input_cleared.connect(_clear_vehicle_input)
|
||||
_ensure_actions()
|
||||
if interaction_area:
|
||||
interaction_area.monitoring = true
|
||||
interaction_area.monitorable = true
|
||||
@@ -92,14 +93,31 @@ func _ready() -> void:
|
||||
call_deferred("_update_crust_exception")
|
||||
|
||||
|
||||
var _hull_driver: Node = null
|
||||
|
||||
|
||||
func _bind_kestrel() -> void:
|
||||
if kestrel == null:
|
||||
kestrel = get_node_or_null("Kestrel")
|
||||
print("Kestrel hull=", kestrel, " driver=", kestrel.get_script() if kestrel else null)
|
||||
for name in ["kestrel_body", "Kestrel", "KestrelBody"]:
|
||||
kestrel = get_node_or_null(name) as Node3D
|
||||
if kestrel:
|
||||
break
|
||||
if kestrel == null:
|
||||
for c in find_children("*", "Node", true, false):
|
||||
if "abort_burn" in c and "gear_deploy" in c:
|
||||
kestrel = c as Node3D
|
||||
break
|
||||
_hull_driver = kestrel
|
||||
if kestrel and not ("abort_burn" in kestrel):
|
||||
for c in kestrel.find_children("*", "Node", true, false):
|
||||
if "abort_burn" in c and "gear_deploy" in c:
|
||||
_hull_driver = c
|
||||
break
|
||||
print("Kestrel hull=", kestrel, " driver=", _hull_driver)
|
||||
|
||||
|
||||
func _hull() -> Node:
|
||||
return kestrel if kestrel else null
|
||||
return _hull_driver if _hull_driver else kestrel
|
||||
|
||||
|
||||
func _set_hull(prop: String, value: Variant) -> void:
|
||||
@@ -108,6 +126,16 @@ func _set_hull(prop: String, value: Variant) -> void:
|
||||
h.set(prop, value)
|
||||
|
||||
|
||||
func _drive_hull(thrusting: bool, pitch: float, yaw: float, roll: float) -> void:
|
||||
_set_hull("abort_burn", thrusting)
|
||||
_set_hull("att_pitch", pitch)
|
||||
_set_hull("att_yaw", yaw)
|
||||
_set_hull("att_roll", roll)
|
||||
var h := _hull()
|
||||
if h and h.has_method("drive"):
|
||||
h.drive(thrusting, pitch, yaw, roll)
|
||||
|
||||
|
||||
func _moon() -> Node3D:
|
||||
return get_node_or_null("/root/Node3D/SolarSystem/Moon") as Node3D
|
||||
|
||||
@@ -193,7 +221,7 @@ func _gravity_accel() -> Vector3:
|
||||
|
||||
func _update_telemetry() -> void:
|
||||
telem_speed = velocity.length()
|
||||
telem_thrust = _thrust_input > 0.0
|
||||
telem_thrust = Input.is_key_pressed(KEY_SPACE)
|
||||
var earth := _earth()
|
||||
if earth:
|
||||
telem_earth_rng = maxf(0.0, global_position.distance_to(earth.global_position) - EARTH_RADIUS)
|
||||
@@ -262,7 +290,7 @@ func _on_body_entered(body: Node3D) -> void:
|
||||
if body.is_in_group("player"):
|
||||
player_ref = body
|
||||
if interact_prompt and not player_inside:
|
||||
interact_prompt.text = "[%s] Enter" % GameplayInput.binding_label(&"interact")
|
||||
interact_prompt.text = "Press F to Enter"
|
||||
interact_prompt.visible = true
|
||||
|
||||
|
||||
@@ -273,61 +301,104 @@ func _on_body_exited(body: Node3D) -> void:
|
||||
interact_prompt.visible = false
|
||||
|
||||
|
||||
## Handles semantic vehicle commands; proximity permits entry only on foot.
|
||||
func _handle_vehicle_command(action: StringName, command_context: int) -> void:
|
||||
if command_context != GameplayInput.context:
|
||||
return
|
||||
if action == &"interact":
|
||||
if player_inside:
|
||||
exit_capsule()
|
||||
elif player_ref and interaction_area.overlaps_body(player_ref) and GameplayInput.context == GameplayInput.Context.ON_FOOT:
|
||||
enter_capsule()
|
||||
return
|
||||
if not player_inside or GameplayInput.context != GameplayInput.Context.VEHICLE:
|
||||
return
|
||||
match action:
|
||||
&"toggle_view":
|
||||
toggle_camera()
|
||||
&"vehicle_toggle_gear":
|
||||
_gear_down = not _gear_down
|
||||
_set_hull("gear_deploy", 1.0 if _gear_down else 0.0)
|
||||
&"vehicle_toggle_crew_hatch":
|
||||
_hatch_crew_open = not _hatch_crew_open
|
||||
_set_hull("hatch_crew_open", 1.0 if _hatch_crew_open else 0.0)
|
||||
&"vehicle_toggle_dock_hatch":
|
||||
_hatch_dock_open = not _hatch_dock_open
|
||||
_set_hull("hatch_dock_open", 1.0 if _hatch_dock_open else 0.0)
|
||||
&"capsule_toggle_ladder":
|
||||
_ladder_out = not _ladder_out
|
||||
_set_hull("hatch_ladder_deploy", 1.0 if _ladder_out else 0.0)
|
||||
&"vehicle_activate_instruments":
|
||||
_set_hull("instruments_demo", 1.0)
|
||||
&"vehicle_toggle_cabin_lights":
|
||||
_cabin_dim = not _cabin_dim
|
||||
_set_hull("cabin_dim", _cabin_dim)
|
||||
|
||||
|
||||
## Clears held cockpit look and visual thrust on menus, handoffs, or focus loss.
|
||||
func _clear_vehicle_input() -> void:
|
||||
free_look = false
|
||||
cockpit_yaw = 0.0
|
||||
cockpit_pitch = 0.0
|
||||
_thrust_input = 0.0
|
||||
if player_inside:
|
||||
_set_hull("abort_burn", false)
|
||||
_set_hull("att_pitch", 0.0)
|
||||
_set_hull("att_yaw", 0.0)
|
||||
_set_hull("att_roll", 0.0)
|
||||
|
||||
|
||||
## Updates active vehicle input/cameras while retaining the original flight timing.
|
||||
func _process(delta: float) -> void:
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
if not player_inside:
|
||||
if player_ref and interact_prompt:
|
||||
interact_prompt.text = "[%s] Enter" % GameplayInput.binding_label(&"interact")
|
||||
return
|
||||
if event.is_action_pressed("ui_cancel"):
|
||||
if pause_menu and pause_menu.has_method("open_pause") and player_ref:
|
||||
pause_menu.open_pause(player_ref)
|
||||
get_viewport().set_input_as_handled()
|
||||
return
|
||||
if _event_toggles(event, "capsule_gear", KEY_G):
|
||||
_gear_down = not _gear_down
|
||||
_set_hull("gear_deploy", 1.0 if _gear_down else 0.0)
|
||||
get_viewport().set_input_as_handled()
|
||||
elif _event_toggles(event, "capsule_hatch_crew", KEY_H):
|
||||
_hatch_crew_open = not _hatch_crew_open
|
||||
_set_hull("hatch_crew_open", 1.0 if _hatch_crew_open else 0.0)
|
||||
get_viewport().set_input_as_handled()
|
||||
elif _event_toggles(event, "capsule_hatch_dock", KEY_J):
|
||||
_hatch_dock_open = not _hatch_dock_open
|
||||
_set_hull("hatch_dock_open", 1.0 if _hatch_dock_open else 0.0)
|
||||
get_viewport().set_input_as_handled()
|
||||
elif _event_toggles(event, "capsule_ladder", KEY_L):
|
||||
_ladder_out = not _ladder_out
|
||||
_set_hull("hatch_ladder_deploy", 1.0 if _ladder_out else 0.0)
|
||||
get_viewport().set_input_as_handled()
|
||||
elif _event_toggles(event, "capsule_instruments", KEY_I):
|
||||
_instruments_on = not _instruments_on
|
||||
_set_hull("instruments_demo", 1.0 if _instruments_on else 0.35)
|
||||
get_viewport().set_input_as_handled()
|
||||
elif _event_toggles(event, "capsule_cabin_light", KEY_K):
|
||||
_cabin_dim = not _cabin_dim
|
||||
_set_hull("cabin_dim", _cabin_dim)
|
||||
get_viewport().set_input_as_handled()
|
||||
|
||||
|
||||
func _ensure_actions() -> void:
|
||||
var binds := {
|
||||
"interact": KEY_F,
|
||||
"toggle_first_person": KEY_V,
|
||||
"capsule_gear": KEY_G,
|
||||
"capsule_hatch_crew": KEY_H,
|
||||
"capsule_hatch_dock": KEY_J,
|
||||
"capsule_ladder": KEY_L,
|
||||
"capsule_instruments": KEY_I,
|
||||
"capsule_cabin_light": KEY_K,
|
||||
}
|
||||
for action in binds.keys():
|
||||
if InputMap.has_action(action):
|
||||
continue
|
||||
InputMap.add_action(action)
|
||||
var ev := InputEventKey.new()
|
||||
ev.physical_keycode = binds[action]
|
||||
InputMap.action_add_event(action, ev)
|
||||
|
||||
|
||||
func _event_toggles(event: InputEvent, action: String, key: Key) -> bool:
|
||||
if InputMap.has_action(action) and event.is_action_pressed(action):
|
||||
return true
|
||||
if event is InputEventKey and event.pressed and not event.echo and event.physical_keycode == key:
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
func _act_pressed(action: String) -> bool:
|
||||
return InputMap.has_action(action) and Input.is_action_pressed(action)
|
||||
|
||||
|
||||
func _act_just(action: String) -> bool:
|
||||
return InputMap.has_action(action) and Input.is_action_just_pressed(action)
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
var interact_now := _act_just("interact") or _just_key(KEY_F)
|
||||
if not player_inside and player_ref and interact_now:
|
||||
f_was_down = true
|
||||
enter_capsule()
|
||||
return
|
||||
if not player_inside:
|
||||
f_was_down = Input.is_physical_key_pressed(KEY_F)
|
||||
_update_crust_exception()
|
||||
return
|
||||
_update_vehicle_look(delta)
|
||||
if interact_now and not f_was_down:
|
||||
f_was_down = true
|
||||
exit_capsule()
|
||||
return
|
||||
f_was_down = _act_pressed("interact") or Input.is_physical_key_pressed(KEY_F)
|
||||
if _act_just("toggle_first_person"):
|
||||
toggle_camera()
|
||||
elif not InputMap.has_action("toggle_first_person") and _just_key(KEY_V):
|
||||
toggle_camera()
|
||||
var was_free = free_look
|
||||
free_look = Input.is_mouse_button_pressed(MOUSE_BUTTON_RIGHT)
|
||||
if was_free and not free_look and not using_third_person:
|
||||
cockpit_yaw = 0.0
|
||||
cockpit_pitch = 0.0
|
||||
if Input.is_key_pressed(KEY_ALT):
|
||||
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
|
||||
else:
|
||||
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
||||
handle_flight(delta)
|
||||
_update_telemetry()
|
||||
_update_flight_hud()
|
||||
@@ -341,38 +412,30 @@ func _process(delta: float) -> void:
|
||||
capsule_camera.make_current()
|
||||
|
||||
|
||||
## Updates cockpit/orbit look without letting menu input reach the vehicle camera.
|
||||
func _update_vehicle_look(delta: float) -> void:
|
||||
var cursor_released := GameplayInput.is_held(&"vehicle_release_cursor")
|
||||
if GameplayInput.gameplay_enabled():
|
||||
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE if cursor_released else Input.MOUSE_MODE_CAPTURED
|
||||
var previous_freelook := free_look
|
||||
free_look = GameplayInput.is_held(&"vehicle_freelook")
|
||||
if previous_freelook and not free_look and not using_third_person:
|
||||
cockpit_yaw = 0.0
|
||||
cockpit_pitch = 0.0
|
||||
var mouse_displacement := GameplayInput.consume_mouse_displacement()
|
||||
if cursor_released:
|
||||
func _just_key(key: Key) -> bool:
|
||||
var down := Input.is_physical_key_pressed(key)
|
||||
if key == KEY_V:
|
||||
var edge := down and not _v_was
|
||||
_v_was = down
|
||||
return edge
|
||||
return false
|
||||
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
if not player_inside:
|
||||
return
|
||||
var mouse_turn := mouse_displacement * look_sensitivity
|
||||
var controller_turn := GameplayInput.read_controller_look(delta)
|
||||
if using_third_person:
|
||||
_apply_vehicle_look(mouse_turn + controller_turn)
|
||||
else:
|
||||
_apply_vehicle_look((mouse_turn if free_look else Vector2.ZERO) + controller_turn)
|
||||
|
||||
|
||||
## Applies angular displacement in radians while preserving existing camera limits.
|
||||
func _apply_vehicle_look(look_delta: Vector2) -> void:
|
||||
if using_third_person:
|
||||
orbit_yaw -= look_delta.x
|
||||
orbit_pitch += look_delta.y
|
||||
orbit_pitch = clampf(orbit_pitch, orbit_pitch_min, orbit_pitch_max)
|
||||
else:
|
||||
cockpit_yaw -= look_delta.x
|
||||
cockpit_pitch -= look_delta.y
|
||||
cockpit_yaw = clampf(cockpit_yaw, -cockpit_look_limit_yaw, cockpit_look_limit_yaw)
|
||||
cockpit_pitch = clampf(cockpit_pitch, -cockpit_look_limit_down, cockpit_look_limit_up)
|
||||
if Input.is_key_pressed(KEY_ALT):
|
||||
return
|
||||
if event is InputEventMouseMotion:
|
||||
if using_third_person:
|
||||
orbit_yaw -= event.relative.x * look_sensitivity
|
||||
orbit_pitch += event.relative.y * look_sensitivity
|
||||
orbit_pitch = clampf(orbit_pitch, orbit_pitch_min, orbit_pitch_max)
|
||||
elif free_look:
|
||||
cockpit_yaw -= event.relative.x * look_sensitivity
|
||||
cockpit_pitch -= event.relative.y * look_sensitivity
|
||||
cockpit_yaw = clamp(cockpit_yaw, -cockpit_look_limit_yaw, cockpit_look_limit_yaw)
|
||||
cockpit_pitch = clamp(cockpit_pitch, -cockpit_look_limit_down, cockpit_look_limit_up)
|
||||
|
||||
|
||||
func enter_capsule() -> void:
|
||||
@@ -402,6 +465,7 @@ func enter_capsule() -> void:
|
||||
orbit_yaw = 0.0
|
||||
orbit_pitch = 0.4
|
||||
using_third_person = false
|
||||
f_was_down = true
|
||||
free_look = false
|
||||
if camera_pivot:
|
||||
camera_pivot.top_level = false
|
||||
@@ -419,7 +483,6 @@ func enter_capsule() -> void:
|
||||
if flight_label:
|
||||
flight_label.visible = true
|
||||
_update_crust_exception()
|
||||
GameplayInput.set_context(GameplayInput.Context.VEHICLE)
|
||||
|
||||
|
||||
func exit_capsule() -> void:
|
||||
@@ -429,6 +492,7 @@ func exit_capsule() -> void:
|
||||
player_inside = false
|
||||
velocity = Vector3.ZERO
|
||||
free_look = false
|
||||
f_was_down = false
|
||||
using_third_person = false
|
||||
_set_hull("abort_burn", false)
|
||||
_set_hull("rcs_direction", 0)
|
||||
@@ -469,7 +533,6 @@ func exit_capsule() -> void:
|
||||
FloatingOrigin.set_focus(exiting_player)
|
||||
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
||||
player_ref = null
|
||||
GameplayInput.set_context(GameplayInput.Context.ON_FOOT)
|
||||
|
||||
|
||||
func toggle_camera() -> void:
|
||||
@@ -535,25 +598,31 @@ func update_third_person_camera() -> void:
|
||||
third_person_camera.global_basis = cam_basis
|
||||
|
||||
|
||||
## Reads signed flight intent while preserving the existing flight equations/timing.
|
||||
func handle_flight(delta: float) -> void:
|
||||
_update_crust_exception()
|
||||
var input_pitch := GameplayInput.read_axis(&"vehicle_pitch_up", &"vehicle_pitch_down")
|
||||
var input_roll := GameplayInput.read_axis(&"vehicle_roll_left", &"vehicle_roll_right")
|
||||
var input_yaw := GameplayInput.read_axis(&"vehicle_yaw_right", &"vehicle_yaw_left")
|
||||
var input_pitch := 0.0
|
||||
var input_roll := 0.0
|
||||
var input_yaw := 0.0
|
||||
if Input.is_key_pressed(KEY_W):
|
||||
input_pitch -= 1.0
|
||||
if Input.is_key_pressed(KEY_S):
|
||||
input_pitch += 1.0
|
||||
if Input.is_key_pressed(KEY_A):
|
||||
input_yaw += 1.0
|
||||
if Input.is_key_pressed(KEY_D):
|
||||
input_yaw -= 1.0
|
||||
if Input.is_key_pressed(KEY_Q):
|
||||
input_roll -= 1.0
|
||||
if Input.is_key_pressed(KEY_E):
|
||||
input_roll += 1.0
|
||||
rotate_object_local(Vector3.RIGHT, input_pitch * rotation_speed * delta)
|
||||
rotate_object_local(Vector3.FORWARD, -input_yaw * rotation_speed * delta)
|
||||
rotate_object_local(Vector3.UP, input_roll * rotation_speed * delta)
|
||||
_thrust_input = GameplayInput.read_strength(&"vehicle_thrust")
|
||||
var thrusting := _thrust_input > 0.0
|
||||
_set_hull("abort_burn", thrusting)
|
||||
_set_hull("att_pitch", input_pitch)
|
||||
_set_hull("att_yaw", input_yaw)
|
||||
_set_hull("att_roll", input_roll)
|
||||
_set_hull("rcs_direction", 0)
|
||||
var thrusting := Input.is_key_pressed(KEY_SPACE)
|
||||
_drive_hull(thrusting, input_pitch, input_yaw, input_roll)
|
||||
var acceleration: Vector3 = _gravity_accel()
|
||||
if thrusting:
|
||||
acceleration += global_transform.basis.y * (thrust_force / mass) * _thrust_input
|
||||
acceleration += global_transform.basis.y * (thrust_force / mass)
|
||||
velocity += acceleration * delta
|
||||
var near_surface := is_on_floor() or _crust_exception
|
||||
if not near_surface:
|
||||
|
||||
+2
-2
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user