Files
Trinittu/scripts/train_camera.gd
JMP Games e1a95d7417 Init
2026-01-22 08:34:02 +01:00

119 lines
3.4 KiB
GDScript

extends Camera3D
class_name TrainCamera
enum CameraMode { FOLLOW, SIDE, TOP, COCKPIT, CINEMATIC }
@export_group("Camera")
@export var follow_distance: float = 18.0
@export var follow_height: float = 7.0
@export var smoothness: float = 4.0
var train: Train
var mode: CameraMode = CameraMode.FOLLOW
var orbit_angle: float = 0.0
var cinematic_angle: float = 0.0
func _process(delta: float) -> void:
if not train or not train.locomotive:
return
_handle_input(delta)
match mode:
CameraMode.FOLLOW:
_update_follow(delta)
CameraMode.SIDE:
_update_side(delta)
CameraMode.TOP:
_update_top(delta)
CameraMode.COCKPIT:
_update_cockpit(delta)
CameraMode.CINEMATIC:
_update_cinematic(delta)
func _handle_input(delta: float) -> void:
if Input.is_action_just_pressed("ui_accept"):
mode = ((mode + 1) % CameraMode.size()) as CameraMode
orbit_angle = 0.0
if Input.is_action_pressed("camera_left"):
orbit_angle -= 2.0 * delta
elif Input.is_action_pressed("camera_right"):
orbit_angle += 2.0 * delta
orbit_angle = clamp(orbit_angle, -PI/2.5, PI/2.5)
func _update_follow(delta: float) -> void:
var loco = train.locomotive
var train_pos = loco.global_position
var forward = -loco.global_transform.basis.z
var right = loco.global_transform.basis.x
var rotated = forward * cos(orbit_angle) + right * sin(orbit_angle)
var target_pos = train_pos - rotated * follow_distance + Vector3.UP * follow_height
var target_look = train_pos + Vector3.UP * 2.0
global_position = global_position.lerp(target_pos, smoothness * delta)
look_at(target_look, Vector3.UP)
func _update_side(delta: float) -> void:
var loco = train.locomotive
var train_pos = loco.global_position
var right = loco.global_transform.basis.x
var side_dir = sign(orbit_angle) if abs(orbit_angle) > 0.1 else 1.0
var target_pos = train_pos + right * 12.0 * side_dir + Vector3.UP * 4.0
global_position = global_position.lerp(target_pos, smoothness * delta)
look_at(train_pos + Vector3.UP * 1.5, Vector3.UP)
func _update_top(delta: float) -> void:
var train_pos = train.get_locomotive_position()
var target_pos = train_pos + Vector3.UP * 35.0
global_position = global_position.lerp(target_pos, smoothness * delta)
look_at(train_pos, Vector3.FORWARD)
func _update_cockpit(delta: float) -> void:
var loco = train.locomotive
# Offset: dentro la cabina
var cockpit_pos = loco.global_position + loco.global_transform.basis * Vector3(0, 3.2, 1.5)
var forward_point = loco.global_position - (-loco.global_transform.basis.z) * 40.0
var look_offset = loco.global_transform.basis.x * orbit_angle * 15.0
global_position = global_position.lerp(cockpit_pos, smoothness * 2.0 * delta)
look_at(forward_point + look_offset + Vector3.UP * 1.0, Vector3.UP)
func _update_cinematic(delta: float) -> void:
var train_pos = train.get_locomotive_position()
cinematic_angle += 0.25 * delta
var offset = Vector3(
cos(cinematic_angle) * 22.0,
8.0 + sin(cinematic_angle * 0.5) * 4.0,
sin(cinematic_angle) * 22.0
)
var target_pos = train_pos + offset
global_position = global_position.lerp(target_pos, smoothness * 0.4 * delta)
look_at(train_pos + Vector3.UP * 1.5, Vector3.UP)
func get_mode_name() -> String:
match mode:
CameraMode.FOLLOW: return "Segue"
CameraMode.SIDE: return "Laterale"
CameraMode.TOP: return "Alto"
CameraMode.COCKPIT: return "Prima persona"
CameraMode.CINEMATIC: return "Cinematica"
return "Sconosciuta"