feat: Introduce an enhanced gridmap addon with procedural generation, pathfinding, and initial core game scripts and assets.
This commit is contained in:
@@ -52,7 +52,11 @@ func _ready():
|
||||
if auto_generate:
|
||||
generate_grid()
|
||||
if auto_randomize:
|
||||
randomize_grid()
|
||||
# Safety check: Don't auto-randomize if game mode manages its own arena
|
||||
if not (ResourceLoader.exists("res://scripts/managers/lobby_manager.gd") \
|
||||
and get_node_or_null("/root/LobbyManager") \
|
||||
and get_node("/root/LobbyManager").game_mode == "Stop n Go"):
|
||||
randomize_grid()
|
||||
validate_item_indices()
|
||||
|
||||
# Core grid management functions
|
||||
@@ -276,9 +280,9 @@ func randomize_floor(floor_index: int, custom_rng_callable: Callable = Callable(
|
||||
if current_item_on_floor in immutable_items:
|
||||
continue
|
||||
|
||||
# IMPORTANT: Only place items if Floor 0 has a walkable tile
|
||||
# IMPORTANT: Only place items if Floor 0 has a valid ground tile (Walkable, Safe Zone, etc)
|
||||
var floor_0_item = get_cell_item(Vector3i(x, 0, z))
|
||||
var is_ground = (floor_0_item == normal_items[0]) # Assuming 0 is ground
|
||||
var is_ground = (floor_0_item != -1) # All tiles on Layer 0 are valid ground
|
||||
|
||||
if not is_ground:
|
||||
set_cell_item(Vector3i(x, floor_index, z), -1) # Clear item if no ground
|
||||
@@ -564,25 +568,29 @@ func find_path(start: Vector2, end: Vector2, floor_index: int = 0, clear_path_vi
|
||||
|
||||
path = astar.get_point_path(start_point, end_point)
|
||||
|
||||
# TEMPORARY PATH VISUALIZATION - Moved to Layer 2 (Overlay) to protect Floor 0 and Floor 1
|
||||
if visualize:
|
||||
if clear_path_visual:
|
||||
clear_path_visualization(floor_index)
|
||||
clear_path_visualization()
|
||||
|
||||
set_cell_item(Vector3i(start.x, floor_index, start.y), start_item)
|
||||
set_cell_item(Vector3i(end.x, floor_index, end.y), end_item)
|
||||
# Always use Layer 2 for these temporary markers
|
||||
set_cell_item(Vector3i(start.x, 2, start.y), start_item)
|
||||
set_cell_item(Vector3i(end.x, 2, end.y), end_item)
|
||||
for point in path:
|
||||
if point != start and point != end:
|
||||
set_cell_item(Vector3i(point.x, floor_index, point.y), hover_item)
|
||||
if Vector2(point.x, point.y) != start and Vector2(point.x, point.y) != end:
|
||||
set_cell_item(Vector3i(point.x, 2, point.y), hover_item)
|
||||
|
||||
return path
|
||||
|
||||
# Path visualization
|
||||
func clear_path_visualization(floor_index: int = 0):
|
||||
# Path visualization - Standardized to Layer 2
|
||||
func clear_path_visualization(unused_floor_idx: int = 0):
|
||||
# We strictly clear Layer 2 (Overlay) and reset to -1 (Empty)
|
||||
# This ensures we never overwrite Layer 0 (Floor) or Layer 1 (Items)
|
||||
for x in range(columns):
|
||||
for z in range(rows):
|
||||
var cell_item = get_cell_item(Vector3i(x, floor_index, z))
|
||||
var cell_item = get_cell_item(Vector3i(x, 2, z))
|
||||
if cell_item == hover_item or cell_item == start_item or cell_item == end_item:
|
||||
set_cell_item(Vector3i(x, floor_index, z), normal_items[0])
|
||||
set_cell_item(Vector3i(x, 2, z), -1)
|
||||
|
||||
# Cost calculation and updates
|
||||
func get_cell_cost(x: int, z: int, floor_index: int = 0) -> float:
|
||||
|
||||
Binary file not shown.
@@ -3,5 +3,5 @@
|
||||
[resource]
|
||||
resource_name = "tile_a1"
|
||||
cull_mode = 2
|
||||
albedo_color = Color(0.380392, 0.372549, 0.333333, 1)
|
||||
albedo_color = Color(0.38039216, 1, 0.33333334, 1)
|
||||
roughness = 0.5
|
||||
|
||||
+15
-1
@@ -444,7 +444,11 @@ func _setup_client_game():
|
||||
print("Client setup - my peer ID: ", my_id)
|
||||
|
||||
# INITIALIZE ARENA SIZE for Stop n Go locally to prevent out-of-bounds before sync arrives
|
||||
if LobbyManager.game_mode == "Stop n Go" and stop_n_go_manager:
|
||||
if LobbyManager.game_mode == "Stop n Go":
|
||||
if not stop_n_go_manager:
|
||||
stop_n_go_manager = load("res://scripts/managers/stop_n_go_manager.gd").new()
|
||||
stop_n_go_manager.name = "StopNGoManager"
|
||||
add_child(stop_n_go_manager)
|
||||
stop_n_go_manager._apply_arena_setup()
|
||||
|
||||
# Pre-spawn ALL players known from LobbyManager (including Host ID 1)
|
||||
@@ -1503,9 +1507,19 @@ func sync_full_grid_data(data: PackedInt32Array):
|
||||
if not enhanced_gridmap:
|
||||
print("[Main] Error: EnhancedGridMap not found!")
|
||||
return
|
||||
|
||||
# Reapply deterministic Floor 0 before syncing Floor 1 items
|
||||
if LobbyManager.game_mode == "Stop n Go":
|
||||
if not stop_n_go_manager:
|
||||
stop_n_go_manager = load("res://scripts/managers/stop_n_go_manager.gd").new()
|
||||
stop_n_go_manager.name = "StopNGoManager"
|
||||
add_child(stop_n_go_manager)
|
||||
stop_n_go_manager._apply_arena_setup()
|
||||
|
||||
# Apply the synced data to Floor 1
|
||||
enhanced_gridmap.set_floor_data(1, data)
|
||||
enhanced_gridmap.update_grid_data()
|
||||
enhanced_gridmap.initialize_astar()
|
||||
print("[Main] Grid sync complete.")
|
||||
|
||||
|
||||
|
||||
+9
-9
@@ -559,9 +559,10 @@ func receive_spawn_positions_update(occupied_positions: Array):
|
||||
if pos in occupied_positions:
|
||||
highlighted_spawn_points.erase(pos)
|
||||
if enhanced_gridmap:
|
||||
# Clear the highlight from Layer 2 (Overlay) instead of overwriting Floor 0
|
||||
enhanced_gridmap.set_cell_item(
|
||||
Vector3i(pos.x, 0, pos.y),
|
||||
enhanced_gridmap.normal_items[0]
|
||||
Vector3i(pos.x, 2, pos.y),
|
||||
-1
|
||||
)
|
||||
|
||||
# Now highlight available positions
|
||||
@@ -1141,11 +1142,10 @@ func clear_spawn_highlights():
|
||||
# Clear the highlighted spawn points array
|
||||
for spawn_pos in highlighted_spawn_points:
|
||||
if enhanced_gridmap:
|
||||
# Reset the cell to its original state
|
||||
var cell_item = enhanced_gridmap.get_cell_item(Vector3i(spawn_pos.x, 1, spawn_pos.y))
|
||||
# Clear Layer 2 (Overlay Highlight) instead of potentially overwriting Layer 0
|
||||
enhanced_gridmap.set_cell_item(
|
||||
Vector3i(spawn_pos.x, 0, spawn_pos.y),
|
||||
enhanced_gridmap.normal_items[0] if cell_item != -1 else -1
|
||||
Vector3i(spawn_pos.x, 2, spawn_pos.y),
|
||||
-1
|
||||
)
|
||||
|
||||
# Clear the array
|
||||
@@ -1662,11 +1662,11 @@ func notify_spawn_selected(spawn_pos: Vector2i):
|
||||
if spawn_pos in highlighted_spawn_points:
|
||||
highlighted_spawn_points.erase(spawn_pos)
|
||||
|
||||
# Clear highlight for the selected position
|
||||
# Clear highlight for the selected position on Layer 2 (Overlay)
|
||||
if enhanced_gridmap:
|
||||
enhanced_gridmap.set_cell_item(
|
||||
Vector3i(spawn_pos.x, 0, spawn_pos.y),
|
||||
enhanced_gridmap.normal_items[0]
|
||||
Vector3i(spawn_pos.x, 2, spawn_pos.y),
|
||||
-1
|
||||
)
|
||||
|
||||
# Disabled, auto put activated
|
||||
|
||||
@@ -105,7 +105,7 @@ func highlight_empty_adjacent_cells():
|
||||
var current_cell = Vector3i(player.current_position.x, 1, player.current_position.y)
|
||||
if enhanced_gridmap.get_cell_item(current_cell) == -1:
|
||||
highlighted_cells.append(player.current_position)
|
||||
enhanced_gridmap.set_cell_item(Vector3i(player.current_position.x, 0, player.current_position.y),
|
||||
enhanced_gridmap.set_cell_item(Vector3i(player.current_position.x, 2, player.current_position.y),
|
||||
enhanced_gridmap.hover_item)
|
||||
print("Highlighted current position: ", player.current_position)
|
||||
|
||||
@@ -117,7 +117,7 @@ func highlight_empty_adjacent_cells():
|
||||
var cell = Vector3i(cell_pos.x, 1, cell_pos.y)
|
||||
if enhanced_gridmap.get_cell_item(cell) == -1: # Check if cell is empty
|
||||
highlighted_cells.append(cell_pos)
|
||||
enhanced_gridmap.set_cell_item(Vector3i(cell_pos.x, 0, cell_pos.y),
|
||||
enhanced_gridmap.set_cell_item(Vector3i(cell_pos.x, 2, cell_pos.y),
|
||||
enhanced_gridmap.hover_item)
|
||||
print("Highlighted adjacent cell: ", cell_pos)
|
||||
|
||||
@@ -132,7 +132,7 @@ func highlight_random_valid_cells():
|
||||
var current_item = enhanced_gridmap.get_cell_item(current_cell)
|
||||
if current_item != -1:
|
||||
highlighted_cells.append(player.current_position)
|
||||
enhanced_gridmap.set_cell_item(Vector3i(player.current_position.x, 0, player.current_position.y),
|
||||
enhanced_gridmap.set_cell_item(Vector3i(player.current_position.x, 2, player.current_position.y),
|
||||
enhanced_gridmap.hover_item)
|
||||
|
||||
# Then check all adjacent cells for items
|
||||
@@ -143,7 +143,7 @@ func highlight_random_valid_cells():
|
||||
var cell = Vector3i(cell_pos.x, 1, cell_pos.y)
|
||||
if enhanced_gridmap.get_cell_item(cell) != -1: # Only highlight cells with items
|
||||
highlighted_cells.append(cell_pos)
|
||||
enhanced_gridmap.set_cell_item(Vector3i(cell_pos.x, 0, cell_pos.y),
|
||||
enhanced_gridmap.set_cell_item(Vector3i(cell_pos.x, 2, cell_pos.y),
|
||||
enhanced_gridmap.hover_item)
|
||||
|
||||
func highlight_occupied_playerboard_slots():
|
||||
@@ -196,12 +196,6 @@ func clear_highlights():
|
||||
# Safest is to check against hover_id or typical highlight IDs.
|
||||
if l2_item != -1:
|
||||
enhanced_gridmap.set_cell_item(l2_pos, -1)
|
||||
|
||||
# Check Layer 0 (Floor Highlight)
|
||||
var l0_pos = Vector3i(cell.x, 0, cell.y)
|
||||
var l0_item = enhanced_gridmap.get_cell_item(l0_pos)
|
||||
if l0_item == hover_id:
|
||||
enhanced_gridmap.set_cell_item(l0_pos, enhanced_gridmap.normal_items[0])
|
||||
|
||||
highlighted_cells.clear()
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ var finish_line_x: int = 21 # Right side of the map for win condition
|
||||
|
||||
# Tile IDs
|
||||
const TILE_WALKABLE = 0
|
||||
const TILE_START = 2 # Start Line
|
||||
const TILE_SAFE = 2 # Green Safe Zone
|
||||
const TILE_OBSTACLE = 4 # Wall
|
||||
|
||||
@@ -162,7 +163,9 @@ func sync_phase(phase_name: String, duration: float):
|
||||
phase_timer = duration
|
||||
|
||||
func _setup_arena():
|
||||
var gridmap = get_node("/root/Main/EnhancedGridMap")
|
||||
var gridmap = get_parent().get_node_or_null("EnhancedGridMap")
|
||||
if not gridmap:
|
||||
gridmap = get_node_or_null("/root/Main/EnhancedGridMap")
|
||||
if not gridmap: return
|
||||
|
||||
print("[StopNGo] Setting up 22x10 Arena with Randomized Obstacles...")
|
||||
@@ -181,7 +184,10 @@ func sync_arena_setup():
|
||||
|
||||
func _apply_arena_setup():
|
||||
# Shared logic for resizing and clearing
|
||||
var gridmap = get_node("/root/Main/EnhancedGridMap")
|
||||
var gridmap = get_parent().get_node_or_null("EnhancedGridMap")
|
||||
if not gridmap:
|
||||
# Fallback just in case
|
||||
gridmap = get_node_or_null("/root/Main/EnhancedGridMap")
|
||||
if not gridmap: return
|
||||
|
||||
# Set Size for Stop n Go explicitly, bypassing setters that wipe the map
|
||||
@@ -197,7 +203,9 @@ func _apply_arena_setup():
|
||||
# Create bands based on X (Horizontal Progress)
|
||||
for x in range(gridmap.columns):
|
||||
var tile_id = TILE_WALKABLE
|
||||
if x in safe_columns:
|
||||
if x == 0:
|
||||
tile_id = TILE_START
|
||||
elif x in safe_columns:
|
||||
tile_id = TILE_SAFE
|
||||
|
||||
for z in range(gridmap.rows):
|
||||
@@ -251,7 +259,10 @@ func _apply_arena_setup():
|
||||
# by sync_grid_item inside _spawn_mission_tiles.
|
||||
|
||||
func _spawn_mission_tiles():
|
||||
var gridmap = get_node("/root/Main/EnhancedGridMap")
|
||||
var gridmap = get_parent().get_node_or_null("EnhancedGridMap")
|
||||
if not gridmap:
|
||||
gridmap = get_node_or_null("/root/Main/EnhancedGridMap")
|
||||
if not gridmap: return
|
||||
|
||||
# Tile IDs for missions: Heart(7), Diamond(8), Star(9), Coin(10)
|
||||
var mission_tiles = [7, 8, 9, 10]
|
||||
@@ -297,8 +308,9 @@ func sync_missions(missions: Dictionary):
|
||||
func check_movement_violation(player_id: int, from: Vector2i, to: Vector2i) -> bool:
|
||||
"""Check if movement is illegal (during STOP phase and not in safe zone)."""
|
||||
if current_phase == Phase.STOP:
|
||||
var main = get_node("/root/Main")
|
||||
var gridmap = main.get_node("EnhancedGridMap") if main else null
|
||||
var gridmap = get_parent().get_node_or_null("EnhancedGridMap")
|
||||
if not gridmap:
|
||||
gridmap = get_node_or_null("/root/Main/EnhancedGridMap")
|
||||
if gridmap:
|
||||
# Check FROM position. If you were safe, you can move?
|
||||
# Rules: "If a player moves during this phase".
|
||||
|
||||
Reference in New Issue
Block a user