跟随与边界

带位置平滑和四个 limit 属性的 Camera2D。黄色十字是相机中心,可以看到它停在边界上而玩家继续往前走。

上方的编辑器正在运行这个项目。改一行代码,它就会重新加载。

用到的 Godot 类

Camera2DLine2DPolygon2D

代码

scripts/main.gd
extends Node

const MAP: Vector2 = Vector2(2600, 1500)
const SPEED: float = 520.0

var player: Node2D
var camera: Camera2D
var crosshair: Node2D
var readout: Label
var angle: float = PI
var manual: bool = false


func _ready() -> void:
	_add_background()
	_add_map()

	player = _make_square(52.0, Color('#8eef97'))
	player.position = _orbit_point()
	add_child(player)

	camera = Camera2D.new()
	camera.position_smoothing_enabled = true
	camera.position_smoothing_speed = 4.0
	camera.limit_left = 0
	camera.limit_top = 0
	camera.limit_right = int(MAP.x)
	camera.limit_bottom = int(MAP.y)
	camera.limit_smoothed = true
	player.add_child(camera)
	camera.make_current()

	crosshair = _make_crosshair()
	add_child(crosshair)

	_add_hud()

	print('the green square walks the map on its own, arrows drive it, the camera stops at the border')


func _process(delta: float) -> void:
	var drive: Vector2 = Vector2(
		float(Input.is_key_pressed(KEY_RIGHT)) - float(Input.is_key_pressed(KEY_LEFT)),
		float(Input.is_key_pressed(KEY_DOWN)) - float(Input.is_key_pressed(KEY_UP))
	)

	if drive != Vector2.ZERO:
		manual = true

	if manual:
		player.position += drive.normalized() * SPEED * delta
		player.position = player.position.clamp(Vector2(60, 60), MAP - Vector2(60, 60))
	else:
		angle += delta * 0.6
		player.position = _orbit_point()

	var center: Vector2 = camera.get_screen_center_position()
	crosshair.position = center
	readout.text = 'player %d, %d      camera %d, %d' % [player.position.x, player.position.y, center.x, center.y]


func _orbit_point() -> Vector2:
	return MAP * 0.5 + Vector2(cos(angle) * MAP.x * 0.46, sin(angle) * MAP.y * 0.44)


func _add_map() -> void:
	var floor_rect: Polygon2D = Polygon2D.new()
	floor_rect.polygon = PackedVector2Array([Vector2.ZERO, Vector2(MAP.x, 0), MAP, Vector2(0, MAP.y)])
	floor_rect.color = Color('#12141a').lerp(Color('#2a2f3d'), 0.55)
	add_child(floor_rect)

	for x in range(200, int(MAP.x), 200):
		_add_line(Vector2(x, 0), Vector2(x, MAP.y), 2.0, Color('#2a2f3d'))

	for y in range(200, int(MAP.y), 200):
		_add_line(Vector2(0, y), Vector2(MAP.x, y), 2.0, Color('#2a2f3d'))

	var rng: RandomNumberGenerator = RandomNumberGenerator.new()
	rng.seed = 9

	for row in 4:
		for column in 6:
			var block: Node2D = _make_square(rng.randf_range(70, 140), Color('#8da5f3').lerp(Color('#12141a'), 0.35))
			block.position = Vector2(300 + column * 400, 260 + row * 340) + Vector2(rng.randf_range(-80, 80), rng.randf_range(-80, 80))
			add_child(block)

	var border: Line2D = Line2D.new()
	border.points = PackedVector2Array([Vector2(8, 8), Vector2(MAP.x - 8, 8), MAP - Vector2(8, 8), Vector2(8, MAP.y - 8), Vector2(8, 8)])
	border.width = 16.0
	border.default_color = Color('#fc7f7f')
	add_child(border)


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 _make_square(size: float, color: Color) -> Node2D:
	var square: Polygon2D = Polygon2D.new()
	square.polygon = PackedVector2Array([Vector2(-size, -size) * 0.5, Vector2(size, -size) * 0.5, Vector2(size, size) * 0.5, Vector2(-size, size) * 0.5])
	square.color = color

	return square


func _make_crosshair() -> Node2D:
	var mark: Node2D = Node2D.new()

	for points in [PackedVector2Array([Vector2(-34, 0), Vector2(34, 0)]), PackedVector2Array([Vector2(0, -34), Vector2(0, 34)])]:
		var line: Line2D = Line2D.new()
		line.points = points
		line.width = 4.0
		line.default_color = Color('#f3d48d')
		mark.add_child(line)

	return mark


func _add_hud() -> void:
	var hud: CanvasLayer = CanvasLayer.new()
	add_child(hud)

	var title: Label = Label.new()
	title.text = 'green square: player          yellow cross: camera center'
	title.add_theme_font_size_override('font_size', 20)
	title.add_theme_color_override('font_color', Color('#8da5f3'))
	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, 64)
	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)
	background.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)

更多相机示例