From 32ac46f840636ef651b80301f84a3f65f78e2543 Mon Sep 17 00:00:00 2001 From: Richard Aasa Date: Thu, 27 Aug 2026 21:34:18 +0300 Subject: [PATCH] lobby cam --- camera_iso.gd | 18 +++++++++++++++--- levels/game_shell.gd | 2 ++ levels/level_def.gd | 4 ++++ levels/run_state.gd | 2 ++ 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/camera_iso.gd b/camera_iso.gd index f00ca3f..5ebc4bd 100644 --- a/camera_iso.gd +++ b/camera_iso.gd @@ -1,3 +1,4 @@ +class_name IsoCamera extends Camera3D @export var height: float = 25.0 @@ -16,6 +17,11 @@ var _shake_amount: float = 0.0 var _shake_decay: float = 0.0 var _user_fov: float = 0.0 +# Per-level framing multiplier: 1.0 = the designer's base shot, >1 dollies the camera +# back for a wider view (the lobby uses this). Set by game_shell when a level loads; +# kept separate from the scroll-wheel FOV zoom so the two don't fight. +var _framing_scale: float = 1.0 + # Trailing-camera state: _focus is the smoothed point the camera frames (it lags # the bull), _drag_offset is the velocity-driven trail that slides it behind. var _focus: Vector3 = Vector3.ZERO @@ -51,15 +57,21 @@ func adjust_zoom(ratio: float) -> void: _user_fov = clampf(_user_fov / ratio, fov_min, fov_max) +## Dolly the camera in/out for the level being loaded. 1.0 is the base framing; >1 pulls +## back for a wider shot (the lobby hub uses this). Independent of the scroll-wheel zoom. +func set_framing_scale(scale: float) -> void: + _framing_scale = maxf(scale, 0.1) + + func _process(delta: float) -> void: fov = lerpf(fov, _user_fov, delta * 8.0) var angle_rad := deg_to_rad(horizontal_angle_deg) var offset := Vector3( - sin(angle_rad) * horizontal_distance, - height, - cos(angle_rad) * horizontal_distance + sin(angle_rad) * horizontal_distance * _framing_scale, + height * _framing_scale, + cos(angle_rad) * horizontal_distance * _framing_scale ) var target := get_parent() as Node3D diff --git a/levels/game_shell.gd b/levels/game_shell.gd index 893695e..2a72980 100644 --- a/levels/game_shell.gd +++ b/levels/game_shell.gd @@ -5,6 +5,7 @@ extends Node3D ## previous module first, so no old mesh or collider can survive into the next fight. @onready var _level_root: Node3D = $LevelRoot +@onready var _camera: IsoCamera = $Player/Camera3D func _ready() -> void: @@ -23,4 +24,5 @@ func load_active_level() -> void: if level == null or level.level_scene == null: push_warning("game_shell: active level has no level_scene") return + _camera.set_framing_scale(level.camera_zoom) _level_root.add_child(level.level_scene.instantiate()) diff --git a/levels/level_def.gd b/levels/level_def.gd index da7262f..95276a8 100644 --- a/levels/level_def.gd +++ b/levels/level_def.gd @@ -17,6 +17,10 @@ extends Resource @export var level_scene: PackedScene = null ## Placeholder pip tint on the map until per-level icon art exists. @export var color: Color = Color(0.80, 0.62, 0.24) +## Camera framing multiplier when this level loads — 1.0 is the shell camera's default +## shot; >1 dollies the camera back for a wider view (the lobby pulls out so the whole +## hub reads). Applied by game_shell; independent of the player's scroll-wheel zoom. +@export var camera_zoom: float = 1.0 ## A boss level caps a run — its node is drawn larger and clearing it ends the map. @export var is_boss: bool = false ## The enemy this level pits the bull against. Null → the usual matador wave (the diff --git a/levels/run_state.gd b/levels/run_state.gd index c8e19f1..a69faf2 100644 --- a/levels/run_state.gd +++ b/levels/run_state.gd @@ -61,6 +61,8 @@ func _ready() -> void: _bear.enemy_scene = _BEAR_SCENE # The lobby is a fightless hub — no enemy_scene, so no wave spawns and no win/lose. _lobby = _make_level(&"lobby", "Lobby", _LOBBY_LEVEL, Color(0.62, 0.66, 0.72), false) + # It's a roomy hub with nothing to fight — pull the camera back so more of it reads. + _lobby.camera_zoom = 1.6 func _make_level(