Files
Papay-Shooter/debug/orbit_capture.gd
T
Nicholas ButzkeandClaude Fable 5 87b8ae70df 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]>
2026-07-19 23:59:44 -04:00

60 lines
1.9 KiB
GDScript

extends SceneTree
## Dev tool: screenshot the third-person over-the-shoulder framing, the Alt
## free-look orbit, and the spring-back. Run:
## godot --path . --windowed --resolution 1280x720 -s res://debug/orbit_capture.gd -- <out_dir>
var _frames := 0
var _out_dir := "."
var _player: Node = null
var _rig: Node = null
func _initialize() -> void:
var args := OS.get_cmdline_user_args()
if args.size() > 0:
_out_dir = args[0]
change_scene_to_file("res://ui/main_menu/main_menu.tscn")
func _process(_delta: float) -> bool:
_frames += 1
if _frames == 40:
var sm = root.get_node_or_null("SkinManager")
if sm:
sm.set_active_skin("taila")
var nm = root.get_node_or_null("NetworkManager")
if nm and nm.has_method("start_singleplayer_match"):
nm.start_singleplayer_match("Deathmatch")
change_scene_to_file("res://scenes/maps/test_level/test_level.tscn")
elif _frames == 160:
for p in root.find_children("*", "CharacterBody3D", true, false):
if p.has_method("set_third_person") and p.is_multiplayer_authority():
_player = p
break
if not _player:
printerr("orbit_capture: no player")
return true
_rig = _player.get_node_or_null("HeadPivot")
_player.set_third_person(true)
elif _frames == 220:
_shot("ots_default") # over-the-shoulder framing, no orbit
elif _frames > 220 and _frames <= 280:
# Simulate holding Alt: force the orbit angles every frame (the
# spring-back fights us since Alt isn't really down, so keep writing).
_rig._orbit_yaw = 1.9
_rig._orbit_pitch = -0.25
elif _frames == 281:
_shot("orbit_side") # camera swung around toward the front
elif _frames == 320:
_shot("sprung_back") # ~0.65s after release: should be behind again
return true
return false
func _shot(tag: String) -> void:
var img := root.get_viewport().get_texture().get_image()
var path := _out_dir + "/" + tag + ".png"
img.save_png(path)
print("orbit_capture: saved ", path)