Initial commit: Godot 4.7 pixel platformer prototype
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).
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
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
|
||||
Reference in New Issue
Block a user