Add example scene and update gridmap assets
Added a new example scene and player script for EnhancedGridMap. Updated mesh library, materials, and tile assets for improved visuals and structure. Modified main scene and logic to support new gridmap configuration and auto item handling. Adjusted project settings for resolution and main scene path.
This commit is contained in:
+308
-96
@@ -524,9 +524,9 @@ func handle_grid_click(grid_position: Vector2i):
|
||||
main.ActionState.GRABBING:
|
||||
if grid_position in highlighted_cells or grid_position == current_position:
|
||||
grab_item(grid_position)
|
||||
main.ActionState.PUTTING:
|
||||
if grid_position in highlighted_cells and selected_playerboard_slot != -1:
|
||||
put_item(grid_position)
|
||||
#main.ActionState.PUTTING:
|
||||
#if grid_position in highlighted_cells and selected_playerboard_slot != -1:
|
||||
#put_item(grid_position)
|
||||
main.ActionState.RANDOMIZING:
|
||||
if grid_position in highlighted_cells:
|
||||
main.randomize_item_at_position(grid_position)
|
||||
@@ -933,16 +933,63 @@ func bot_try_grab_item() -> bool:
|
||||
|
||||
return false
|
||||
|
||||
#func grab_item(grid_position: Vector2i = current_position) -> bool:
|
||||
#if is_bot:
|
||||
#return bot_try_grab_item()
|
||||
#
|
||||
#if not enhanced_gridmap or action_points <= 0:
|
||||
#return false
|
||||
#
|
||||
#var cell = Vector3i(grid_position.x, 1, grid_position.y)
|
||||
#var item = enhanced_gridmap.get_cell_item(cell)
|
||||
#
|
||||
#if grid_position != current_position:
|
||||
#var neighbors = enhanced_gridmap.get_neighbors(current_position, 0)
|
||||
#var is_adjacent = false
|
||||
#for neighbor in neighbors:
|
||||
#if neighbor.position == grid_position:
|
||||
#is_adjacent = true
|
||||
#break
|
||||
#if not is_adjacent:
|
||||
#return false
|
||||
#
|
||||
#if item == -1:
|
||||
#return false
|
||||
#
|
||||
## Bot-specific grab logic moved to bot_grab_item RPC
|
||||
#if is_in_group("Bots") or is_bot:
|
||||
#var empty_slot = playerboard.find(-1)
|
||||
#if empty_slot == -1:
|
||||
#return false
|
||||
#
|
||||
#if is_multiplayer_authority():
|
||||
#rpc("bot_grab_item", grid_position, empty_slot, cell.x, cell.y, cell.z)
|
||||
#return true
|
||||
#
|
||||
#var main = get_tree().get_root().get_node_or_null("Main")
|
||||
#if main:
|
||||
#selected_gridmap_position = grid_position
|
||||
#clear_highlights()
|
||||
#clear_playerboard_highlights()
|
||||
#
|
||||
#for i in range(playerboard.size()):
|
||||
#if playerboard[i] == -1:
|
||||
#var slot = main.playerboard_ui.get_child(i)
|
||||
#if slot.get_child_count() > 0:
|
||||
#slot.get_child(0).show()
|
||||
#highlighted_cells.append(i)
|
||||
#return true
|
||||
#
|
||||
#return false
|
||||
|
||||
func grab_item(grid_position: Vector2i = current_position) -> bool:
|
||||
if is_bot:
|
||||
return bot_try_grab_item()
|
||||
|
||||
if not enhanced_gridmap or action_points <= 0:
|
||||
return false
|
||||
|
||||
|
||||
var cell = Vector3i(grid_position.x, 1, grid_position.y)
|
||||
var item = enhanced_gridmap.get_cell_item(cell)
|
||||
|
||||
|
||||
# Validate adjacency (unless it's current position)
|
||||
if grid_position != current_position:
|
||||
var neighbors = enhanced_gridmap.get_neighbors(current_position, 0)
|
||||
var is_adjacent = false
|
||||
@@ -952,86 +999,137 @@ func grab_item(grid_position: Vector2i = current_position) -> bool:
|
||||
break
|
||||
if not is_adjacent:
|
||||
return false
|
||||
|
||||
|
||||
if item == -1:
|
||||
return false
|
||||
|
||||
# Bot-specific grab logic moved to bot_grab_item RPC
|
||||
if is_in_group("Bots") or is_bot:
|
||||
var empty_slot = playerboard.find(-1)
|
||||
if empty_slot == -1:
|
||||
return false
|
||||
|
||||
if is_multiplayer_authority():
|
||||
rpc("bot_grab_item", grid_position, empty_slot, cell.x, cell.y, cell.z)
|
||||
return true
|
||||
|
||||
var main = get_tree().get_root().get_node_or_null("Main")
|
||||
if main:
|
||||
selected_gridmap_position = grid_position
|
||||
clear_highlights()
|
||||
clear_playerboard_highlights()
|
||||
|
||||
for i in range(playerboard.size()):
|
||||
if playerboard[i] == -1:
|
||||
var slot = main.playerboard_ui.get_child(i)
|
||||
if slot.get_child_count() > 0:
|
||||
slot.get_child(0).show()
|
||||
highlighted_cells.append(i)
|
||||
return true
|
||||
|
||||
return false
|
||||
# === AUTO-ARRANGE LOGIC ===
|
||||
var target_slot = find_best_goal_slot_for_item(item)
|
||||
if target_slot == -1:
|
||||
return false # no space
|
||||
|
||||
func put_item(grid_position: Vector2i = current_position) -> bool:
|
||||
if not enhanced_gridmap or action_points <= 0 or selected_playerboard_slot == -1:
|
||||
return false
|
||||
|
||||
var cell = Vector3i(grid_position.x, 1, grid_position.y)
|
||||
if enhanced_gridmap.get_cell_item(cell) != -1:
|
||||
return false
|
||||
|
||||
# Check if position is adjacent or current position
|
||||
if grid_position != current_position:
|
||||
var is_adjacent = false
|
||||
var neighbors = enhanced_gridmap.get_neighbors(current_position, 0)
|
||||
for neighbor in neighbors:
|
||||
if neighbor.position == grid_position:
|
||||
is_adjacent = true
|
||||
break
|
||||
if not is_adjacent:
|
||||
return false
|
||||
|
||||
# Get the item to place first
|
||||
var item = playerboard[selected_playerboard_slot]
|
||||
|
||||
# For clients, we need to RPC to the server first, then let the server RPC back
|
||||
if is_multiplayer_authority() and not multiplayer.is_server():
|
||||
# Client requests server to perform the put operation
|
||||
rpc_id(1, "request_server_put", grid_position, selected_playerboard_slot, cell.x, cell.y, cell.z, item)
|
||||
|
||||
# We'll return true and let the server handle the actual operation
|
||||
# The server will RPC back to update our state if successful
|
||||
return true
|
||||
elif is_multiplayer_authority() and multiplayer.is_server():
|
||||
# Server directly implements the change
|
||||
rpc("sync_grid_item", cell.x, cell.y, cell.z, item)
|
||||
playerboard[selected_playerboard_slot] = -1
|
||||
# Perform the grab and auto-place
|
||||
if is_multiplayer_authority():
|
||||
# Update gridmap: remove item
|
||||
rpc("sync_grid_item", cell.x, cell.y, cell.z, -1)
|
||||
# Update playerboard
|
||||
playerboard[target_slot] = item
|
||||
rpc("sync_playerboard", playerboard)
|
||||
|
||||
# Consume action
|
||||
has_performed_action = true
|
||||
consume_action_points(1)
|
||||
if not is_bot == true:
|
||||
clear_highlights()
|
||||
clear_playerboard_highlights()
|
||||
selected_playerboard_slot = -1
|
||||
|
||||
|
||||
# Optional: visual feedback
|
||||
var main = get_tree().get_root().get_node_or_null("Main")
|
||||
if main:
|
||||
main.update_playerboard_ui()
|
||||
main.set_action_state(main.ActionState.NONE)
|
||||
|
||||
return true
|
||||
|
||||
# Auto-put: no manual selection needed
|
||||
# Automatically puts a goal-matching tile into an adjacent (or current) empty grid cell
|
||||
func auto_put_item() -> bool:
|
||||
if not enhanced_gridmap or action_points <= 0 or is_bot or is_in_group("Bots"):
|
||||
return false
|
||||
|
||||
# Step 1: Find empty adjacent (or current) grid cells
|
||||
var valid_put_positions = []
|
||||
# Check current position
|
||||
var current_cell_3d = Vector3i(current_position.x, 1, current_position.y)
|
||||
if enhanced_gridmap.get_cell_item(current_cell_3d) == -1:
|
||||
valid_put_positions.append(current_position)
|
||||
# Check neighbors
|
||||
var neighbors = enhanced_gridmap.get_neighbors(current_position, 0)
|
||||
for neighbor in neighbors:
|
||||
if neighbor.is_walkable:
|
||||
var pos = neighbor.position
|
||||
var cell_3d = Vector3i(pos.x, 1, pos.y)
|
||||
if enhanced_gridmap.get_cell_item(cell_3d) == -1 and not is_position_occupied(pos):
|
||||
valid_put_positions.append(pos)
|
||||
|
||||
if valid_put_positions.is_empty():
|
||||
return false
|
||||
|
||||
# Step 2: Find a playerboard tile that matches any goal
|
||||
var put_slot = -1
|
||||
for i in range(playerboard.size()):
|
||||
if playerboard[i] in goals:
|
||||
put_slot = i
|
||||
break
|
||||
|
||||
if put_slot == -1:
|
||||
return false
|
||||
|
||||
# Step 3: Perform the put
|
||||
var target_pos = valid_put_positions[0] # pick first valid
|
||||
var item = playerboard[put_slot]
|
||||
var cell = Vector3i(target_pos.x, 1, target_pos.y)
|
||||
|
||||
if is_multiplayer_authority():
|
||||
rpc("sync_grid_item", cell.x, cell.y, cell.z, item)
|
||||
playerboard[put_slot] = -1
|
||||
rpc("sync_playerboard", playerboard)
|
||||
has_performed_action = true
|
||||
consume_action_points(1)
|
||||
|
||||
var main = get_tree().get_root().get_node_or_null("Main")
|
||||
if main:
|
||||
main.set_action_state(main.ActionState.NONE)
|
||||
_after_action_completed()
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
return true
|
||||
|
||||
# Disabled logic, due the auto put
|
||||
#func put_item(grid_position: Vector2i = current_position) -> bool:
|
||||
#if not enhanced_gridmap or action_points <= 0 or selected_playerboard_slot == -1:
|
||||
#return false
|
||||
#
|
||||
#var cell = Vector3i(grid_position.x, 1, grid_position.y)
|
||||
#if enhanced_gridmap.get_cell_item(cell) != -1:
|
||||
#return false
|
||||
#
|
||||
## Check if position is adjacent or current position
|
||||
#if grid_position != current_position:
|
||||
#var is_adjacent = false
|
||||
#var neighbors = enhanced_gridmap.get_neighbors(current_position, 0)
|
||||
#for neighbor in neighbors:
|
||||
#if neighbor.position == grid_position:
|
||||
#is_adjacent = true
|
||||
#break
|
||||
#if not is_adjacent:
|
||||
#return false
|
||||
#
|
||||
## Get the item to place first
|
||||
#var item = playerboard[selected_playerboard_slot]
|
||||
#
|
||||
## For clients, we need to RPC to the server first, then let the server RPC back
|
||||
#if is_multiplayer_authority() and not multiplayer.is_server():
|
||||
## Client requests server to perform the put operation
|
||||
#rpc_id(1, "request_server_put", grid_position, selected_playerboard_slot, cell.x, cell.y, cell.z, item)
|
||||
#
|
||||
## We'll return true and let the server handle the actual operation
|
||||
## The server will RPC back to update our state if successful
|
||||
#return true
|
||||
#elif is_multiplayer_authority() and multiplayer.is_server():
|
||||
## Server directly implements the change
|
||||
#rpc("sync_grid_item", cell.x, cell.y, cell.z, item)
|
||||
#playerboard[selected_playerboard_slot] = -1
|
||||
#rpc("sync_playerboard", playerboard)
|
||||
#
|
||||
#has_performed_action = true
|
||||
#consume_action_points(1)
|
||||
#if not is_bot == true:
|
||||
#clear_highlights()
|
||||
#clear_playerboard_highlights()
|
||||
#selected_playerboard_slot = -1
|
||||
#
|
||||
#var main = get_tree().get_root().get_node_or_null("Main")
|
||||
#if main:
|
||||
#main.set_action_state(main.ActionState.NONE)
|
||||
#_after_action_completed()
|
||||
#return true
|
||||
#
|
||||
#return false
|
||||
|
||||
@rpc("any_peer", "reliable")
|
||||
func request_server_put(grid_position: Vector2i, slot_index: int, x: int, y: int, z: int, item: int):
|
||||
@@ -1092,24 +1190,23 @@ func notify_spawn_selected(spawn_pos: Vector2i):
|
||||
enhanced_gridmap.normal_items[0]
|
||||
)
|
||||
|
||||
|
||||
|
||||
func handle_put_action():
|
||||
var main = get_tree().get_root().get_node_or_null("Main")
|
||||
if not main or action_points < 1:
|
||||
return
|
||||
|
||||
if not is_bot == true:
|
||||
clear_highlights()
|
||||
clear_playerboard_highlights()
|
||||
|
||||
# Highlight non-empty slots in playerboard
|
||||
for i in range(playerboard.size()):
|
||||
if playerboard[i] != -1: # Highlight occupied slots
|
||||
var slot = main.playerboard_ui.get_child(i)
|
||||
if slot.get_child_count() > 0:
|
||||
slot.get_child(0).show() # Show highlight for occupied slots
|
||||
highlighted_cells.append(i)
|
||||
# Disabled, auto put activated
|
||||
#func handle_put_action():
|
||||
#var main = get_tree().get_root().get_node_or_null("Main")
|
||||
#if not main or action_points < 1:
|
||||
#return
|
||||
#
|
||||
#if not is_bot == true:
|
||||
#clear_highlights()
|
||||
#clear_playerboard_highlights()
|
||||
#
|
||||
## Highlight non-empty slots in playerboard
|
||||
#for i in range(playerboard.size()):
|
||||
#if playerboard[i] != -1: # Highlight occupied slots
|
||||
#var slot = main.playerboard_ui.get_child(i)
|
||||
#if slot.get_child_count() > 0:
|
||||
#slot.get_child(0).show() # Show highlight for occupied slots
|
||||
#highlighted_cells.append(i)
|
||||
|
||||
func handle_playerboard_slot_selected(slot_index: int):
|
||||
var main = get_tree().get_root().get_node_or_null("Main")
|
||||
@@ -1247,6 +1344,121 @@ func is_valid_arrangement_slot(from_slot: int, to_slot: int) -> bool:
|
||||
|
||||
return (row_diff == 1 and col_diff == 0) or (row_diff == 0 and col_diff == 1)
|
||||
|
||||
# Returns { slot_index: int, grid_position: Vector2i } or null if no valid put
|
||||
func find_best_put_candidate() -> Dictionary:
|
||||
# Convert goals to 2D (3x3)
|
||||
var goals_2d = []
|
||||
for i in range(3):
|
||||
var row = []
|
||||
for j in range(3):
|
||||
row.append(goals[i * 3 + j])
|
||||
goals_2d.append(row)
|
||||
|
||||
# Convert playerboard to 2D (5x5)
|
||||
var board_2d = []
|
||||
for i in range(5):
|
||||
var row = []
|
||||
for j in range(5):
|
||||
row.append(playerboard[i * 5 + j])
|
||||
board_2d.append(row)
|
||||
|
||||
# Step 1: Find misplaced or extra goal-matching items
|
||||
var candidate_items = []
|
||||
for board_i in range(5):
|
||||
for board_j in range(5):
|
||||
var item = board_2d[board_i][board_j]
|
||||
if item == -1:
|
||||
continue
|
||||
var board_idx = board_i * 5 + board_j
|
||||
|
||||
# Is this item part of the goals?
|
||||
if item not in goals:
|
||||
continue
|
||||
|
||||
# Is it already in the correct central position?
|
||||
var is_in_correct_central_spot = false
|
||||
if board_i in [1,2,3] and board_j in [1,2,3]:
|
||||
var goal_i = board_i - 1
|
||||
var goal_j = board_j - 1
|
||||
if goals_2d[goal_i][goal_j] == item:
|
||||
is_in_correct_central_spot = true
|
||||
|
||||
if not is_in_correct_central_spot:
|
||||
candidate_items.append({
|
||||
"slot": board_idx,
|
||||
"item": item
|
||||
})
|
||||
|
||||
# Step 2: Find valid adjacent empty grid cells
|
||||
var valid_cells = []
|
||||
# Check current position
|
||||
var current_cell_3d = Vector3i(current_position.x, 1, current_position.y)
|
||||
if enhanced_gridmap.get_cell_item(current_cell_3d) == -1:
|
||||
valid_cells.append(current_position)
|
||||
# Check neighbors
|
||||
var neighbors = enhanced_gridmap.get_neighbors(current_position, 0)
|
||||
for neighbor in neighbors:
|
||||
if neighbor.is_walkable:
|
||||
var pos = neighbor.position
|
||||
var cell_3d = Vector3i(pos.x, 1, pos.y)
|
||||
if enhanced_gridmap.get_cell_item(cell_3d) == -1 and not is_position_occupied(pos):
|
||||
valid_cells.append(pos)
|
||||
|
||||
if valid_cells.is_empty() or candidate_items.is_empty():
|
||||
return {}
|
||||
|
||||
# Step 3: Prefer to put an item that *completes* a missing goal
|
||||
for goal_i in range(3):
|
||||
for goal_j in range(3):
|
||||
var needed_item = goals_2d[goal_i][goal_j]
|
||||
if needed_item == -1:
|
||||
continue
|
||||
# Check if central spot is empty
|
||||
var board_i = goal_i + 1
|
||||
var board_j = goal_j + 1
|
||||
var central_slot = board_i * 5 + board_j
|
||||
if playerboard[central_slot] == -1:
|
||||
# Look for this item in candidate_items
|
||||
for cand in candidate_items:
|
||||
if cand.item == needed_item:
|
||||
if not valid_cells.is_empty():
|
||||
return {
|
||||
"slot_index": cand.slot,
|
||||
"grid_position": valid_cells[0] # pick first valid cell
|
||||
}
|
||||
|
||||
# Fallback: just put any candidate item
|
||||
return {
|
||||
"slot_index": candidate_items[0].slot,
|
||||
"grid_position": valid_cells[0]
|
||||
}
|
||||
|
||||
# Finds the best slot in the playerboard for a given item based on goals
|
||||
func find_best_goal_slot_for_item(item: int) -> int:
|
||||
if item == -1:
|
||||
return -1
|
||||
|
||||
# Convert goals to 2D (3x3)
|
||||
var goals_2d = []
|
||||
for i in range(3):
|
||||
var row = []
|
||||
for j in range(3):
|
||||
row.append(goals[i * 3 + j])
|
||||
goals_2d.append(row)
|
||||
|
||||
# Search for where this item should go in the central 3x3 (mapped to 5x5 board)
|
||||
for i in range(3):
|
||||
for j in range(3):
|
||||
if goals_2d[i][j] == item:
|
||||
var board_row = i + 1 # offset to center in 5x5
|
||||
var board_col = j + 1
|
||||
var slot_index = board_row * 5 + board_col
|
||||
if playerboard[slot_index] == -1: # only if empty
|
||||
return slot_index
|
||||
|
||||
# No ideal slot? Return any empty slot
|
||||
return playerboard.find(-1)
|
||||
|
||||
func get_adjacent_playerboard_slots(slot_index) -> Array:
|
||||
var adjacent = []
|
||||
var row = slot_index / 5
|
||||
|
||||
Reference in New Issue
Block a user