Zoom e pan
Arraste para mover e role a roda para dar zoom no ponteiro em vez do centro da tela, o que são duas linhas de matemática em cima do Camera2D.zoom.
O editor acima está rodando este projeto. Mude uma linha e ele recarrega.
Classes do Godot usadas
Camera2DInputEventMouseButtonLine2D
O código
scripts/main.gd
extends Node
const CELL: float = 120.0
const HALF: Vector2 = Vector2(1200, 960)
const MIN_ZOOM: Vector2 = Vector2(0.35, 0.35)
const MAX_ZOOM: Vector2 = Vector2(3.0, 3.0)
var camera: Camera2D
var readout: Label
var elapsed: float = 0.0
var manual: bool = false
func _ready() -> void:
_add_background()
_add_grid()
_add_landmarks()
camera = Camera2D.new()
add_child(camera)
camera.make_current()
_add_hud()
print('drag with the left button to pan, use the wheel to zoom at the pointer')
func _process(delta: float) -> void:
elapsed += delta
if not manual:
camera.position = Vector2(sin(elapsed * 0.5) * 520.0, sin(elapsed * 0.31) * 320.0)
camera.zoom = Vector2.ONE * (0.95 + 0.45 * sin(elapsed * 0.7))
readout.text = 'zoom %.2f camera %d, %d' % [camera.zoom.x, camera.position.x, camera.position.y]
func _unhandled_input(event: InputEvent) -> void:
if event is InputEventMouseButton and event.pressed:
var button: InputEventMouseButton = event as InputEventMouseButton
if button.button_index == MOUSE_BUTTON_WHEEL_UP:
_zoom_at(button.position, 1.12)
elif button.button_index == MOUSE_BUTTON_WHEEL_DOWN:
_zoom_at(button.position, 1.0 / 1.12)
elif event is InputEventMouseMotion:
var motion: InputEventMouseMotion = event as InputEventMouseMotion
if motion.button_mask & MOUSE_BUTTON_MASK_LEFT:
manual = true
camera.position -= motion.relative / camera.zoom
func _zoom_at(screen_point: Vector2, factor: float) -> void:
manual = true
var view: Vector2 = get_viewport().get_visible_rect().size
var before: Vector2 = camera.position + (screen_point - view * 0.5) / camera.zoom
camera.zoom = (camera.zoom * factor).clamp(MIN_ZOOM, MAX_ZOOM)
camera.position = before - (screen_point - view * 0.5) / camera.zoom
func _add_grid() -> void:
var x: float = -HALF.x
while x <= HALF.x:
var accent: bool = is_zero_approx(x)
_add_line(Vector2(x, -HALF.y), Vector2(x, HALF.y), 6.0 if accent else 2.0, Color('#8da5f3') if accent else Color('#2a2f3d'))
x += CELL
var y: float = -HALF.y
while y <= HALF.y:
var accent: bool = is_zero_approx(y)
_add_line(Vector2(-HALF.x, y), Vector2(HALF.x, y), 6.0 if accent else 2.0, Color('#8da5f3') if accent else Color('#2a2f3d'))
y += CELL
func _add_landmarks() -> void:
var colors: Array[Color] = [Color('#8eef97'), Color('#fc7f7f'), Color('#f3d48d'), Color('#8da5f3')]
var rng: RandomNumberGenerator = RandomNumberGenerator.new()
rng.seed = 11
for row in 8:
for column in 10:
var size: float = rng.randf_range(34, 78)
var block: Polygon2D = Polygon2D.new()
block.polygon = PackedVector2Array([Vector2(-size, -size) * 0.5, Vector2(size, -size) * 0.5, Vector2(size, size) * 0.5, Vector2(-size, size) * 0.5])
block.color = colors[(row + column) % colors.size()]
block.position = Vector2(-1080 + column * 240, -840 + row * 240)
block.rotation = rng.randf_range(-0.4, 0.4)
add_child(block)
var origin: Label = Label.new()
origin.text = '0, 0'
origin.add_theme_font_size_override('font_size', 28)
origin.add_theme_color_override('font_color', Color('#8da5f3'))
origin.position = Vector2(14, 6)
add_child(origin)
func _add_line(from: Vector2, to: Vector2, width: float, color: Color) -> void:
var line: Line2D = Line2D.new()
line.points = PackedVector2Array([from, to])
line.width = width
line.default_color = color
add_child(line)
func _add_hud() -> void:
var hud: CanvasLayer = CanvasLayer.new()
add_child(hud)
var title: Label = Label.new()
title.text = 'drag to pan, wheel to zoom at the pointer'
title.add_theme_font_size_override('font_size', 22)
title.add_theme_color_override('font_color', Color('#8eef97'))
title.position = Vector2(40, 34)
hud.add_child(title)
readout = Label.new()
readout.add_theme_font_size_override('font_size', 20)
readout.add_theme_color_override('font_color', Color('#f3d48d'))
readout.position = Vector2(40, 66)
hud.add_child(readout)
func _add_background() -> void:
var layer: CanvasLayer = CanvasLayer.new()
layer.layer = -1
add_child(layer)
var background: ColorRect = ColorRect.new()
background.color = Color('#12141a')
layer.add_child(background)
# ColorRect defaults to MOUSE_FILTER_STOP and would eat the click before _unhandled_input
background.mouse_filter = Control.MOUSE_FILTER_IGNORE
background.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)