Files
go-a-dot/playground/levels/playground_level_base.gd

93 lines
2.6 KiB
GDScript

@tool
class_name PlaygroundLevel
extends Area2D
@export var show_bounds: bool = true
@export var bounds_color: Color = Color.RED
@export var bounds_width: float = 2.0
@export var editor_only: bool = true
signal entered(level: PlaygroundLevel)
signal exited(level: PlaygroundLevel)
var tilemap_layer: TileMapLayer
var tilemap_bounds: Rect2
var last_used_cells_count: int = -1
func _enter_tree() -> void:
if Engine.is_editor_hint():
set_process_mode(Node.PROCESS_MODE_PAUSABLE)
#call_deferred("_ready")
func _ready() -> void:
tilemap_layer = $TileMapLayer
update_bounds()
update_collision_shape()
func update_collision_shape() -> void:
var collision_shape = $CollisionShape2D
# 确保 Shape 是唯一的,防止多个关卡实例共享同一个资源
if collision_shape.shape and !collision_shape.shape.is_local_to_scene():
collision_shape.shape = collision_shape.shape.duplicate()
collision_shape.shape.size = tilemap_bounds.size
# bounds 已经是局部坐标,直接使用中心点即可,不需要减去 position
collision_shape.position = tilemap_bounds.get_center()
print("[", name, "] Collision shape updated: size=", tilemap_bounds.size, " position=", collision_shape.position)
func _process(_delta) -> void:
if update_bounds():
update_collision_shape()
if enable_debug_draw():
queue_redraw()
func update_bounds() -> bool:
var used_rect: Rect2i = tilemap_layer.get_used_rect()
var used_cells_count = tilemap_layer.get_used_cells().size()
last_used_cells_count = used_cells_count
var tile_size = tilemap_layer.tile_set.tile_size
var position_offset = tilemap_layer.position
var bounds = Rect2(
position_offset + Vector2(used_rect.position * tile_size),
used_rect.size * tile_size
)
var changed = bounds != tilemap_bounds
tilemap_bounds = bounds
if changed:
print("[", name, "] Bounds updated: ", bounds)
return changed
func enable_debug_draw() -> bool:
return show_bounds && (!editor_only || Engine.is_editor_hint())
func _draw() -> void:
if enable_debug_draw():
draw_rect(tilemap_bounds, bounds_color, false, bounds_width)
func get_global_bounds() -> Rect2:
var global_bounds = tilemap_bounds
global_bounds.position += global_position
return global_bounds
func _on_area_entered(area: Area2D) -> void:
if area.name != "Player":
return
print("[", name, "] Player entered level bounds!")
print(" - Area: ", area.name)
entered.emit(self)
func _on_area_exited(area: Area2D) -> void:
if area.name != "Player":
return
print("[", name, "] Player exited level bounds!")
print(" - Area: ", area.name)
exited.emit(self)