93 lines
2.6 KiB
GDScript
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)
|