Files
tekton/scripts/managers/obstacle_manager.gd
T

147 lines
4.5 KiB
GDScript

extends Node
class_name ObstacleManager
# ObstacleManager - Handles static spawning of walls/blocks on the arena
const TILE_OBSTACLE = 4 # Wall
const TILE_GROUND = 0 # Standard Floor
var main: Node
var gridmap: Node
func initialize(p_main: Node, p_gridmap: Node):
main = p_main
gridmap = p_gridmap
print("[ObstacleManager] Initialized")
func spawn_random_obstacles(count: int = 15):
if not multiplayer.is_server(): return
print("[ObstacleManager] Attempting to spawn %d obstacles (Guaranteed types first)" % count)
var shapes = _get_all_shapes()
var successful_spawns = 0
# 1. First, try to spawn each shape type at least once
for shape_idx in range(shapes.size()):
var shape_attempts = 0
var shape_placed = false
while not shape_placed and shape_attempts < 20: # Give each type a fair chance
shape_attempts += 1
if spawn_random_wall(shape_idx):
shape_placed = true
successful_spawns += 1
if successful_spawns >= count: break
# 2. Then, fill the remaining count with random shapes
var total_attempts = 0
var max_attempts = count * 5
while successful_spawns < count and total_attempts < max_attempts:
total_attempts += 1
if spawn_random_wall():
successful_spawns += 1
print("[ObstacleManager] Final: Spawned %d obstacles" % successful_spawns)
# Force AStar update after all spawns
if gridmap and gridmap.has_method("initialize_astar"):
gridmap.initialize_astar()
func _get_all_shapes() -> Array:
return [
# L (3 blocks) - 4 Rotations
[Vector2i(0, 0), Vector2i(1, 0), Vector2i(0, 1)], # L - Corner Bottom Left
[Vector2i(0, 0), Vector2i(-1, 0), Vector2i(0, 1)], # L - Corner Bottom Right
[Vector2i(0, 0), Vector2i(1, 0), Vector2i(0, -1)], # L - Corner Top Left
[Vector2i(0, 0), Vector2i(-1, 0), Vector2i(0, -1)], # L - Corner Top Right
# 2 Vertical
[Vector2i(0, 0), Vector2i(0, 1)],
[Vector2i(0, 0), Vector2i(0, -1)],
# 2 Horizontal
[Vector2i(0, 0), Vector2i(1, 0)],
[Vector2i(0, 0), Vector2i(-1, 0)],
# Single
[Vector2i(0, 0)]
]
func spawn_random_wall(forced_shape_idx: int = -1) -> bool:
if not gridmap or not main: return false
var cols = gridmap.get("columns") if "columns" in gridmap else 14
var rows = gridmap.get("rows") if "rows" in gridmap else 14
# User Request: "spawn on columns 3 and so on"
if cols <= 3: return false
var x = randi_range(3, cols - 1)
var z = randi_range(0, rows - 1)
var shapes = _get_all_shapes()
var shape_idx = forced_shape_idx if forced_shape_idx != -1 else randi() % shapes.size()
var shape = shapes[shape_idx]
var wall_positions: Array[Vector3i] = []
# Validate position and check for ground
for offset in shape:
var target_x = x + offset.x
var target_z = z + offset.y
# Bounds check
if target_x >= 3 and target_x < cols and target_z >= 0 and target_z < rows:
var current_item = gridmap.get_cell_item(Vector3i(target_x, 0, target_z))
# Only spawn on ground (0) to avoid replacing other obstacles or special tiles
if current_item == TILE_GROUND:
# PLAYER CHECK: Ensure no player is on this tile
var is_occupied = false
for player in get_tree().get_nodes_in_group("Players"):
if player.get("current_position") == Vector2i(target_x, target_z):
is_occupied = true
break
if is_occupied: return false
# ADJACENCY CHECK: Ensure no existing walls are nearby
if not _is_position_isolated(target_x, target_z, shape, x, z):
return false
wall_positions.append(Vector3i(target_x, 0, target_z))
else:
# If any block of the shape hits a non-ground tile, fail the whole shape for clean placement
return false
else:
return false
# Only proceed if we can place the full shape
if wall_positions.is_empty():
return false
# Create walls on all clients (Permanent, no despawn)
for pos in wall_positions:
main.rpc("sync_grid_item", pos.x, pos.y, pos.z, TILE_OBSTACLE)
return true
func _is_position_isolated(target_x: int, target_z: int, shape_offsets: Array, origin_x: int, origin_z: int) -> bool:
# Check 3x3 area
for dx in range(-1, 2):
for dz in range(-1, 2):
if dx == 0 and dz == 0: continue
var nx = target_x + dx
var nz = target_z + dz
# Check if this neighbor is part of the shape we are currently placing
var is_part_of_shape = false
for offset in shape_offsets:
if nx == origin_x + offset.x and nz == origin_z + offset.y:
is_part_of_shape = true
break
if is_part_of_shape: continue
# Check if gridmap has a wall at this neighbor
if gridmap.get_cell_item(Vector3i(nx, 0, nz)) == TILE_OBSTACLE:
return false
return true