Minimapa
Una Camera2D alejada en un SubViewport que comparte el World2D del juego. El HUD está fuera de ese mundo, por eso no aparece en el mapa.
El editor de arriba está ejecutando este proyecto. Cambia una línea y se recarga.
Clases de Godot usadas
SubViewportCamera2DWorld2D
El código
scripts/main.gd
extends Node
const MAP: Vector2 = Vector2(2600, 1600)
const SPEED: float = 400.0
const MINIMAP_SIZE: Vector2i = Vector2i(320, 240)
var stage: SubViewport
var player: Node2D
var minimap_camera: Camera2D
var route: PackedVector2Array = PackedVector2Array()
var target: int = 1
var manual: bool = false
func _ready() -> void:
_add_background()
var view: Vector2 = get_viewport().get_visible_rect().size
var container: SubViewportContainer = SubViewportContainer.new()
container.stretch = true
add_child(container)
container.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
stage = SubViewport.new()
stage.size = Vector2i(view)
stage.render_target_update_mode = SubViewport.UPDATE_ALWAYS
container.add_child(stage)
_add_world()
route = PackedVector2Array([Vector2(420, 400), Vector2(2180, 420), Vector2(2160, 1200), Vector2(1300, 800), Vector2(440, 1180)])
player = _add_player()
player.position = route[0]
var camera: Camera2D = Camera2D.new()
camera.position_smoothing_enabled = true
camera.position_smoothing_speed = 5.0
camera.limit_left = 0
camera.limit_top = 0
camera.limit_right = int(MAP.x)
camera.limit_bottom = int(MAP.y)
player.add_child(camera)
camera.make_current()
var minimap: SubViewport = SubViewport.new()
minimap.size = MINIMAP_SIZE
minimap.render_target_update_mode = SubViewport.UPDATE_ALWAYS
add_child(minimap)
# a Viewport is born with its own World2D, so sharing one has to be explicit
minimap.world_2d = stage.world_2d
minimap_camera = Camera2D.new()
minimap_camera.zoom = Vector2(0.26, 0.26)
minimap_camera.position = player.position
minimap.add_child(minimap_camera)
minimap_camera.make_current()
_add_hud(minimap)
print('the corner panel is a second Camera2D on the same World2D, wasd drives the square')
func _process(delta: float) -> void:
var drive: Vector2 = Vector2(
float(Input.is_key_pressed(KEY_D)) - float(Input.is_key_pressed(KEY_A)),
float(Input.is_key_pressed(KEY_S)) - float(Input.is_key_pressed(KEY_W))
)
if drive != Vector2.ZERO:
manual = true
if manual:
player.position += drive.normalized() * SPEED * delta
player.position = player.position.clamp(Vector2(80, 80), MAP - Vector2(80, 80))
else:
var goal: Vector2 = route[target]
player.position = player.position.move_toward(goal, SPEED * delta)
if player.position.distance_to(goal) < 4.0:
target = (target + 1) % route.size()
minimap_camera.position = player.position
func _add_world() -> void:
var outside: Polygon2D = _make_rect(MAP + Vector2(2400, 2400), Color('#12141a'))
outside.position = MAP * 0.5
stage.add_child(outside)
var ground: Polygon2D = _make_rect(MAP, Color('#12141a').lerp(Color('#2a2f3d'), 0.5))
ground.position = MAP * 0.5
stage.add_child(ground)
for x in range(200, int(MAP.x), 200):
_add_grid_line(Vector2(x, 0), Vector2(x, MAP.y))
for y in range(200, int(MAP.y), 200):
_add_grid_line(Vector2(0, y), Vector2(MAP.x, y))
for wall in [
{ at = Vector2(MAP.x * 0.5, 45), size = Vector2(MAP.x, 90) },
{ at = Vector2(MAP.x * 0.5, MAP.y - 45), size = Vector2(MAP.x, 90) },
{ at = Vector2(45, MAP.y * 0.5), size = Vector2(90, MAP.y) },
{ at = Vector2(MAP.x - 45, MAP.y * 0.5), size = Vector2(90, MAP.y) },
{ at = Vector2(900, 760), size = Vector2(560, 90) },
{ at = Vector2(1700, 480), size = Vector2(90, 620) },
{ at = Vector2(1820, 1160), size = Vector2(620, 90) },
{ at = Vector2(700, 1300), size = Vector2(90, 520) },
{ at = Vector2(1180, 1420), size = Vector2(700, 90) },
{ at = Vector2(2280, 800), size = Vector2(90, 480) },
{ at = Vector2(420, 700), size = Vector2(90, 340) },
]:
var block: Polygon2D = _make_rect(wall.size, Color('#8da5f3').lerp(Color('#12141a'), 0.45))
block.position = wall.at
stage.add_child(block)
var rng: RandomNumberGenerator = RandomNumberGenerator.new()
rng.seed = 7
for i in 26:
var crate: Polygon2D = _make_rect(Vector2(90, 90), Color('#f3d48d').lerp(Color('#12141a'), 0.35))
crate.position = Vector2(rng.randf_range(200, MAP.x - 200), rng.randf_range(200, MAP.y - 200))
crate.rotation = rng.randf_range(-0.4, 0.4)
stage.add_child(crate)
func _add_player() -> Node2D:
var body: Node2D = Node2D.new()
body.add_child(_make_rect(Vector2(80, 80), Color('#8eef97')))
body.add_child(_make_rect(Vector2(30, 30), Color('#fc7f7f')))
stage.add_child(body)
return body
func _add_grid_line(from: Vector2, to: Vector2) -> void:
var line: Line2D = Line2D.new()
line.points = PackedVector2Array([from, to])
line.width = 3.0
line.default_color = Color('#2a2f3d')
stage.add_child(line)
func _make_rect(size: Vector2, color: Color) -> Polygon2D:
var rect: Polygon2D = Polygon2D.new()
rect.polygon = PackedVector2Array([-size * 0.5, Vector2(size.x, -size.y) * 0.5, size * 0.5, Vector2(-size.x, size.y) * 0.5])
rect.color = color
return rect
func _add_hud(minimap: SubViewport) -> void:
var hud: CanvasLayer = CanvasLayer.new()
add_child(hud)
var view: Vector2 = get_viewport().get_visible_rect().size
var origin: Vector2 = Vector2(view.x - MINIMAP_SIZE.x - 34, 34)
var frame: ColorRect = ColorRect.new()
frame.color = Color('#8da5f3')
frame.position = origin - Vector2(4, 4)
frame.size = Vector2(MINIMAP_SIZE) + Vector2(8, 8)
hud.add_child(frame)
var picture: TextureRect = TextureRect.new()
picture.texture = minimap.get_texture()
picture.position = origin
picture.size = Vector2(MINIMAP_SIZE)
hud.add_child(picture)
var label: Label = Label.new()
label.text = 'minimap zoom 0.26'
label.add_theme_font_size_override('font_size', 20)
label.add_theme_color_override('font_color', Color('#8da5f3'))
label.position = origin + Vector2(0, MINIMAP_SIZE.y + 10)
hud.add_child(label)
var title: Label = Label.new()
title.text = 'the HUD is outside the shared world, so it stays out of the minimap'
title.add_theme_font_size_override('font_size', 20)
title.add_theme_color_override('font_color', Color('#8eef97'))
title.position = Vector2(40, 40)
hud.add_child(title)
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)