add beehave

This commit is contained in:
2025-01-28 13:53:59 +08:00
parent d6b69c14ac
commit 144a01556d
112 changed files with 6075 additions and 205 deletions
+146 -139
View File
@@ -14,10 +14,10 @@ var max_players = 4
var bots = []
@export var turn_based_mode: bool = true
var bot_move_timer: float = 0.0
const BOT_MOVE_INTERVAL: float = 2.0
#var bot_move_timer: float = 0.0
#const BOT_MOVE_INTERVAL: float = 2.0
var moving_bots = {}
#var moving_bots = {}
enum ActionState {
NONE,
@@ -57,13 +57,14 @@ func _process(delta):
if turn_based_mode:
rpc("sync_turn_index", current_turn_index)
else:
bot_move_timer += delta
if bot_move_timer >= BOT_MOVE_INTERVAL:
bot_move_timer = 0.0
var current_bots = bots.duplicate()
for bot_id in current_bots:
if not moving_bots.get(bot_id, false):
move_bot(bot_id)
pass
#bot_move_timer += delta
#if bot_move_timer >= BOT_MOVE_INTERVAL:
#bot_move_timer = 0.0
#var current_bots = bots.duplicate()
#for bot_id in current_bots:
#if not moving_bots.get(bot_id, false):
#move_bot(bot_id)
func setup_action_buttons():
move_button.pressed.connect(func(): set_action_state(ActionState.MOVING))
@@ -265,27 +266,33 @@ func add_player_character(peer_id):
func add_bot(bot_id):
if multiplayer.is_server():
rpc("create_bot", bot_id)
moving_bots[bot_id] = false
#moving_bots[bot_id] = false
@rpc("call_local")
func create_bot(bot_id):
var bot_character = player_scene.instantiate()
bot_character.set_multiplayer_authority(1)
bot_character.name = str(bot_id)
# Add Beehave tree
var behavior_tree = preload("res://scripts/bot_behavior_tree.gd").new()
bot_character.add_child(behavior_tree)
behavior_tree.name = "BehaviorTree"
add_child(bot_character)
bot_character.add_to_group("Players", true)
bot_character.add_to_group("Bots", true)
if multiplayer.is_server():
bots.append(bot_id)
players.append(bot_id)
moving_bots[bot_id] = false
func replace_bot_with_player(player_id):
if multiplayer.is_server() and bots.size() > 0:
var bot_id = bots.pop_front()
players.erase(bot_id)
players.append(player_id)
moving_bots.erase(bot_id)
#moving_bots.erase(bot_id)
rpc("remove_bot", bot_id)
rpc("sync_players", players)
@@ -350,8 +357,8 @@ func next_turn():
if multiplayer.is_server() and turn_based_mode:
current_turn_index = (current_turn_index + 1) % players.size()
rpc("set_current_turn", players[current_turn_index])
if players[current_turn_index] in bots:
move_bot(players[current_turn_index])
#if players[current_turn_index] in bots:
#move_bot(players[current_turn_index])
func request_next_turn():
if multiplayer.is_server():
@@ -384,130 +391,130 @@ func end_current_turn():
next_turn()
rpc("sync_turn_index", current_turn_index)
func move_bot(bot_id):
if not multiplayer.is_server() or moving_bots.get(bot_id, false):
return
var bot = get_node_or_null(str(bot_id))
if not is_instance_valid(bot) or bot.is_player_moving:
moving_bots.erase(bot_id)
return
if bot.action_points <= 0:
if turn_based_mode:
moving_bots[bot_id] = false
end_current_turn()
else:
bot.action_points = 2
bot.has_moved_this_turn = false
bot.has_performed_action = false
moving_bots[bot_id] = false
await get_tree().create_timer(0.5).timeout
move_bot(bot_id)
return
moving_bots[bot_id] = true
await get_tree().create_timer(0.5).timeout
if not is_instance_valid(bot):
moving_bots.erase(bot_id)
return
var best_move = evaluate_bot_move(bot)
execute_bot_move(bot, bot_id, best_move)
#func move_bot(bot_id):
#if not multiplayer.is_server() or moving_bots.get(bot_id, false):
#return
#
#var bot = get_node_or_null(str(bot_id))
#if not is_instance_valid(bot) or bot.is_player_moving:
#moving_bots.erase(bot_id)
#return
#
#if bot.action_points <= 0:
#if turn_based_mode:
#moving_bots[bot_id] = false
#end_current_turn()
#else:
#bot.action_points = 2
#bot.has_moved_this_turn = false
#bot.has_performed_action = false
#moving_bots[bot_id] = false
#await get_tree().create_timer(0.5).timeout
#move_bot(bot_id)
#return
#
#moving_bots[bot_id] = true
#await get_tree().create_timer(0.5).timeout
#
#if not is_instance_valid(bot):
#moving_bots.erase(bot_id)
#return
#
#var best_move = evaluate_bot_move(bot)
#execute_bot_move(bot, bot_id, best_move)
func execute_bot_move(bot, bot_id, move):
match move.action:
"arrange":
if bot.action_points >= 2:
bot.arrange_playerboard_item(bot.find_best_arrangement_slot())
bot.action_points -= 2
moving_bots[bot_id] = false
if bot.action_points > 0 or not turn_based_mode:
move_bot(bot_id)
elif turn_based_mode:
end_current_turn()
"grab", "put":
var success = bot.grab_item(move.position) if move.action == "grab" else bot.put_item(move.position)
if success:
bot.action_points -= 1
moving_bots[bot_id] = false
if bot.action_points > 0 or not turn_based_mode:
move_bot(bot_id)
elif turn_based_mode:
end_current_turn()
"move":
if is_instance_valid(bot) and bot.action_points >= 1:
var path = bot.enhanced_gridmap.find_path(Vector2(bot.current_position), Vector2(move.position))
if path.size() > 1:
path.pop_front()
var trimmed_path = path.slice(0, bot.movement_range)
bot.rotate_towards_target(move.position)
bot.move_bot_along_path(trimmed_path, bot_id)
bot.action_points -= 1
else:
moving_bots[bot_id] = false
if bot.action_points > 0 or not turn_based_mode:
move_bot(bot_id)
elif turn_based_mode:
end_current_turn()
else:
moving_bots[bot_id] = false
if bot.action_points > 0 or not turn_based_mode:
move_bot(bot_id)
elif turn_based_mode:
end_current_turn()
_:
moving_bots[bot_id] = false
if turn_based_mode:
end_current_turn()
else:
move_bot(bot_id)
#func execute_bot_move(bot, bot_id, move):
#match move.action:
#"arrange":
#if bot.action_points >= 2:
#bot.arrange_playerboard_item(bot.find_best_arrangement_slot())
#bot.action_points -= 2
#moving_bots[bot_id] = false
#if bot.action_points > 0 or not turn_based_mode:
#move_bot(bot_id)
#elif turn_based_mode:
#end_current_turn()
#
#"grab", "put":
#var success = bot.grab_item(move.position) if move.action == "grab" else bot.put_item(move.position)
#if success:
#bot.action_points -= 1
#moving_bots[bot_id] = false
#if bot.action_points > 0 or not turn_based_mode:
#move_bot(bot_id)
#elif turn_based_mode:
#end_current_turn()
#
#"move":
#if is_instance_valid(bot) and bot.action_points >= 1:
#var path = bot.enhanced_gridmap.find_path(Vector2(bot.current_position), Vector2(move.position))
#if path.size() > 1:
#path.pop_front()
#var trimmed_path = path.slice(0, bot.movement_range)
#bot.rotate_towards_target(move.position)
#bot.move_bot_along_path(trimmed_path, bot_id)
#bot.action_points -= 1
#else:
#moving_bots[bot_id] = false
#if bot.action_points > 0 or not turn_based_mode:
#move_bot(bot_id)
#elif turn_based_mode:
#end_current_turn()
#else:
#moving_bots[bot_id] = false
#if bot.action_points > 0 or not turn_based_mode:
#move_bot(bot_id)
#elif turn_based_mode:
#end_current_turn()
#
#_:
#moving_bots[bot_id] = false
#if turn_based_mode:
#end_current_turn()
#else:
#move_bot(bot_id)
func evaluate_bot_move(bot: Node) -> Dictionary:
if not is_instance_valid(bot) or bot.action_points <= 0:
return { "action": "none", "position": Vector2i.ZERO, "value": -1 }
#func evaluate_bot_move(bot: Node) -> Dictionary:
#if not is_instance_valid(bot) or bot.action_points <= 0:
#return { "action": "none", "position": Vector2i.ZERO, "value": -1 }
#
#var moves = []
#
#if bot.action_points >= 2 and bot.check_playerboard_arrangement(bot):
#moves.append({ "action": "arrange", "position": bot.current_position, "value": 20 })
#
#if bot.action_points >= 1:
#var put_position = bot.find_best_put_position(bot)
#if put_position != Vector2i(-1, -1):
#moves.append({ "action": "put", "position": put_position, "value": 18 })
#
#if bot.action_points >= 1 and not bot.playerboard_is_full():
#var grab_position = bot.find_best_grab_position()
#if grab_position != Vector2i(-1, -1):
#moves.append({ "action": "grab", "position": grab_position, "value": 15 })
#
#if bot.action_points >= 1 and not bot.has_moved_this_turn:
#var random_pos = bot.find_random_valid_position_in_range()
#if random_pos != bot.current_position:
#moves.append({ "action": "move", "position": random_pos, "value": 5 })
#
#moves.sort_custom(func(a, b): return a.value > b.value)
#return moves[0] if moves.size() > 0 else { "action": "none", "position": bot.current_position, "value": 0 }
var moves = []
if bot.action_points >= 2 and bot.check_playerboard_arrangement(bot):
moves.append({ "action": "arrange", "position": bot.current_position, "value": 20 })
if bot.action_points >= 1:
var put_position = bot.find_best_put_position(bot)
if put_position != Vector2i(-1, -1):
moves.append({ "action": "put", "position": put_position, "value": 18 })
if bot.action_points >= 1 and not bot.playerboard_is_full():
var grab_position = bot.find_best_grab_position()
if grab_position != Vector2i(-1, -1):
moves.append({ "action": "grab", "position": grab_position, "value": 15 })
if bot.action_points >= 1 and not bot.has_moved_this_turn:
var random_pos = bot.find_random_valid_position_in_range()
if random_pos != bot.current_position:
moves.append({ "action": "move", "position": random_pos, "value": 5 })
moves.sort_custom(func(a, b): return a.value > b.value)
return moves[0] if moves.size() > 0 else { "action": "none", "position": bot.current_position, "value": 0 }
func bot_movement_completed(bot_id):
if not multiplayer.is_server():
return
moving_bots[bot_id] = false
var bot = get_node_or_null(str(bot_id))
if not is_instance_valid(bot):
moving_bots.erase(bot_id)
return
if bot.action_points > 0 or not turn_based_mode:
await get_tree().create_timer(0.5).timeout
if is_instance_valid(bot):
move_bot(bot_id)
else:
end_current_turn()
#func bot_movement_completed(bot_id):
#if not multiplayer.is_server():
#return
#
#moving_bots[bot_id] = false
#var bot = get_node_or_null(str(bot_id))
#
#if not is_instance_valid(bot):
#moving_bots.erase(bot_id)
#return
#
#if bot.action_points > 0 or not turn_based_mode:
#await get_tree().create_timer(0.5).timeout
#if is_instance_valid(bot):
#move_bot(bot_id)
#else:
#end_current_turn()
+1
View File
@@ -17,6 +17,7 @@
[node name="Main" type="Node3D"]
script = ExtResource("1_xcpe3")
players = null
turn_based_mode = false
[node name="EnhancedGridMap" type="GridMap" parent="."]
+65 -65
View File
@@ -71,8 +71,8 @@ func _physics_process(_delta):
rpc("remote_set_position", global_position)
func _unhandled_input(event):
if is_in_group("Bots"):
return
#if is_in_group("Bots"):
#return
var main = get_node("/root/Main")
if not is_multiplayer_authority() or (main.turn_based_mode and (not is_my_turn or is_player_moving)):
@@ -576,28 +576,28 @@ func _on_slot_clicked(event: InputEvent, slot_index: int):
main.set_action_state(main.ActionState.NONE)
func check_playerboard_arrangement(bot: Node) -> bool:
var goal_indices = [] # Store indices of non-empty goals
var goal_items = [] # Store the actual goal items
# Get all valid goals (non -1)
for i in range(goals.size()):
if goals[i] != -1:
goal_indices.append(i)
goal_items.append(goals[i])
# Check if current arrangement matches goals
var current_items = []
for i in range(playerboard.size()):
if playerboard[i] in goal_items:
current_items.append(playerboard[i])
# Compare current order with goal order
for i in range(min(current_items.size(), goal_items.size())):
if current_items[i] != goal_items[i]:
return true
return false
#func check_playerboard_arrangement(bot: Node) -> bool:
#var goal_indices = [] # Store indices of non-empty goals
#var goal_items = [] # Store the actual goal items
#
## Get all valid goals (non -1)
#for i in range(goals.size()):
#if goals[i] != -1:
#goal_indices.append(i)
#goal_items.append(goals[i])
#
## Check if current arrangement matches goals
#var current_items = []
#for i in range(playerboard.size()):
#if playerboard[i] in goal_items:
#current_items.append(playerboard[i])
#
## Compare current order with goal order
#for i in range(min(current_items.size(), goal_items.size())):
#if current_items[i] != goal_items[i]:
#return true
#
#return false
func is_valid_arrangement_slot(from_slot: int, to_slot: int) -> bool:
var from_row = from_slot / 5
@@ -622,39 +622,39 @@ func get_adjacent_playerboard_slots(slot_index) -> Array:
return adjacent
func find_best_arrangement_slot() -> int:
for i in range(playerboard.size()):
if playerboard[i] != -1:
var neighbors = get_adjacent_playerboard_slots(i)
for adj_slot in neighbors:
if playerboard[adj_slot] == -1 and playerboard[i] in goals:
return adj_slot
return playerboard.find(-1)
#func find_best_arrangement_slot() -> int:
#for i in range(playerboard.size()):
#if playerboard[i] != -1:
#var neighbors = get_adjacent_playerboard_slots(i)
#for adj_slot in neighbors:
#if playerboard[adj_slot] == -1 and playerboard[i] in goals:
#return adj_slot
#return playerboard.find(-1)
func find_best_put_position(bot: Node) -> Vector2i:
# Find the first empty cell adjacent to a matching item in the playerboard
for i in range(playerboard.size()):
if playerboard[i] in goals:
var neighbors = enhanced_gridmap.get_neighbors(current_position, 1)
for neighbor in neighbors:
var cell = Vector3i(neighbor.position.x, 1, neighbor.position.y)
if enhanced_gridmap.get_cell_item(cell) == -1:
return neighbor.position
return Vector2i(-1, -1)
#func find_best_put_position(bot: Node) -> Vector2i:
## Find the first empty cell adjacent to a matching item in the playerboard
#for i in range(playerboard.size()):
#if playerboard[i] in goals:
#var neighbors = enhanced_gridmap.get_neighbors(current_position, 1)
#for neighbor in neighbors:
#var cell = Vector3i(neighbor.position.x, 1, neighbor.position.y)
#if enhanced_gridmap.get_cell_item(cell) == -1:
#return neighbor.position
#return Vector2i(-1, -1)
func find_best_grab_position() -> Vector2i:
# Find the first matching item in the grid or adjacent cells
var current_cell = Vector3i(current_position.x, 1, current_position.y)
if enhanced_gridmap.get_cell_item(current_cell) in goals:
return current_position
var neighbors = enhanced_gridmap.get_neighbors(current_position, 1)
for neighbor in neighbors:
var cell = Vector3i(neighbor.position.x, 1, neighbor.position.y)
if enhanced_gridmap.get_cell_item(cell) in goals:
return neighbor.position
return Vector2i(-1, -1)
#func find_best_grab_position() -> Vector2i:
## Find the first matching item in the grid or adjacent cells
#var current_cell = Vector3i(current_position.x, 1, current_position.y)
#if enhanced_gridmap.get_cell_item(current_cell) in goals:
#return current_position
#
#var neighbors = enhanced_gridmap.get_neighbors(current_position, 1)
#for neighbor in neighbors:
#var cell = Vector3i(neighbor.position.x, 1, neighbor.position.y)
#if enhanced_gridmap.get_cell_item(cell) in goals:
#return neighbor.position
#
#return Vector2i(-1, -1)
func has_item_at_current_position() -> bool:
var current_cell = Vector3i(current_position.x, 1, current_position.y)
@@ -667,8 +667,8 @@ func playerboard_is_full() -> bool:
return playerboard.find(-1) == -1
func highlight_movement_range():
if is_in_group("Bots"):
return
#if is_in_group("Bots"):
#return
for x in range(enhanced_gridmap.columns):
for z in range(enhanced_gridmap.rows):
@@ -680,8 +680,8 @@ func highlight_movement_range():
enhanced_gridmap.set_cell_item(Vector3i(x, 0, z), enhanced_gridmap.hover_item)
func highlight_adjacent_cells():
if is_in_group("Bots"):
return
#if is_in_group("Bots"):
#return
var current_cell = Vector3i(current_position.x, 1, current_position.y)
if enhanced_gridmap.get_cell_item(current_cell) != -1:
@@ -698,8 +698,8 @@ func highlight_adjacent_cells():
func highlight_empty_adjacent_cells():
if is_in_group("Bots"):
return
#if is_in_group("Bots"):
#return
# Clear previous highlights
clear_highlights()
@@ -723,8 +723,8 @@ func highlight_empty_adjacent_cells():
enhanced_gridmap.hover_item)
func highlight_random_valid_cells():
if is_in_group("Bots"):
return
#if is_in_group("Bots"):
#return
var valid_cells = []
for x in range(enhanced_gridmap.columns):
@@ -744,8 +744,8 @@ func highlight_random_valid_cells():
valid_cells.remove_at(index)
func highlight_occupied_playerboard_slots():
if is_in_group("Bots"):
return
#if is_in_group("Bots"):
#return
var main = get_node("/root/Main")
if not main or not main.playerboard_ui: