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:
+22
-12
@@ -141,10 +141,14 @@ func connection_verify(expected_players: Array):
|
|||||||
func setup_action_buttons():
|
func setup_action_buttons():
|
||||||
move_button.pressed.connect(func(): set_action_state(ActionState.MOVING))
|
move_button.pressed.connect(func(): set_action_state(ActionState.MOVING))
|
||||||
grab_button.pressed.connect(func(): set_action_state(ActionState.GRABBING))
|
grab_button.pressed.connect(func(): set_action_state(ActionState.GRABBING))
|
||||||
|
#put_button.pressed.connect(func():
|
||||||
|
#if local_player_character:
|
||||||
|
#local_player_character.handle_put_action()
|
||||||
|
#set_action_state(ActionState.PUTTING)
|
||||||
|
#)
|
||||||
put_button.pressed.connect(func():
|
put_button.pressed.connect(func():
|
||||||
if local_player_character:
|
if local_player_character:
|
||||||
local_player_character.handle_put_action()
|
local_player_character.auto_put_item()
|
||||||
set_action_state(ActionState.PUTTING)
|
|
||||||
)
|
)
|
||||||
randomize_button.pressed.connect(func(): set_action_state(ActionState.RANDOMIZING))
|
randomize_button.pressed.connect(func(): set_action_state(ActionState.RANDOMIZING))
|
||||||
arrange_button.pressed.connect(func():
|
arrange_button.pressed.connect(func():
|
||||||
@@ -210,12 +214,15 @@ func set_action_state(new_state):
|
|||||||
local_player_character.highlight_movement_range()
|
local_player_character.highlight_movement_range()
|
||||||
ActionState.GRABBING:
|
ActionState.GRABBING:
|
||||||
local_player_character.highlight_adjacent_cells()
|
local_player_character.highlight_adjacent_cells()
|
||||||
if local_player_character.has_item_at_current_position():
|
|
||||||
local_player_character.highlighted_cells.append(local_player_character.current_position)
|
# Deactivated since, using Auto Grabber
|
||||||
local_player_character.enhanced_gridmap.set_cell_item(
|
|
||||||
Vector3i(local_player_character.current_position.x, 0, local_player_character.current_position.y),
|
#if local_player_character.has_item_at_current_position():
|
||||||
local_player_character.enhanced_gridmap.hover_item
|
#local_player_character.highlighted_cells.append(local_player_character.current_position)
|
||||||
)
|
#local_player_character.enhanced_gridmap.set_cell_item(
|
||||||
|
#Vector3i(local_player_character.current_position.x, 0, local_player_character.current_position.y),
|
||||||
|
#local_player_character.enhanced_gridmap.hover_item
|
||||||
|
#)
|
||||||
ActionState.PUTTING:
|
ActionState.PUTTING:
|
||||||
local_player_character.highlight_occupied_playerboard_slots()
|
local_player_character.highlight_occupied_playerboard_slots()
|
||||||
# Make sure this is client-friendly
|
# Make sure this is client-friendly
|
||||||
@@ -318,10 +325,13 @@ func _on_playerboard_slot_clicked(event, slot_index):
|
|||||||
match current_action_state:
|
match current_action_state:
|
||||||
ActionState.ARRANGING:
|
ActionState.ARRANGING:
|
||||||
local_player_character.arrange_playerboard_item(slot_index)
|
local_player_character.arrange_playerboard_item(slot_index)
|
||||||
ActionState.GRABBING:
|
|
||||||
local_player_character.handle_playerboard_slot_selected(slot_index)
|
# Deactivated since we're using auto grab
|
||||||
ActionState.PUTTING:
|
#ActionState.GRABBING:
|
||||||
local_player_character.handle_put_slot_selected(slot_index)
|
#local_player_character.handle_playerboard_slot_selected(slot_index)
|
||||||
|
# Deactivated since we're using auto put
|
||||||
|
#ActionState.PUTTING:
|
||||||
|
#local_player_character.handle_put_slot_selected(slot_index)
|
||||||
|
|
||||||
func update_playerboard_ui():
|
func update_playerboard_ui():
|
||||||
if not local_player_character:
|
if not local_player_character:
|
||||||
|
|||||||
+303
-91
@@ -524,9 +524,9 @@ func handle_grid_click(grid_position: Vector2i):
|
|||||||
main.ActionState.GRABBING:
|
main.ActionState.GRABBING:
|
||||||
if grid_position in highlighted_cells or grid_position == current_position:
|
if grid_position in highlighted_cells or grid_position == current_position:
|
||||||
grab_item(grid_position)
|
grab_item(grid_position)
|
||||||
main.ActionState.PUTTING:
|
#main.ActionState.PUTTING:
|
||||||
if grid_position in highlighted_cells and selected_playerboard_slot != -1:
|
#if grid_position in highlighted_cells and selected_playerboard_slot != -1:
|
||||||
put_item(grid_position)
|
#put_item(grid_position)
|
||||||
main.ActionState.RANDOMIZING:
|
main.ActionState.RANDOMIZING:
|
||||||
if grid_position in highlighted_cells:
|
if grid_position in highlighted_cells:
|
||||||
main.randomize_item_at_position(grid_position)
|
main.randomize_item_at_position(grid_position)
|
||||||
@@ -933,16 +933,63 @@ func bot_try_grab_item() -> bool:
|
|||||||
|
|
||||||
return false
|
return false
|
||||||
|
|
||||||
func grab_item(grid_position: Vector2i = current_position) -> bool:
|
#func grab_item(grid_position: Vector2i = current_position) -> bool:
|
||||||
if is_bot:
|
#if is_bot:
|
||||||
return bot_try_grab_item()
|
#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 not enhanced_gridmap or action_points <= 0:
|
if not enhanced_gridmap or action_points <= 0:
|
||||||
return false
|
return false
|
||||||
|
|
||||||
var cell = Vector3i(grid_position.x, 1, grid_position.y)
|
var cell = Vector3i(grid_position.x, 1, grid_position.y)
|
||||||
var item = enhanced_gridmap.get_cell_item(cell)
|
var item = enhanced_gridmap.get_cell_item(cell)
|
||||||
|
|
||||||
|
# Validate adjacency (unless it's current position)
|
||||||
if grid_position != current_position:
|
if grid_position != current_position:
|
||||||
var neighbors = enhanced_gridmap.get_neighbors(current_position, 0)
|
var neighbors = enhanced_gridmap.get_neighbors(current_position, 0)
|
||||||
var is_adjacent = false
|
var is_adjacent = false
|
||||||
@@ -956,82 +1003,133 @@ func grab_item(grid_position: Vector2i = current_position) -> bool:
|
|||||||
if item == -1:
|
if item == -1:
|
||||||
return false
|
return false
|
||||||
|
|
||||||
# Bot-specific grab logic moved to bot_grab_item RPC
|
# === AUTO-ARRANGE LOGIC ===
|
||||||
if is_in_group("Bots") or is_bot:
|
var target_slot = find_best_goal_slot_for_item(item)
|
||||||
var empty_slot = playerboard.find(-1)
|
if target_slot == -1:
|
||||||
if empty_slot == -1:
|
return false # no space
|
||||||
return false
|
|
||||||
|
|
||||||
if is_multiplayer_authority():
|
# Perform the grab and auto-place
|
||||||
rpc("bot_grab_item", grid_position, empty_slot, cell.x, cell.y, cell.z)
|
if is_multiplayer_authority():
|
||||||
return true
|
# Update gridmap: remove item
|
||||||
|
rpc("sync_grid_item", cell.x, cell.y, cell.z, -1)
|
||||||
var main = get_tree().get_root().get_node_or_null("Main")
|
# Update playerboard
|
||||||
if main:
|
playerboard[target_slot] = item
|
||||||
selected_gridmap_position = grid_position
|
rpc("sync_playerboard", playerboard)
|
||||||
clear_highlights()
|
# Consume action
|
||||||
clear_playerboard_highlights()
|
has_performed_action = true
|
||||||
|
consume_action_points(1)
|
||||||
for i in range(playerboard.size()):
|
|
||||||
if playerboard[i] == -1:
|
# Optional: visual feedback
|
||||||
var slot = main.playerboard_ui.get_child(i)
|
var main = get_tree().get_root().get_node_or_null("Main")
|
||||||
if slot.get_child_count() > 0:
|
if main:
|
||||||
slot.get_child(0).show()
|
main.update_playerboard_ui()
|
||||||
highlighted_cells.append(i)
|
main.set_action_state(main.ActionState.NONE)
|
||||||
return true
|
|
||||||
|
return true
|
||||||
return false
|
|
||||||
|
# Auto-put: no manual selection needed
|
||||||
func put_item(grid_position: Vector2i = current_position) -> bool:
|
# Automatically puts a goal-matching tile into an adjacent (or current) empty grid cell
|
||||||
if not enhanced_gridmap or action_points <= 0 or selected_playerboard_slot == -1:
|
func auto_put_item() -> bool:
|
||||||
return false
|
if not enhanced_gridmap or action_points <= 0 or is_bot or is_in_group("Bots"):
|
||||||
|
return false
|
||||||
var cell = Vector3i(grid_position.x, 1, grid_position.y)
|
|
||||||
if enhanced_gridmap.get_cell_item(cell) != -1:
|
# Step 1: Find empty adjacent (or current) grid cells
|
||||||
return false
|
var valid_put_positions = []
|
||||||
|
# Check current position
|
||||||
# Check if position is adjacent or current position
|
var current_cell_3d = Vector3i(current_position.x, 1, current_position.y)
|
||||||
if grid_position != current_position:
|
if enhanced_gridmap.get_cell_item(current_cell_3d) == -1:
|
||||||
var is_adjacent = false
|
valid_put_positions.append(current_position)
|
||||||
var neighbors = enhanced_gridmap.get_neighbors(current_position, 0)
|
# Check neighbors
|
||||||
for neighbor in neighbors:
|
var neighbors = enhanced_gridmap.get_neighbors(current_position, 0)
|
||||||
if neighbor.position == grid_position:
|
for neighbor in neighbors:
|
||||||
is_adjacent = true
|
if neighbor.is_walkable:
|
||||||
break
|
var pos = neighbor.position
|
||||||
if not is_adjacent:
|
var cell_3d = Vector3i(pos.x, 1, pos.y)
|
||||||
return false
|
if enhanced_gridmap.get_cell_item(cell_3d) == -1 and not is_position_occupied(pos):
|
||||||
|
valid_put_positions.append(pos)
|
||||||
# Get the item to place first
|
|
||||||
var item = playerboard[selected_playerboard_slot]
|
if valid_put_positions.is_empty():
|
||||||
|
return false
|
||||||
# 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():
|
# Step 2: Find a playerboard tile that matches any goal
|
||||||
# Client requests server to perform the put operation
|
var put_slot = -1
|
||||||
rpc_id(1, "request_server_put", grid_position, selected_playerboard_slot, cell.x, cell.y, cell.z, item)
|
for i in range(playerboard.size()):
|
||||||
|
if playerboard[i] in goals:
|
||||||
# We'll return true and let the server handle the actual operation
|
put_slot = i
|
||||||
# The server will RPC back to update our state if successful
|
break
|
||||||
return true
|
|
||||||
elif is_multiplayer_authority() and multiplayer.is_server():
|
if put_slot == -1:
|
||||||
# Server directly implements the change
|
return false
|
||||||
rpc("sync_grid_item", cell.x, cell.y, cell.z, item)
|
|
||||||
playerboard[selected_playerboard_slot] = -1
|
# 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)
|
rpc("sync_playerboard", playerboard)
|
||||||
|
|
||||||
has_performed_action = true
|
has_performed_action = true
|
||||||
consume_action_points(1)
|
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")
|
var main = get_tree().get_root().get_node_or_null("Main")
|
||||||
if main:
|
if main:
|
||||||
main.set_action_state(main.ActionState.NONE)
|
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")
|
@rpc("any_peer", "reliable")
|
||||||
func request_server_put(grid_position: Vector2i, slot_index: int, x: int, y: int, z: int, item: int):
|
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]
|
enhanced_gridmap.normal_items[0]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Disabled, auto put activated
|
||||||
|
#func handle_put_action():
|
||||||
func handle_put_action():
|
#var main = get_tree().get_root().get_node_or_null("Main")
|
||||||
var main = get_tree().get_root().get_node_or_null("Main")
|
#if not main or action_points < 1:
|
||||||
if not main or action_points < 1:
|
#return
|
||||||
return
|
#
|
||||||
|
#if not is_bot == true:
|
||||||
if not is_bot == true:
|
#clear_highlights()
|
||||||
clear_highlights()
|
#clear_playerboard_highlights()
|
||||||
clear_playerboard_highlights()
|
#
|
||||||
|
## Highlight non-empty slots in playerboard
|
||||||
# Highlight non-empty slots in playerboard
|
#for i in range(playerboard.size()):
|
||||||
for i in range(playerboard.size()):
|
#if playerboard[i] != -1: # Highlight occupied slots
|
||||||
if playerboard[i] != -1: # Highlight occupied slots
|
#var slot = main.playerboard_ui.get_child(i)
|
||||||
var slot = main.playerboard_ui.get_child(i)
|
#if slot.get_child_count() > 0:
|
||||||
if slot.get_child_count() > 0:
|
#slot.get_child(0).show() # Show highlight for occupied slots
|
||||||
slot.get_child(0).show() # Show highlight for occupied slots
|
#highlighted_cells.append(i)
|
||||||
highlighted_cells.append(i)
|
|
||||||
|
|
||||||
func handle_playerboard_slot_selected(slot_index: int):
|
func handle_playerboard_slot_selected(slot_index: int):
|
||||||
var main = get_tree().get_root().get_node_or_null("Main")
|
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)
|
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:
|
func get_adjacent_playerboard_slots(slot_index) -> Array:
|
||||||
var adjacent = []
|
var adjacent = []
|
||||||
var row = slot_index / 5
|
var row = slot_index / 5
|
||||||
|
|||||||
@@ -0,0 +1,172 @@
|
|||||||
|
# tekton-enet/scripts/tile_grabber.gd
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
class_name TileGrabber
|
||||||
|
|
||||||
|
signal tile_grabbed(tile_id: int, position: Vector3i)
|
||||||
|
signal tiles_arranged(arranged_tiles: Array)
|
||||||
|
|
||||||
|
@export var enhanced_gridmap_path: NodePath
|
||||||
|
@export var player_board_path: NodePath
|
||||||
|
|
||||||
|
var enhanced_gridmap: EnhancedGridMap
|
||||||
|
var player_board: Node
|
||||||
|
var grabbed_tile: int = -1
|
||||||
|
var grabbed_position: Vector3i
|
||||||
|
|
||||||
|
# Goal combinations - define what patterns score points
|
||||||
|
var goal_combinations = [
|
||||||
|
{
|
||||||
|
"name": "Line of 3",
|
||||||
|
"pattern": [
|
||||||
|
[1, 1, 1],
|
||||||
|
[0, 0, 0],
|
||||||
|
[0, 0, 0]
|
||||||
|
],
|
||||||
|
"score": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "L-Shape",
|
||||||
|
"pattern": [
|
||||||
|
[1, 0, 0],
|
||||||
|
[1, 0, 0],
|
||||||
|
[1, 1, 0]
|
||||||
|
],
|
||||||
|
"score": 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Square",
|
||||||
|
"pattern": [
|
||||||
|
[1, 1, 0],
|
||||||
|
[1, 1, 0],
|
||||||
|
[0, 0, 0]
|
||||||
|
],
|
||||||
|
"score": 20
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
if enhanced_gridmap_path:
|
||||||
|
enhanced_gridmap = get_node(enhanced_gridmap_path)
|
||||||
|
if player_board_path:
|
||||||
|
player_board = get_node(player_board_path)
|
||||||
|
|
||||||
|
func grab_tile(grid_position: Vector3i) -> bool:
|
||||||
|
if not enhanced_gridmap:
|
||||||
|
print("Error: EnhancedGridMap not found")
|
||||||
|
return false
|
||||||
|
|
||||||
|
# Get the tile at the specified position
|
||||||
|
var tile_id = enhanced_gridmap.get_cell_item(grid_position)
|
||||||
|
if tile_id == -1:
|
||||||
|
print("No tile at position: ", grid_position)
|
||||||
|
return false
|
||||||
|
|
||||||
|
# Store the grabbed tile and its position
|
||||||
|
grabbed_tile = tile_id
|
||||||
|
grabbed_position = grid_position
|
||||||
|
|
||||||
|
# Remove the tile from the grid
|
||||||
|
enhanced_gridmap.set_cell_item(grid_position, -1)
|
||||||
|
|
||||||
|
# Emit signal that a tile was grabbed
|
||||||
|
tile_grabbed.emit(tile_id, grid_position)
|
||||||
|
|
||||||
|
print("Grabbed tile ", tile_id, " from position ", grid_position)
|
||||||
|
return true
|
||||||
|
|
||||||
|
func auto_arrange_tile() -> bool:
|
||||||
|
if grabbed_tile == -1:
|
||||||
|
print("No tile to arrange")
|
||||||
|
return false
|
||||||
|
|
||||||
|
# Find the best position for the grabbed tile based on goal combinations
|
||||||
|
var best_position = find_best_position_for_tile(grabbed_tile)
|
||||||
|
|
||||||
|
if best_position == Vector3i(-1, -1, -1):
|
||||||
|
print("No valid position found for tile")
|
||||||
|
return false
|
||||||
|
|
||||||
|
# Place the tile at the best position
|
||||||
|
enhanced_gridmap.set_cell_item(best_position, grabbed_tile)
|
||||||
|
|
||||||
|
# Reset grabbed tile
|
||||||
|
grabbed_tile = -1
|
||||||
|
grabbed_position = Vector3i(-1, -1, -1)
|
||||||
|
|
||||||
|
# Emit signal that tiles were arranged
|
||||||
|
tiles_arranged.emit([best_position])
|
||||||
|
|
||||||
|
print("Auto-arranged tile at position: ", best_position)
|
||||||
|
return true
|
||||||
|
|
||||||
|
func find_best_position_for_tile(tile_id: int) -> Vector3i:
|
||||||
|
var best_position = Vector3i(-1, -1, -1)
|
||||||
|
var best_score = -1
|
||||||
|
|
||||||
|
# Check all possible positions on the grid
|
||||||
|
for x in range(enhanced_gridmap.columns):
|
||||||
|
for z in range(enhanced_gridmap.rows):
|
||||||
|
var position = Vector3i(x, 0, z)
|
||||||
|
|
||||||
|
# Skip if position is already occupied
|
||||||
|
if enhanced_gridmap.get_cell_item(position) != -1:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Temporarily place the tile to check for goal combinations
|
||||||
|
enhanced_gridmap.set_cell_item(position, tile_id)
|
||||||
|
|
||||||
|
# Calculate score for this position
|
||||||
|
var score = calculate_position_score(position)
|
||||||
|
|
||||||
|
# Remove the temporary tile
|
||||||
|
enhanced_gridmap.set_cell_item(position, -1)
|
||||||
|
|
||||||
|
# Update best position if this one scores higher
|
||||||
|
if score > best_score:
|
||||||
|
best_score = score
|
||||||
|
best_position = position
|
||||||
|
|
||||||
|
return best_position
|
||||||
|
|
||||||
|
func calculate_position_score(position: Vector3i) -> int:
|
||||||
|
var total_score = 0
|
||||||
|
|
||||||
|
# Check each goal combination
|
||||||
|
for goal in goal_combinations:
|
||||||
|
var matches = check_goal_combination(position, goal.pattern)
|
||||||
|
if matches:
|
||||||
|
total_score += goal.score
|
||||||
|
|
||||||
|
return total_score
|
||||||
|
|
||||||
|
func check_goal_combination(center_position: Vector3i, pattern: Array) -> bool:
|
||||||
|
# Get the pattern dimensions
|
||||||
|
var pattern_width = pattern[0].size()
|
||||||
|
var pattern_height = pattern.size()
|
||||||
|
|
||||||
|
# Calculate the top-left position of the pattern
|
||||||
|
var start_x = center_position.x - (pattern_width / 2)
|
||||||
|
var start_z = center_position.z - (pattern_height / 2)
|
||||||
|
|
||||||
|
# Check if the pattern fits within the grid
|
||||||
|
if start_x < 0 or start_z < 0 or start_x + pattern_width > enhanced_gridmap.columns or start_z + pattern_height > enhanced_gridmap.rows:
|
||||||
|
return false
|
||||||
|
|
||||||
|
# Check each cell in the pattern
|
||||||
|
for z in range(pattern_height):
|
||||||
|
for x in range(pattern_width):
|
||||||
|
var pattern_value = pattern[z][x]
|
||||||
|
var grid_position = Vector3i(start_x + x, 0, start_z + z)
|
||||||
|
var grid_value = enhanced_gridmap.get_cell_item(grid_position)
|
||||||
|
|
||||||
|
# If pattern expects a tile (1) but grid is empty (-1), no match
|
||||||
|
if pattern_value == 1 and grid_value == -1:
|
||||||
|
return false
|
||||||
|
|
||||||
|
# If pattern expects empty (0) but grid has a tile, no match
|
||||||
|
if pattern_value == 0 and grid_value != -1:
|
||||||
|
return false
|
||||||
|
|
||||||
|
# All cells match the pattern
|
||||||
|
return true
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://dc1cw21830bfp
|
||||||
Reference in New Issue
Block a user