extends Node const TILE_SIZE := 8.0 const GRID_SIZE := 3 const ENEMY_COUNT := 3 const WIN_MESSAGE_SECONDS := 1.5 const WALL_HEIGHT := 6.0 const WALL_THICKNESS := 1.0 const PLAIN_TILES := [ preload("res://world/arena/tiles/arena_tile_plain_a.tscn"), preload("res://world/arena/tiles/arena_tile_plain_b.tscn"), preload("res://world/arena/tiles/arena_tile_plain_c.tscn"), preload("res://world/arena/tiles/arena_tile_plain_d.tscn"), ] const OBSTACLE_TILES := [ preload("res://world/arena/tiles/arena_tile_obstacle_a.tscn"), preload("res://world/arena/tiles/arena_tile_obstacle_b.tscn"), ] const ENEMY_SCENE := preload("res://world/enemy/enemy.tscn") var _current_poi: Node = null var _live_enemies: int = 0 # Baut die Arena bei jedem Aufruf komplett neu (nur eine gleichzeitig aktiv) und # teleportiert den Spieler hinein. 3x3-Raster aus den Kacheln, Mittelfeld immer # ein Boden-Stück (damit niemand auf einem Hindernis landet). func start_arena(poi: Node) -> void: _current_poi = poi var arena_root := get_tree().get_first_node_in_group("arena_root") if arena_root == null: push_error("ArenaRoot nicht gefunden! Gruppe 'arena_root' gesetzt?") return for child in arena_root.get_children(): child.queue_free() _build_walls(arena_root) var half := float(GRID_SIZE) * TILE_SIZE * 0.5 var center_index := GRID_SIZE / 2 var spawn_cells: Array[Vector3] = [] for gx in range(GRID_SIZE): for gz in range(GRID_SIZE): var is_center := gx == center_index and gz == center_index var palette := PLAIN_TILES if is_center else (PLAIN_TILES + OBSTACLE_TILES) var tile_scene: PackedScene = palette[randi() % palette.size()] var tile := tile_scene.instantiate() var local_pos := Vector3( gx * TILE_SIZE - half + TILE_SIZE * 0.5, 0.0, gz * TILE_SIZE - half + TILE_SIZE * 0.5 ) tile.position = local_pos arena_root.add_child(tile) if not is_center: spawn_cells.append(local_pos) spawn_cells.shuffle() _live_enemies = 0 for i in range(min(ENEMY_COUNT, spawn_cells.size())): var enemy := ENEMY_SCENE.instantiate() arena_root.add_child(enemy) enemy.global_position = arena_root.global_position + spawn_cells[i] + Vector3(0, 1.0, 0) _live_enemies += 1 var player := get_tree().get_first_node_in_group("player") if player: player.global_position = arena_root.global_position + Vector3(0, 1.0, 0) func on_enemy_died(enemy: Node) -> void: enemy.queue_free() _live_enemies -= 1 if _live_enemies <= 0: _on_win() func _on_win() -> void: var poi := _current_poi if poi and poi.has_method("mark_visited"): poi.mark_visited() InteractionManager.open_message(poi, "Sieg!", "Die Gegner wurden besiegt.") var timer := get_tree().create_timer(WIN_MESSAGE_SECONDS) timer.timeout.connect(_on_win_message_done) func _on_win_message_done() -> void: InteractionManager.close() var player := get_tree().get_first_node_in_group("player") if player and _current_poi: player.global_position = _current_poi.global_position + Vector3(0, 0.5, 0.6) _current_poi = null func _build_walls(arena_root: Node3D) -> void: var half := float(GRID_SIZE) * TILE_SIZE * 0.5 var barrier := StaticBody3D.new() barrier.name = "ArenaWalls" arena_root.add_child(barrier) var configs := [ {"size": Vector3(WALL_THICKNESS, WALL_HEIGHT, half * 2.0), "pos": Vector3(half, WALL_HEIGHT * 0.5, 0)}, {"size": Vector3(WALL_THICKNESS, WALL_HEIGHT, half * 2.0), "pos": Vector3(-half, WALL_HEIGHT * 0.5, 0)}, {"size": Vector3(half * 2.0, WALL_HEIGHT, WALL_THICKNESS), "pos": Vector3(0, WALL_HEIGHT * 0.5, half)}, {"size": Vector3(half * 2.0, WALL_HEIGHT, WALL_THICKNESS), "pos": Vector3(0, WALL_HEIGHT * 0.5, -half)}, ] for cfg in configs: var box := BoxShape3D.new() box.size = cfg["size"] var cs := CollisionShape3D.new() cs.shape = box cs.position = cfg["pos"] barrier.add_child(cs)