66 lines
2.7 KiB
GDScript
66 lines
2.7 KiB
GDScript
class_name VaultCamera
|
|
extends Camera2D
|
|
## Камера убежища: перетаскивание, зум колесом и клавиатурная прокрутка.
|
|
##
|
|
## Границы задаются встроенными limit_* по размеру убежища, поэтому вручную
|
|
## позицию не зажимаем — движок делает это сам.
|
|
|
|
const ZOOM_STEP := 1.2
|
|
const MIN_ZOOM := 0.45
|
|
const MAX_ZOOM := 2.2
|
|
const KEY_PAN_SPEED := 900.0
|
|
const EDGE_MARGIN := 420.0
|
|
## Сверху запас больше: там небо со светилами, и на него хочется смотреть.
|
|
const SKY_MARGIN := 900.0
|
|
|
|
var _dragging := false
|
|
|
|
|
|
func _ready() -> void:
|
|
var bounds := VaultGrid.bounds()
|
|
limit_left = int(bounds.position.x - EDGE_MARGIN)
|
|
limit_right = int(bounds.end.x + EDGE_MARGIN)
|
|
# Сверху отмеряем от поверхности, а не от бункера: над землёй стоит будка
|
|
# входа, и до неё нужно доезжать.
|
|
limit_top = int(-SKY_MARGIN)
|
|
limit_bottom = int(bounds.end.y + EDGE_MARGIN)
|
|
# Открываемся на верхних этажах — оттуда видно и вход, и застройку.
|
|
position = Vector2(bounds.get_center().x, bounds.position.y + VaultGrid.CELL.y)
|
|
|
|
|
|
func _process(delta: float) -> void:
|
|
var direction := Input.get_vector("move_left", "move_right", "move_up", "move_down")
|
|
if direction != Vector2.ZERO:
|
|
position += direction * KEY_PAN_SPEED * delta / zoom.x
|
|
|
|
|
|
func _unhandled_input(event: InputEvent) -> void:
|
|
if event is InputEventMouseButton:
|
|
_handle_mouse_button(event as InputEventMouseButton)
|
|
elif event is InputEventMouseMotion and _dragging:
|
|
position -= (event as InputEventMouseMotion).relative / zoom
|
|
get_viewport().set_input_as_handled()
|
|
|
|
|
|
func _handle_mouse_button(event: InputEventMouseButton) -> void:
|
|
match event.button_index:
|
|
# На один щелчок колеса Godot шлёт и нажатие, и отпускание. Без
|
|
# проверки pressed шаг зума применялся бы дважды.
|
|
MOUSE_BUTTON_WHEEL_UP:
|
|
if event.pressed:
|
|
_zoom_by(ZOOM_STEP)
|
|
get_viewport().set_input_as_handled()
|
|
MOUSE_BUTTON_WHEEL_DOWN:
|
|
if event.pressed:
|
|
_zoom_by(1.0 / ZOOM_STEP)
|
|
get_viewport().set_input_as_handled()
|
|
MOUSE_BUTTON_RIGHT, MOUSE_BUTTON_MIDDLE:
|
|
# Правая и средняя кнопки таскают вид; левая остаётся строительству.
|
|
_dragging = event.pressed
|
|
get_viewport().set_input_as_handled()
|
|
|
|
|
|
func _zoom_by(factor: float) -> void:
|
|
var target := clampf(zoom.x * factor, MIN_ZOOM, MAX_ZOOM)
|
|
zoom = Vector2(target, target)
|