9dffacd938
Player: move/jump (Space), test flight (F, debug builds only). Key: pickup, hold S to aim with live trajectory preview, release to throw, W to warp to the thrown key. Spring bounce. Spikes deal damage. 3-heart health, Z consumes a heal item for +1 heart and a 5s shield. HUD with hearts and item count. Death screen with fade-to-black and restart. Hidden passages. Assets: Kenney Pixel Platformer (CC0).
84 lines
2.5 KiB
GDScript
84 lines
2.5 KiB
GDScript
extends Node2D
|
|
|
|
const ATLAS := preload("res://assets/game/tilesets/kenney_tiles_atlas.png")
|
|
const TILE := 18
|
|
|
|
## 隐藏通道:下面这些格子在关卡开始时会被"挖空",
|
|
## 原本是实心石壁的地方就变成能穿过去的暗道。
|
|
## 坐标是格坐标(格边长 18px),改这里就能挪位置。
|
|
@export var hidden_cells: Array = [
|
|
# ① 主线走廊上的石柱(第 13 列第 6~7 行)
|
|
Vector2i(13, 6), Vector2i(13, 7),
|
|
|
|
# ② 低层暗道(第 11 行第 12~15 列)
|
|
Vector2i(12, 11), Vector2i(13, 11), Vector2i(14, 11), Vector2i(15, 11),
|
|
]
|
|
|
|
## 伪装贴图所在层:要低于角色(z=10)、高于地形(z=0~2)
|
|
@export var cover_z_index: int = 3
|
|
## 是否给洞口盖上"假墙"(关掉的话洞口会明显地露出来)
|
|
@export var hide_with_cover: bool = true
|
|
|
|
|
|
func _ready() -> void:
|
|
var layers := _tile_layers()
|
|
if layers.is_empty():
|
|
return
|
|
var base: TileMapLayer = layers[0]
|
|
|
|
# 先把盖子做好(此时参考的那块墙还在),再挖空
|
|
var covers: Array = []
|
|
for cell in hidden_cells:
|
|
covers.append([cell, _make_cover(cell) if hide_with_cover else null])
|
|
|
|
for cell in hidden_cells:
|
|
for layer in layers:
|
|
layer.erase_cell(cell)
|
|
|
|
for pair in covers:
|
|
var sprite: Sprite2D = pair[1]
|
|
if sprite != null:
|
|
add_child(sprite)
|
|
sprite.global_position = base.to_global(base.map_to_local(pair[0]))
|
|
|
|
|
|
func _tile_layers() -> Array:
|
|
var out: Array = []
|
|
for child in get_children():
|
|
if child is TileMapLayer:
|
|
out.append(child)
|
|
return out
|
|
|
|
|
|
## 借用正下方最近一块实心墙的贴图,做成一个完全没有碰撞的 Sprite2D
|
|
func _make_cover(cell: Vector2i) -> Sprite2D:
|
|
var found := Vector2i(-1, -1)
|
|
for dy in range(1, 6):
|
|
for layer in _tile_layers():
|
|
var probe: Vector2i = cell + Vector2i(0, dy)
|
|
var source_id: int = layer.get_cell_source_id(probe)
|
|
if source_id == -1:
|
|
continue
|
|
var coords: Vector2i = layer.get_cell_atlas_coords(probe)
|
|
var source := layer.tile_set.get_source(source_id) as TileSetAtlasSource
|
|
if source == null:
|
|
continue
|
|
var data: TileData = source.get_tile_data(coords, 0)
|
|
if data != null and data.get_collision_polygons_count(0) > 0:
|
|
found = coords
|
|
break
|
|
if found.x >= 0:
|
|
break
|
|
if found.x < 0:
|
|
return null
|
|
|
|
var atlas_texture := AtlasTexture.new()
|
|
atlas_texture.atlas = ATLAS
|
|
atlas_texture.region = Rect2(found.x * TILE, found.y * TILE, TILE, TILE)
|
|
|
|
var sprite := Sprite2D.new()
|
|
sprite.texture = atlas_texture
|
|
sprite.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
|
|
sprite.z_index = cover_z_index
|
|
return sprite
|