feat: Add main game scene script with manager initialization, UI setup, multiplayer logic, and game mode specific configurations.
This commit is contained in:
+81
-22
@@ -523,11 +523,14 @@ func _setup_host_game():
|
|||||||
print("Spawning lobby player: ", peer_id)
|
print("Spawning lobby player: ", peer_id)
|
||||||
_spawn_lobby_client_sync(peer_id)
|
_spawn_lobby_client_sync(peer_id)
|
||||||
|
|
||||||
# 1. PVT: Pre-calculate Static Tekton positions so we know where NOT to spawn players
|
# Spawning and arena setup
|
||||||
|
if LobbyManager.game_mode == "Stop n Go" and stop_n_go_manager:
|
||||||
|
stop_n_go_manager._setup_arena()
|
||||||
|
elif LobbyManager.game_mode == "Tekton Doors" and portal_mode_manager:
|
||||||
|
portal_mode_manager.setup_arena_locally()
|
||||||
|
|
||||||
|
# 1. PVT: Pre-calculate Static Tekton positions AFTER arena size is known
|
||||||
_precalculate_static_positions()
|
_precalculate_static_positions()
|
||||||
|
|
||||||
# Delay spawn assignment until ALL players (including bots) are spawned
|
|
||||||
# Moved _assign_random_spawn_positions() to after bot loop
|
|
||||||
|
|
||||||
# Wait for players to be fully ready (player.gd has 0.1s await in _ready before managers init)
|
# Wait for players to be fully ready (player.gd has 0.1s await in _ready before managers init)
|
||||||
# Faster for LAN mode
|
# Faster for LAN mode
|
||||||
@@ -565,14 +568,6 @@ func _setup_host_game():
|
|||||||
# Ensure Bots are in the tree before assigning positions
|
# Ensure Bots are in the tree before assigning positions
|
||||||
await get_tree().process_frame
|
await get_tree().process_frame
|
||||||
|
|
||||||
# INITIALIZE ARENA SIZE for Stop n Go BEFORE spawning players, to prevent out-of-bounds
|
|
||||||
if LobbyManager.game_mode == "Stop n Go" and stop_n_go_manager:
|
|
||||||
stop_n_go_manager._setup_arena()
|
|
||||||
|
|
||||||
# Arena is set up, wait for __start_game to assign positions where Socket is open
|
|
||||||
if LobbyManager.game_mode == "Tekton Doors" and portal_mode_manager:
|
|
||||||
portal_mode_manager.setup_arena_locally()
|
|
||||||
|
|
||||||
_start_game()
|
_start_game()
|
||||||
|
|
||||||
func _spawn_lobby_client_sync(peer_id: int):
|
func _spawn_lobby_client_sync(peer_id: int):
|
||||||
@@ -813,10 +808,10 @@ func _assign_random_spawn_positions():
|
|||||||
var pos = Vector2i(x, z)
|
var pos = Vector2i(x, z)
|
||||||
|
|
||||||
# SAFETY CHECK: Is this reserved for a Static Tekton Stand?
|
# SAFETY CHECK: Is this reserved for a Static Tekton Stand?
|
||||||
# Stand covers [center-1, center+1]
|
# Stand clears 3x3, but we use a radius of 2 (5x5) for safety
|
||||||
var is_safe = true
|
var is_safe = true
|
||||||
for reserved in reserved_static_positions:
|
for reserved in reserved_static_positions:
|
||||||
if abs(x - reserved.x) <= 1 and abs(z - reserved.y) <= 1:
|
if abs(x - reserved.x) <= 2 and abs(z - reserved.y) <= 2:
|
||||||
is_safe = false
|
is_safe = false
|
||||||
break
|
break
|
||||||
|
|
||||||
@@ -924,7 +919,7 @@ func _assign_stop_n_go_spawn_positions(all_players: Array):
|
|||||||
print("[StopNGo] Assigned spawn %s to player %s" % [assigned_pos, player.name])
|
print("[StopNGo] Assigned spawn %s to player %s" % [assigned_pos, player.name])
|
||||||
|
|
||||||
func _assign_portal_mode_spawn_positions(all_players: Array):
|
func _assign_portal_mode_spawn_positions(all_players: Array):
|
||||||
"""Assigns spawns to different quadrants for Tekton Doors mode."""
|
"""Assigns spawns to different quadrants for Tekton Doors mode, avoiding stands and intersections."""
|
||||||
if not portal_mode_manager:
|
if not portal_mode_manager:
|
||||||
_assign_random_spawn_positions() # Fallback
|
_assign_random_spawn_positions() # Fallback
|
||||||
return
|
return
|
||||||
@@ -932,13 +927,57 @@ func _assign_portal_mode_spawn_positions(all_players: Array):
|
|||||||
# Sort players for deterministic assignment
|
# Sort players for deterministic assignment
|
||||||
all_players.sort_custom(func(a, b): return a.name.to_int() < b.name.to_int())
|
all_players.sort_custom(func(a, b): return a.name.to_int() < b.name.to_int())
|
||||||
|
|
||||||
var spawn_points = portal_mode_manager.get_spawn_points()
|
# Get baseline quadrant centers (3,3), (10,3), etc.
|
||||||
|
var base_spawn_points = portal_mode_manager.get_spawn_points()
|
||||||
var spawn_index = 0
|
var spawn_index = 0
|
||||||
|
var assigned_positions: Array[Vector2i] = []
|
||||||
|
|
||||||
for player in all_players:
|
for player in all_players:
|
||||||
var assigned_pos = spawn_points[spawn_index % spawn_points.size()]
|
var center_pos = base_spawn_points[spawn_index % base_spawn_points.size()]
|
||||||
|
var assigned_pos = center_pos # Fallback position
|
||||||
|
|
||||||
# Sync
|
# Spiral search for a valid spot (walkable, not in stand zone, not occupied)
|
||||||
|
var found = false
|
||||||
|
for radius in range(0, 5): # Increase search radius
|
||||||
|
for dx in range(-radius, radius + 1):
|
||||||
|
for dz in range(-radius, radius + 1):
|
||||||
|
# Only check the "ring" at the current radius
|
||||||
|
if abs(dx) != radius and abs(dz) != radius and radius > 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
var test_pos = center_pos + Vector2i(dx, dz)
|
||||||
|
|
||||||
|
# 1. Check map bounds
|
||||||
|
var em = $EnhancedGridMap
|
||||||
|
if not em or test_pos.x < 0 or test_pos.x >= em.columns or test_pos.y < 0 or test_pos.y >= em.rows:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 2. Check if walkable floor (Floor 0, ID 0)
|
||||||
|
if em.get_cell_item(Vector3i(test_pos.x, 0, test_pos.y)) != 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 3. Check if reserved for a Static Tekton Stand (3x3 area, use 2-tile buffer)
|
||||||
|
var is_reserved = false
|
||||||
|
for reserved in reserved_static_positions:
|
||||||
|
if abs(test_pos.x - reserved.x) <= 2 and abs(test_pos.y - reserved.y) <= 2:
|
||||||
|
is_reserved = true
|
||||||
|
break
|
||||||
|
if is_reserved:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 4. Check if occupied by another already-assigned player
|
||||||
|
if assigned_positions.has(test_pos):
|
||||||
|
continue
|
||||||
|
|
||||||
|
assigned_pos = test_pos
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
if found: break
|
||||||
|
if found: break
|
||||||
|
|
||||||
|
assigned_positions.append(assigned_pos)
|
||||||
|
|
||||||
|
# Sync and place
|
||||||
player.position = player.grid_to_world(assigned_pos)
|
player.position = player.grid_to_world(assigned_pos)
|
||||||
player.current_position = assigned_pos
|
player.current_position = assigned_pos
|
||||||
player.is_player_moving = false
|
player.is_player_moving = false
|
||||||
@@ -948,7 +987,7 @@ func _assign_portal_mode_spawn_positions(all_players: Array):
|
|||||||
player.rpc("set_spawn_position", assigned_pos)
|
player.rpc("set_spawn_position", assigned_pos)
|
||||||
|
|
||||||
spawn_index += 1
|
spawn_index += 1
|
||||||
print("[PortalMode] Assigned Room Quadrant %s to player %s" % [assigned_pos, player.name])
|
print("[PortalMode] Assigned Quadrant Pos %s to player %s" % [assigned_pos, player.name])
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# Tekton NPC Management
|
# Tekton NPC Management
|
||||||
@@ -1072,12 +1111,25 @@ func spawn_static_tektons():
|
|||||||
if not static_tekton_manager:
|
if not static_tekton_manager:
|
||||||
static_tekton_manager = StaticTektonManager.new()
|
static_tekton_manager = StaticTektonManager.new()
|
||||||
|
|
||||||
# Use pre-calculated points if available, otherwise calculate new ones
|
# Use pre-calculated points if available
|
||||||
var spawn_points = []
|
var spawn_points: Array[Vector2i] = []
|
||||||
if not reserved_static_positions.is_empty():
|
if not reserved_static_positions.is_empty():
|
||||||
spawn_points = reserved_static_positions
|
spawn_points = reserved_static_positions
|
||||||
else:
|
else:
|
||||||
spawn_points = static_tekton_manager.calculate_spawn_points(3, enhanced_gridmap)
|
# If pre-calculation failed, we MUST check for player overlaps now
|
||||||
|
var raw_points = static_tekton_manager.calculate_spawn_points(3, enhanced_gridmap)
|
||||||
|
var all_players = get_tree().get_nodes_in_group("Players")
|
||||||
|
|
||||||
|
for p_spot in raw_points:
|
||||||
|
var is_overlapping = false
|
||||||
|
for player in all_players:
|
||||||
|
if abs(p_spot.x - player.current_position.x) <= 2 and abs(p_spot.y - player.current_position.y) <= 2:
|
||||||
|
is_overlapping = true
|
||||||
|
break
|
||||||
|
if not is_overlapping:
|
||||||
|
spawn_points.append(p_spot)
|
||||||
|
|
||||||
|
reserved_static_positions = spawn_points # Save them
|
||||||
|
|
||||||
print("[Main] Spawning Static Tektons at: %s" % str(spawn_points))
|
print("[Main] Spawning Static Tektons at: %s" % str(spawn_points))
|
||||||
|
|
||||||
@@ -1682,6 +1734,13 @@ func randomize_game_grid():
|
|||||||
|
|
||||||
var enhanced_gridmap = $EnhancedGridMap
|
var enhanced_gridmap = $EnhancedGridMap
|
||||||
if enhanced_gridmap:
|
if enhanced_gridmap:
|
||||||
|
# FIRST: Ensure Floor 0 is entirely filled with walkable ground (ID 0)
|
||||||
|
# This ensures StaticTektonManager calculation (which checks Floor 0) succeeds.
|
||||||
|
for x in range(enhanced_gridmap.columns):
|
||||||
|
for z in range(enhanced_gridmap.rows):
|
||||||
|
if enhanced_gridmap.get_cell_item(Vector3i(x, 0, z)) == -1:
|
||||||
|
enhanced_gridmap.set_cell_item(Vector3i(x, 0, z), 0)
|
||||||
|
|
||||||
# Custom spawn ratio for Free Mode: 80% common tiles, 20% empty tiles (start of game)
|
# Custom spawn ratio for Free Mode: 80% common tiles, 20% empty tiles (start of game)
|
||||||
var density_callable = func():
|
var density_callable = func():
|
||||||
if randf() <= 0.8:
|
if randf() <= 0.8:
|
||||||
|
|||||||
Reference in New Issue
Block a user