feat: Fortnite-style OTS camera + Alt free-look orbit in third person
- Third-person camera chain is now HeadPivot > OrbitPivot > ShoulderOffset (0.55m right, 0.12m up) > SpringArm(2.6m, 14 deg) — the character sits slightly left of screen centre over-the-shoulder instead of dead centre behind. Aim is unchanged (still the first-person camera). - Hold Alt in third person to orbit the camera freely around the character with the mouse (yaw wraps, pitch clamped -69..+29 deg); the character keeps facing and aiming where it was. Release Alt and the camera springs back behind the shoulder. - debug/orbit_capture.gd: screenshots the OTS framing, a driven orbit, and the spring-back for visual regression. Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
co-authored by
Claude Fable 5
parent
b0f26e6dde
commit
87b8ae70df
@@ -28,6 +28,14 @@ var _pitch_impulse: float = 0.0 # extra camera pitch in radians, decays
|
||||
var _dash_fov_kick: float = 0.0 # extra FOV from dashing, decays
|
||||
var _machine: MovementStateMachine = null
|
||||
|
||||
# Third-person free-look: hold Alt to orbit the camera around the character
|
||||
# without turning the character or aim; release and it springs back behind.
|
||||
var _orbit_yaw: float = 0.0
|
||||
var _orbit_pitch: float = 0.0
|
||||
const ORBIT_PITCH_MIN := -1.2 # radians (looking down from above)
|
||||
const ORBIT_PITCH_MAX := 0.5 # radians (looking up from below)
|
||||
const ORBIT_RETURN_SPEED := 10.0
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
||||
@@ -71,10 +79,17 @@ func _input(event: InputEvent) -> void:
|
||||
if event is InputEventMouseMotion and Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
|
||||
var is_ads = camera and camera.fov < SettingsManager.world_fov - 5.0
|
||||
var sens = SettingsManager.ads_sensitivity if is_ads else SettingsManager.mouse_sensitivity
|
||||
# Yaw: rotate the player (parent)
|
||||
get_parent().rotate_y(-event.relative.x * sens)
|
||||
# Pitch: rotate this pivot
|
||||
rotation.x = clampf(rotation.x - event.relative.y * sens, deg_to_rad(-pitch_limit), deg_to_rad(pitch_limit))
|
||||
if _free_looking():
|
||||
# Alt held in third person: orbit the camera around the character;
|
||||
# the character keeps facing (and aiming) where it was.
|
||||
_orbit_yaw = wrapf(_orbit_yaw - event.relative.x * sens, -PI, PI)
|
||||
_orbit_pitch = clampf(_orbit_pitch - event.relative.y * sens,
|
||||
ORBIT_PITCH_MIN, ORBIT_PITCH_MAX)
|
||||
else:
|
||||
# Yaw: rotate the player (parent)
|
||||
get_parent().rotate_y(-event.relative.x * sens)
|
||||
# Pitch: rotate this pivot
|
||||
rotation.x = clampf(rotation.x - event.relative.y * sens, deg_to_rad(-pitch_limit), deg_to_rad(pitch_limit))
|
||||
|
||||
# Toggle mouse capture with Escape
|
||||
if event is InputEventKey and event.pressed and event.keycode == KEY_ESCAPE:
|
||||
@@ -84,6 +99,14 @@ func _input(event: InputEvent) -> void:
|
||||
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
||||
|
||||
|
||||
## True while the player is holding Alt to look around in third person.
|
||||
func _free_looking() -> bool:
|
||||
var p := get_parent()
|
||||
return p != null and "third_person" in p and p.third_person \
|
||||
and Input.is_key_pressed(KEY_ALT) \
|
||||
and Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if not camera or not params:
|
||||
return
|
||||
@@ -92,6 +115,16 @@ func _process(delta: float) -> void:
|
||||
if not player:
|
||||
return
|
||||
|
||||
# ── Third-person free-look orbit ──────────────────────────────────────
|
||||
var orbit := get_node_or_null("OrbitPivot")
|
||||
if orbit:
|
||||
if not _free_looking():
|
||||
# Spring back behind the character once Alt is released.
|
||||
var t := 1.0 - exp(-ORBIT_RETURN_SPEED * delta)
|
||||
_orbit_yaw = lerpf(_orbit_yaw, 0.0, t)
|
||||
_orbit_pitch = lerpf(_orbit_pitch, 0.0, t)
|
||||
orbit.rotation = Vector3(_orbit_pitch, _orbit_yaw, 0.0)
|
||||
|
||||
if not _machine:
|
||||
_connect_machine()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user