Zoom y paneo

Arrastra para mover y gira la rueda para hacer zoom en el puntero en vez del centro de la pantalla, que son dos líneas de matemáticas sobre Camera2D.zoom.

El editor de arriba está ejecutando este proyecto. Cambia una línea y se recarga.

Clases de Godot usadas

Camera2DInputEventMouseButtonLine2D

El 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)

Más ejemplos de Cámara