Initial commit
This commit is contained in:
@@ -0,0 +1,548 @@
|
||||
extends CharacterBody3D
|
||||
## NAF Resolute CVT-07 — Roci-style torch + attitude.
|
||||
## This script on the CharacterBody3D. Hull child named "Resolute" wears resolute_driver.gd.
|
||||
## Sibling of SolarSystem. Walk-to-helm later; F enter is the demo stub.
|
||||
##
|
||||
## Throttle: Alt + mouse wheel → commanded G, 0..5. Cruise ~0.8 G.
|
||||
## Nose +Y. Drive plume follows throttle. RCS puffs on attitude input.
|
||||
## Plugs: pdc_aim_dir, radar_contacts, combat_ui — fill when Nebulous layer lands.
|
||||
|
||||
@onready var interaction_area: Area3D = get_node_or_null("InteractionArea")
|
||||
@onready var hull: Node3D = get_node_or_null("Resolute")
|
||||
@onready var third_person_camera: Camera3D = get_node_or_null("ThirdPersonCamera")
|
||||
@onready var interact_prompt: Label = get_node_or_null("/root/Node3D/HUD/InteractPrompt")
|
||||
@onready var pause_menu: Control = get_node_or_null("/root/Node3D/HUD/PauseMenu")
|
||||
@onready var flight_label: Label = get_node_or_null("/root/Node3D/HUD/FlightLabel")
|
||||
@onready var body_collision: CollisionShape3D = get_node_or_null("CollisionShape3D")
|
||||
|
||||
var player_inside: bool = false
|
||||
var player_ref: CharacterBody3D = null
|
||||
var using_third_person: bool = false
|
||||
var f_was_down: bool = false
|
||||
var _v_was: bool = false
|
||||
|
||||
var mass: float = 280000.0
|
||||
const G0: float = 9.81
|
||||
const G_MAX: float = 5.0
|
||||
const G_CRUISE: float = 0.80
|
||||
const G_STEP: float = 0.10
|
||||
|
||||
var g_cmd: float = 0.0
|
||||
var drive_armed: bool = true
|
||||
|
||||
var ang_vel: Vector3 = Vector3.ZERO
|
||||
@export var ang_accel: float = 0.48
|
||||
@export var ang_max: float = 0.95
|
||||
@export var ang_damp: float = 2.2
|
||||
|
||||
var surface_friction: float = 4.0
|
||||
|
||||
const MOON_RADIUS: float = 173700.0
|
||||
const MOON_G: float = 1.62
|
||||
const MOON_SOI: float = 400000.0
|
||||
const EARTH_RADIUS: float = 637100.0
|
||||
const EARTH_G: float = 9.81
|
||||
const EARTH_SOI: float = 20000000.0
|
||||
const CAM_FAR: float = 1000000.0
|
||||
const NEAR_SURFACE_MARGIN: float = 400.0
|
||||
|
||||
var free_look: bool = false
|
||||
var look_sensitivity: float = 0.003
|
||||
var orbit_yaw: float = 0.0
|
||||
var orbit_pitch: float = 0.35
|
||||
var orbit_distance: float = 48.0
|
||||
var orbit_pitch_min: float = -1.15
|
||||
var orbit_pitch_max: float = 1.15
|
||||
|
||||
var helm_camera: Camera3D = null
|
||||
|
||||
var _gear_down: bool = true
|
||||
var _rads_out: bool = true
|
||||
var _airlock_open: bool = false
|
||||
var _dock_open: bool = false
|
||||
var _cargo_open: bool = false
|
||||
var _deck_open: bool = false
|
||||
var _tubes_open: bool = false
|
||||
var _battle: bool = false
|
||||
var _chaff_t: float = 0.0
|
||||
|
||||
## Combat plugs — empty until radar / track file exists.
|
||||
var pdc_target: Node3D = null
|
||||
var radar_contacts: Array = []
|
||||
var combat_ui_open: bool = false
|
||||
|
||||
var telem_body: String = "—"
|
||||
var telem_alt: float = 0.0
|
||||
var telem_speed: float = 0.0
|
||||
var telem_vspeed: float = 0.0
|
||||
var telem_hspeed: float = 0.0
|
||||
var telem_vcirc: float = 0.0
|
||||
var telem_has_alt: bool = false
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
_ensure_actions()
|
||||
if hull == null or hull == self:
|
||||
hull = get_node_or_null("Resolute") as Node3D
|
||||
if hull == null or hull == self:
|
||||
hull = find_child("NAF_Resolute", true, false) as Node3D
|
||||
if hull == null or hull == self:
|
||||
hull = find_child("Resolute", true, false) as Node3D
|
||||
if interaction_area:
|
||||
interaction_area.monitoring = true
|
||||
interaction_area.monitorable = true
|
||||
interaction_area.body_entered.connect(_on_body_entered)
|
||||
interaction_area.body_exited.connect(_on_body_exited)
|
||||
helm_camera = _find_helm_cam()
|
||||
if helm_camera:
|
||||
helm_camera.near = 0.05
|
||||
helm_camera.far = CAM_FAR
|
||||
helm_camera.current = false
|
||||
if third_person_camera:
|
||||
third_person_camera.near = 0.2
|
||||
third_person_camera.far = CAM_FAR
|
||||
third_person_camera.current = false
|
||||
if flight_label:
|
||||
flight_label.visible = false
|
||||
_set_hull("gear_deploy", 1.0)
|
||||
_set_hull("radiators_deploy", 1.0)
|
||||
print("Resolute ready hull=", hull, " helm=", helm_camera)
|
||||
|
||||
|
||||
func _find_helm_cam() -> Camera3D:
|
||||
var root: Node = hull if hull else self
|
||||
var n := root.find_child("HelmCamera", true, false)
|
||||
if n is Camera3D:
|
||||
return n as Camera3D
|
||||
n = root.find_child("SeatCamera", true, false)
|
||||
if n is Camera3D:
|
||||
return n as Camera3D
|
||||
return get_node_or_null("CameraPivot/CapsuleCamera") as Camera3D
|
||||
|
||||
|
||||
func _set_hull(prop: String, value: Variant) -> void:
|
||||
if hull and prop in hull:
|
||||
hull.set(prop, value)
|
||||
|
||||
|
||||
func _moon() -> Node3D:
|
||||
return get_node_or_null("/root/Node3D/SolarSystem/Moon") as Node3D
|
||||
|
||||
|
||||
func _earth() -> Node3D:
|
||||
return get_node_or_null("/root/Node3D/SolarSystem/Earth") as Node3D
|
||||
|
||||
|
||||
func _active_gravity() -> Dictionary:
|
||||
var moon := _moon()
|
||||
if moon:
|
||||
var d_m: float = global_position.distance_to(moon.global_position)
|
||||
if d_m >= 1.0 and d_m <= MOON_SOI:
|
||||
var to_c: Vector3 = moon.global_position - global_position
|
||||
return {"name": "Luna", "center": moon.global_position, "radius": MOON_RADIUS, "g": MOON_G, "accel": to_c.normalized() * MOON_G, "dist": d_m}
|
||||
var earth := _earth()
|
||||
if earth:
|
||||
var d_e: float = global_position.distance_to(earth.global_position)
|
||||
if d_e >= 1.0 and d_e <= EARTH_SOI:
|
||||
var to_c2: Vector3 = earth.global_position - global_position
|
||||
return {"name": "Earth", "center": earth.global_position, "radius": EARTH_RADIUS, "g": EARTH_G, "accel": to_c2.normalized() * EARTH_G, "dist": d_e}
|
||||
return {"name": "—", "center": Vector3.ZERO, "radius": 0.0, "g": 0.0, "accel": Vector3.ZERO, "dist": 0.0}
|
||||
|
||||
|
||||
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 = "Press F to Board Resolute"
|
||||
interact_prompt.visible = true
|
||||
|
||||
|
||||
func _on_body_exited(body: Node3D) -> void:
|
||||
if body.is_in_group("player") and not player_inside:
|
||||
player_ref = null
|
||||
if interact_prompt:
|
||||
interact_prompt.visible = false
|
||||
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
if not player_inside:
|
||||
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 is InputEventMouseButton and Input.is_key_pressed(KEY_ALT):
|
||||
if event.button_index == MOUSE_BUTTON_WHEEL_UP and event.pressed:
|
||||
g_cmd = minf(G_MAX, g_cmd + G_STEP)
|
||||
get_viewport().set_input_as_handled()
|
||||
elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN and event.pressed:
|
||||
g_cmd = maxf(0.0, g_cmd - G_STEP)
|
||||
get_viewport().set_input_as_handled()
|
||||
if _tap(event, KEY_G):
|
||||
_gear_down = not _gear_down
|
||||
_set_hull("gear_deploy", 1.0 if _gear_down else 0.0)
|
||||
elif _tap(event, KEY_R):
|
||||
_rads_out = not _rads_out
|
||||
_set_hull("radiators_deploy", 1.0 if _rads_out else 0.0)
|
||||
elif _tap(event, KEY_H):
|
||||
_airlock_open = not _airlock_open
|
||||
_set_hull("hatch_airlock_open", 1.0 if _airlock_open else 0.0)
|
||||
elif _tap(event, KEY_J):
|
||||
_dock_open = not _dock_open
|
||||
_set_hull("hatch_dock_open", 1.0 if _dock_open else 0.0)
|
||||
elif _tap(event, KEY_U):
|
||||
_cargo_open = not _cargo_open
|
||||
_set_hull("hatch_cargo_open", 1.0 if _cargo_open else 0.0)
|
||||
elif _tap(event, KEY_M):
|
||||
_deck_open = not _deck_open
|
||||
_set_hull("hatch_deck_open", 1.0 if _deck_open else 0.0)
|
||||
elif _tap(event, KEY_O):
|
||||
_tubes_open = not _tubes_open
|
||||
_set_hull("torpedo_doors_open", 1.0 if _tubes_open else 0.0)
|
||||
elif _tap(event, KEY_B):
|
||||
_battle = not _battle
|
||||
_set_hull("battle_lights", _battle)
|
||||
elif _tap(event, KEY_X):
|
||||
_chaff_t = 0.9
|
||||
elif _tap(event, KEY_T):
|
||||
drive_armed = not drive_armed
|
||||
elif _tap(event, KEY_C):
|
||||
if g_cmd < 0.05:
|
||||
g_cmd = G_CRUISE
|
||||
else:
|
||||
g_cmd = 0.0
|
||||
|
||||
|
||||
func _ensure_actions() -> void:
|
||||
var binds := {
|
||||
"interact": KEY_F,
|
||||
"toggle_first_person": KEY_V,
|
||||
}
|
||||
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 _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 _tap(event: InputEvent, key: Key) -> bool:
|
||||
if event is InputEventKey and event.pressed and not event.echo and event.physical_keycode == key:
|
||||
get_viewport().set_input_as_handled()
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
var interact_now := _act_just("interact") or (Input.is_physical_key_pressed(KEY_F) and not f_was_down)
|
||||
if not player_inside and player_ref and interact_now:
|
||||
f_was_down = true
|
||||
enter_ship()
|
||||
return
|
||||
if not player_inside:
|
||||
f_was_down = Input.is_physical_key_pressed(KEY_F)
|
||||
return
|
||||
if interact_now and not f_was_down:
|
||||
f_was_down = true
|
||||
exit_ship()
|
||||
return
|
||||
f_was_down = _act_pressed("interact") or Input.is_physical_key_pressed(KEY_F)
|
||||
if _act_just("toggle_first_person") or _just_v():
|
||||
toggle_camera()
|
||||
free_look = Input.is_mouse_button_pressed(MOUSE_BUTTON_RIGHT)
|
||||
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()
|
||||
_push_combat_plugs()
|
||||
if using_third_person:
|
||||
update_third_person_camera()
|
||||
if third_person_camera and not third_person_camera.current:
|
||||
third_person_camera.make_current()
|
||||
elif helm_camera and not helm_camera.current:
|
||||
helm_camera.make_current()
|
||||
|
||||
|
||||
func _just_v() -> bool:
|
||||
var down := Input.is_physical_key_pressed(KEY_V)
|
||||
var edge := down and not _v_was
|
||||
_v_was = down
|
||||
return edge
|
||||
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
if not player_inside or not free_look or not using_third_person:
|
||||
return
|
||||
if event is InputEventMouseMotion:
|
||||
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)
|
||||
|
||||
|
||||
func handle_flight(delta: float) -> void:
|
||||
var pitch_in := 0.0
|
||||
var yaw_in := 0.0
|
||||
var roll_in := 0.0
|
||||
if Input.is_key_pressed(KEY_W):
|
||||
pitch_in -= 1.0
|
||||
if Input.is_key_pressed(KEY_S):
|
||||
pitch_in += 1.0
|
||||
if Input.is_key_pressed(KEY_A):
|
||||
yaw_in += 1.0
|
||||
if Input.is_key_pressed(KEY_D):
|
||||
yaw_in -= 1.0
|
||||
if Input.is_key_pressed(KEY_Q):
|
||||
roll_in -= 1.0
|
||||
if Input.is_key_pressed(KEY_E):
|
||||
roll_in += 1.0
|
||||
var torque := Vector3(pitch_in, roll_in, yaw_in) * ang_accel
|
||||
if torque.length_squared() < 0.0001:
|
||||
ang_vel = ang_vel.move_toward(Vector3.ZERO, ang_damp * delta)
|
||||
else:
|
||||
ang_vel += torque * delta
|
||||
if ang_vel.length() > ang_max:
|
||||
ang_vel = ang_vel.normalized() * ang_max
|
||||
if ang_vel.length_squared() > 0.000001:
|
||||
rotate_object_local(Vector3.RIGHT, ang_vel.x * delta)
|
||||
rotate_object_local(Vector3.UP, ang_vel.y * delta)
|
||||
rotate_object_local(Vector3.FORWARD, -ang_vel.z * delta)
|
||||
var thrusting := drive_armed and g_cmd > 0.04
|
||||
_set_hull("drive_on", thrusting)
|
||||
_set_hull("throttle", clampf(g_cmd / G_MAX, 0.0, 1.0) if thrusting else 0.0)
|
||||
_set_hull("rcs_attitude", pitch_in != 0.0 or yaw_in != 0.0 or roll_in != 0.0)
|
||||
_set_hull("pdc_fire", Input.is_physical_key_pressed(KEY_P))
|
||||
if _chaff_t > 0.0:
|
||||
_chaff_t -= delta
|
||||
_set_hull("chaff_fire", true)
|
||||
else:
|
||||
_set_hull("chaff_fire", false)
|
||||
var acceleration: Vector3 = _active_gravity()["accel"]
|
||||
if thrusting:
|
||||
acceleration += global_transform.basis.y * (g_cmd * G0)
|
||||
velocity += acceleration * delta
|
||||
var near_surface := is_on_floor()
|
||||
if not near_surface:
|
||||
var moon := _moon()
|
||||
if moon and global_position.distance_to(moon.global_position) < MOON_RADIUS + NEAR_SURFACE_MARGIN:
|
||||
near_surface = true
|
||||
var earth := _earth()
|
||||
if earth and global_position.distance_to(earth.global_position) < EARTH_RADIUS + NEAR_SURFACE_MARGIN:
|
||||
near_surface = true
|
||||
if near_surface:
|
||||
if body_collision:
|
||||
body_collision.disabled = false
|
||||
move_and_slide()
|
||||
if is_on_floor():
|
||||
velocity = velocity.move_toward(Vector3.ZERO, surface_friction * delta)
|
||||
else:
|
||||
if body_collision:
|
||||
body_collision.disabled = true
|
||||
global_position += velocity * delta
|
||||
PhysicsServer3D.body_set_state(get_rid(), PhysicsServer3D.BODY_STATE_TRANSFORM, global_transform)
|
||||
PhysicsServer3D.body_set_state(get_rid(), PhysicsServer3D.BODY_STATE_LINEAR_VELOCITY, velocity)
|
||||
|
||||
|
||||
func _update_telemetry() -> void:
|
||||
telem_speed = velocity.length()
|
||||
var body: Dictionary = _active_gravity()
|
||||
telem_body = str(body["name"])
|
||||
if telem_body == "—":
|
||||
telem_has_alt = false
|
||||
telem_alt = 0.0
|
||||
telem_vspeed = 0.0
|
||||
telem_hspeed = telem_speed
|
||||
telem_vcirc = 0.0
|
||||
return
|
||||
telem_has_alt = true
|
||||
var r: float = float(body["dist"])
|
||||
var rad: float = float(body["radius"])
|
||||
var g: float = float(body["g"])
|
||||
telem_alt = r - rad
|
||||
var radial: Vector3 = (global_position - body["center"]).normalized()
|
||||
telem_vspeed = velocity.dot(radial)
|
||||
telem_hspeed = (velocity - radial * telem_vspeed).length()
|
||||
telem_vcirc = sqrt(g * rad * rad / r) if r > 1.0 else 0.0
|
||||
|
||||
|
||||
func _update_flight_hud() -> void:
|
||||
if flight_label == null or not player_inside:
|
||||
return
|
||||
flight_label.visible = true
|
||||
var mode := "3P" if using_third_person else "1P"
|
||||
var vs_sign := "+" if telem_vspeed >= 0.0 else ""
|
||||
var alt_txt := "ALT %8.0f m" % telem_alt if telem_has_alt else "ALT —"
|
||||
flight_label.text = (
|
||||
"[%s] RESOLUTE | BODY %s\n" % [mode, telem_body]
|
||||
+ "G %4.2f / %.0f %s\n" % [g_cmd, G_MAX, "DRIVE" if drive_armed and g_cmd > 0.04 else "COAST"]
|
||||
+ alt_txt + "\n"
|
||||
+ "SPD %8.1f m/s\n" % telem_speed
|
||||
+ "VS %s%7.1f m/s\n" % [vs_sign, telem_vspeed]
|
||||
+ "H %8.1f m/s" % telem_hspeed
|
||||
)
|
||||
|
||||
|
||||
func _push_combat_plugs() -> void:
|
||||
if hull == null:
|
||||
return
|
||||
if "pdc_aim_dir" in hull:
|
||||
if pdc_target and is_instance_valid(pdc_target):
|
||||
hull.pdc_aim_dir = (pdc_target.global_position - global_position).normalized()
|
||||
else:
|
||||
hull.pdc_aim_dir = global_transform.basis.y
|
||||
if "radar_contacts" in hull:
|
||||
hull.radar_contacts = radar_contacts
|
||||
|
||||
|
||||
func set_pdc_target(node: Node3D) -> void:
|
||||
pdc_target = node
|
||||
|
||||
|
||||
func set_radar_contacts(list: Array) -> void:
|
||||
radar_contacts = list
|
||||
|
||||
|
||||
func enter_ship() -> void:
|
||||
if player_inside or player_ref == null:
|
||||
return
|
||||
player_inside = true
|
||||
if interact_prompt:
|
||||
interact_prompt.visible = false
|
||||
player_ref.reparent(self)
|
||||
var spawn := _player_spawn()
|
||||
if spawn:
|
||||
player_ref.global_transform = spawn.global_transform
|
||||
else:
|
||||
player_ref.position = Vector3(0, 1.2, 0)
|
||||
player_ref.rotation = Vector3.ZERO
|
||||
player_ref.set_physics_process(false)
|
||||
player_ref.set_process_input(false)
|
||||
player_ref.set_process_unhandled_input(false)
|
||||
if player_ref.has_method("set_in_vehicle"):
|
||||
player_ref.set_in_vehicle(true)
|
||||
var player_col = player_ref.get_node_or_null("CollisionShape3D")
|
||||
if player_col:
|
||||
player_col.disabled = true
|
||||
var player_cam = player_ref.get_node_or_null("CameraPivot/Camera3D")
|
||||
if player_cam:
|
||||
player_cam.current = false
|
||||
player_ref.visible = false
|
||||
using_third_person = false
|
||||
f_was_down = true
|
||||
if helm_camera:
|
||||
helm_camera.current = true
|
||||
helm_camera.make_current()
|
||||
FloatingOrigin.set_focus(self)
|
||||
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
||||
if flight_label:
|
||||
flight_label.visible = true
|
||||
|
||||
|
||||
func exit_ship() -> void:
|
||||
if not player_inside or player_ref == null:
|
||||
return
|
||||
var exiting: CharacterBody3D = player_ref
|
||||
player_inside = false
|
||||
g_cmd = 0.0
|
||||
drive_armed = true
|
||||
ang_vel = Vector3.ZERO
|
||||
_set_hull("drive_on", false)
|
||||
_set_hull("throttle", 0.0)
|
||||
_set_hull("rcs_attitude", false)
|
||||
_set_hull("pdc_fire", false)
|
||||
_set_hull("chaff_fire", false)
|
||||
if flight_label:
|
||||
flight_label.visible = false
|
||||
if helm_camera:
|
||||
helm_camera.current = false
|
||||
if third_person_camera:
|
||||
third_person_camera.current = false
|
||||
var station := get_node_or_null("/root/Node3D/SolarSystem/Moon/LovellAnchor/Station")
|
||||
var dest: Node = station if station else get_tree().current_scene
|
||||
exiting.reparent(dest)
|
||||
var hatch := _airlock_exit()
|
||||
if hatch:
|
||||
exiting.global_position = hatch.global_position + hatch.global_transform.basis.y * 2.0
|
||||
else:
|
||||
exiting.global_position = global_position + global_transform.basis.x * 8.0
|
||||
exiting.visible = true
|
||||
exiting.set_physics_process(true)
|
||||
exiting.set_process_input(true)
|
||||
exiting.set_process_unhandled_input(true)
|
||||
var player_col = exiting.get_node_or_null("CollisionShape3D")
|
||||
if player_col:
|
||||
player_col.disabled = false
|
||||
if exiting.has_method("set_in_vehicle"):
|
||||
exiting.set_in_vehicle(false)
|
||||
var player_cam = exiting.get_node_or_null("CameraPivot/Camera3D")
|
||||
if player_cam:
|
||||
player_cam.current = true
|
||||
player_cam.make_current()
|
||||
if exiting.has_method("restore_from_vehicle"):
|
||||
exiting.restore_from_vehicle()
|
||||
FloatingOrigin.set_focus(exiting)
|
||||
player_ref = null
|
||||
|
||||
|
||||
func _player_spawn() -> Node3D:
|
||||
var root: Node = hull if hull else self
|
||||
return root.find_child("PlayerSpawn", true, false) as Node3D
|
||||
|
||||
|
||||
func _airlock_exit() -> Node3D:
|
||||
var root: Node = hull if hull else self
|
||||
var n := root.find_child("hatch_airlock_outer", true, false)
|
||||
return n as Node3D
|
||||
|
||||
|
||||
func toggle_camera() -> void:
|
||||
using_third_person = not using_third_person
|
||||
if using_third_person:
|
||||
if helm_camera:
|
||||
helm_camera.current = false
|
||||
if third_person_camera:
|
||||
third_person_camera.make_current()
|
||||
else:
|
||||
if third_person_camera:
|
||||
third_person_camera.current = false
|
||||
if helm_camera:
|
||||
helm_camera.make_current()
|
||||
|
||||
|
||||
func update_third_person_camera() -> void:
|
||||
if not third_person_camera:
|
||||
return
|
||||
var cy := cos(orbit_yaw)
|
||||
var sy := sin(orbit_yaw)
|
||||
var cp := cos(orbit_pitch)
|
||||
var sp := sin(orbit_pitch)
|
||||
var offset := Vector3(sy * cp, sp, cy * cp) * orbit_distance
|
||||
var local_off := Vector3(offset.x, -offset.z, offset.y)
|
||||
var cam_pos := global_position + global_transform.basis * local_off
|
||||
third_person_camera.global_position = cam_pos
|
||||
var target := global_position + global_transform.basis.y * 4.0
|
||||
var forward := target - cam_pos
|
||||
if forward.length_squared() < 0.0001:
|
||||
return
|
||||
forward = forward.normalized()
|
||||
var ref_up := global_transform.basis.z
|
||||
if abs(forward.dot(ref_up)) > 0.92:
|
||||
ref_up = global_transform.basis.x
|
||||
var right := ref_up.cross(forward)
|
||||
if right.length_squared() < 0.0001:
|
||||
return
|
||||
right = right.normalized()
|
||||
var up := forward.cross(right).normalized()
|
||||
third_person_camera.global_basis = Basis(-right, up, -forward).orthonormalized()
|
||||
Reference in New Issue
Block a user