46 lines
1.5 KiB
GDScript
46 lines
1.5 KiB
GDScript
extends Node3D
|
|
class_name ShipCamera
|
|
## Third-person camera for a freely flying ship.
|
|
## Stays behind and above the ship regardless of pitch/yaw.
|
|
## Attach as a sibling of the ship (child of the scene root), NOT as a child
|
|
## of the ship, so it can lag smoothly.
|
|
|
|
@export var target: ShipController
|
|
@export var follow_distance: float = 12.0
|
|
@export var follow_height: float = 3.0 ## offset along the ship's local UP
|
|
@export var look_ahead: float = 4.0
|
|
@export var position_smoothing: float = 5.0
|
|
@export var rotation_smoothing: float = 6.0
|
|
|
|
@onready var camera: Camera3D = $Camera3D
|
|
|
|
|
|
func _ready() -> void:
|
|
if not camera:
|
|
camera = Camera3D.new()
|
|
add_child(camera)
|
|
camera.current = true
|
|
|
|
|
|
func _physics_process(delta: float) -> void:
|
|
if not target:
|
|
return
|
|
|
|
# "Behind" the ship in its local space (accounts for pitch + yaw)
|
|
var ship_back := target.global_transform.basis.z # +Z is behind in Godot
|
|
var ship_up := target.global_transform.basis.y
|
|
|
|
var desired_pos := (
|
|
target.global_position
|
|
+ ship_back * follow_distance
|
|
+ ship_up * follow_height
|
|
)
|
|
|
|
global_position = global_position.lerp(desired_pos, position_smoothing * delta)
|
|
|
|
# Look at a point ahead of the ship
|
|
var ship_forward := -target.global_transform.basis.z
|
|
var look_target := target.global_position + ship_forward * look_ahead
|
|
|
|
var desired_transform := global_transform.looking_at(look_target, Vector3.UP)
|
|
global_transform = global_transform.interpolate_with(desired_transform, rotation_smoothing * delta) |