Files
nodewars/addons/strategy_cam/strategy_camera.gd
2026-05-13 18:52:00 +02:00

105 lines
3.8 KiB
GDScript

extends Camera2D
# See WARNING's below for detail on custom control binding. Apart from scroll zooming, every key and mouse
# press must be bound manually by the developer.
@export var allow_mouse_controls: bool = true
@export var allow_keyboard_controls: bool = true
@export_group("Keyboard Controls")
## Camera zoom speed when controlled with keys
@export var key_zoom_speed: float = 2.0
## Translation speed when controlled by keys
@export var translation_speed: float = 100.0
@export_group("Camera Zoom Variables")
## Relative zoom in every scroll wheel tick.
@export var zoom_step: float = 0.2
## Speed at which the camera reaches the next target zoom. Really funky things can happen
## if x and y are set to different values...
@export var zoom_speed: Vector2 = Vector2(10, 10)
@export_group("Directional Limits")
## Top-left limit of the camera position/movement (applied to the top-left of the camera).
## If this and limit_BR set to Vector2.ZERO, no limits will be applied
@export var limit_TL: Vector2 = Vector2.ZERO
## Bottom-right limit of the camera position/movement (applied to the bottom-right of the camera).
## If this and limit_TL set to Vector2.ZERO, no limits will be applied
@export var limit_BR: Vector2 = Vector2.ZERO
var camera_TL: Vector2 = Vector2(-576, -324)
var camera_BR: Vector2 = Vector2(576, 324)
var target_zoom: Vector2 = Vector2.ONE
func _ready() -> void:
target_zoom = zoom
_on_resolution_change()
get_viewport().size_changed.connect(_on_resolution_change)
func _on_resolution_change() -> void:
camera_TL = -get_viewport_rect().size / 2
camera_BR = get_viewport_rect().size / 2
func _unhandled_input(event: InputEvent) -> void:
if not allow_mouse_controls:
return
# Zooming by scrolling with the middle mouse button
if event is InputEventMouse:
if event.is_pressed() and not event.is_echo():
if event.button_index == MOUSE_BUTTON_WHEEL_UP:
zoom_camera(zoom_step)
elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
zoom_camera(-zoom_step)
target_zoom = target_zoom.clamp(Vector2.ONE*0.5, Vector2.INF)
# Camera translation by clicking and dragging
if event is InputEventMouseMotion:
# WARNING: The dragging control must be defined WITHIN THIS PROJECT
if Input.is_action_pressed("cam_drag"):
position -= event.relative / zoom
func _process(delta: float) -> void:
if target_zoom.length()-0.001 <= zoom.length() and zoom.length() <= target_zoom.length()+0.001:
zoom = target_zoom
else:
increment_zoom((target_zoom-zoom) * zoom_speed * delta)
var screen_centre: Vector2 = get_screen_center_position()
var actual_TL: Vector2 = screen_centre + camera_TL / target_zoom
var actual_BR: Vector2 = screen_centre + camera_BR / target_zoom
# WARNING: The keyboard controls must be defined WITHIN THIS PROJECT
if allow_keyboard_controls:
position.x += Input.get_axis("cam_left", "cam_right") * translation_speed * delta
position.y += Input.get_axis("cam_up", "cam_down") * translation_speed * delta
var camera_zoom_direction: float = Input.get_axis("cam_zoom_out", "cam_zoom_in")
if camera_zoom_direction:
zoom_camera(camera_zoom_direction * key_zoom_speed * delta)
zoom = target_zoom
if limit_BR == Vector2.ZERO and limit_TL == Vector2.ZERO:
return
# Camera limit application
if actual_TL.x < limit_TL.x:
position.x += limit_TL.x - actual_TL.x
if actual_TL.y < limit_TL.y:
position.y += limit_TL.y - actual_TL.y
if actual_BR.x > limit_BR.x:
position.x -= actual_BR.x - limit_BR.x
if actual_BR.y > limit_BR.y:
position.y -= actual_BR.y - limit_BR.y
func zoom_camera(zoom_amount: float) -> void:
target_zoom *= pow(10.0, zoom_amount)
func increment_zoom(zoom_direction: Vector2) -> void:
var previous_mouse_position: Vector2 = get_local_mouse_position()
zoom += zoom_direction
var diff: Vector2 = previous_mouse_position - get_local_mouse_position()
offset += diff