extends Camera3D ## Overview camera: orthographic three-quarter view over the whole map, pan, zoom and ## lane focus. Blau's base sits bottom-left, Rot's top-right, as on the minimap. var focus := Vector3.ZERO var yaw: float = 0.0 var pitch: float = deg_to_rad(-56.0) var zoom: float = 34.0 var reduced_motion: bool = false var _goal_focus := Vector3.ZERO var _goal_zoom: float = 34.0 var _dragging: bool = false func _ready() -> void: projection = PROJECTION_ORTHOGONAL near = .1 far = 400.0 current = true _goal_focus = focus _apply() func look_at_point(point: Vector3, new_zoom: float = -1.0, instant: bool = false) -> void: _goal_focus = Vector3(clampf(point.x, -40, 40), 0, clampf(point.z, -40, 40)) if new_zoom > 0.0: _goal_zoom = new_zoom if instant or reduced_motion: focus = _goal_focus zoom = _goal_zoom _apply() func overview(instant: bool = false) -> void: look_at_point(Vector3.ZERO, 46.0, instant) func _apply() -> void: size = zoom var back := Vector3(0, 0, 1).rotated(Vector3.RIGHT, pitch).rotated(Vector3.UP, yaw) position = focus + back * 80.0 look_at(focus, Vector3.UP) func _process(delta: float) -> void: var pan := Vector2(Input.get_axis("ui_left", "ui_right"), Input.get_axis("ui_up", "ui_down")) if Input.is_physical_key_pressed(KEY_A): pan.x -= 1 if Input.is_physical_key_pressed(KEY_D): pan.x += 1 if Input.is_physical_key_pressed(KEY_W): pan.y -= 1 if Input.is_physical_key_pressed(KEY_S): pan.y += 1 if pan != Vector2.ZERO and not _text_focus(): var right := Vector3(cos(yaw), 0, -sin(yaw)) var forward := Vector3(-sin(yaw), 0, -cos(yaw)) _goal_focus += (right * pan.x - forward * pan.y) * zoom * .9 * delta var t: float = 1.0 if reduced_motion else minf(1.0, delta * 7.0) focus = focus.lerp(_goal_focus, t) zoom = lerpf(zoom, _goal_zoom, t) _apply() func _text_focus() -> bool: var owner: Control = get_viewport().gui_get_focus_owner() return owner is LineEdit or owner is TextEdit ## World input only; the HUD consumes its own clicks before they reach here. func handle_world_input(event: InputEvent) -> bool: if event is InputEventMouseButton and event.pressed: if event.button_index == MOUSE_BUTTON_WHEEL_UP: _goal_zoom = maxf(12.0, _goal_zoom - 2.5) return true if event.button_index == MOUSE_BUTTON_WHEEL_DOWN: _goal_zoom = minf(60.0, _goal_zoom + 2.5) return true if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_MIDDLE: _dragging = event.pressed return true if event is InputEventMouseMotion and _dragging: var right := Vector3(cos(yaw), 0, -sin(yaw)) var forward := Vector3(-sin(yaw), 0, -cos(yaw)) _goal_focus -= (right * event.relative.x - forward * event.relative.y) * zoom / 700.0 return true return false