update with bot system, but bot visually hosted on host side, doesn't visually appear on client side
This commit is contained in:
+108
-55
@@ -1,133 +1,186 @@
|
|||||||
extends Node3D # This script is attached to a Node3D (main scene)
|
extends Node3D
|
||||||
|
|
||||||
var multiplayer_peer = ENetMultiplayerPeer.new() # Create a new ENet multiplayer peer
|
var multiplayer_peer = ENetMultiplayerPeer.new()
|
||||||
|
const PORT = 9999
|
||||||
|
const ADDRESS = "127.0.0.1"
|
||||||
|
|
||||||
const PORT = 9999 # Define the port for multiplayer
|
var connected_peer_ids = []
|
||||||
const ADDRESS = "127.0.0.1" # Define the IP address for multiplayer
|
var local_player_character : CharacterBody3D
|
||||||
|
var player_scene = preload("res://scenes/player.tscn")
|
||||||
|
var current_turn_index = 0
|
||||||
|
@export var players = []
|
||||||
|
var game_started = false
|
||||||
|
var max_message_input_char = 51
|
||||||
|
var max_players = 4
|
||||||
|
var bots = []
|
||||||
|
|
||||||
var connected_peer_ids = [] # List of connected peer IDs
|
func _ready():
|
||||||
var local_player_character : CharacterBody3D # Reference to the local player character
|
multiplayer_peer.peer_connected.connect(_on_peer_connected)
|
||||||
var player_scene = preload("res://scenes/player.tscn") # Preload the player scene
|
multiplayer_peer.peer_disconnected.connect(_on_peer_disconnected)
|
||||||
var current_turn_index = 0 # Index of the current turn
|
|
||||||
@export var players = [] # List of player IDs
|
|
||||||
var game_started = false # Flag to track if the game has started
|
|
||||||
|
|
||||||
var max_message_input_char = 51 # Maximum characters allowed in a message
|
func _on_host_pressed():
|
||||||
|
|
||||||
func _on_host_pressed(): # Called when the host button is pressed
|
|
||||||
$NetworkInfo/NetworkSideDisplay.text = "Server"
|
$NetworkInfo/NetworkSideDisplay.text = "Server"
|
||||||
$Menu.visible = false
|
$Menu.visible = false
|
||||||
multiplayer_peer.create_server(PORT) # Create a multiplayer server
|
multiplayer_peer.create_server(PORT)
|
||||||
multiplayer.multiplayer_peer = multiplayer_peer
|
multiplayer.multiplayer_peer = multiplayer_peer
|
||||||
$NetworkInfo/UniquePeerID.text = str(multiplayer.get_unique_id())
|
$NetworkInfo/UniquePeerID.text = str(multiplayer.get_unique_id())
|
||||||
|
|
||||||
add_player_character(1) # Add host player character
|
add_player_character(1)
|
||||||
|
players.append(1)
|
||||||
|
|
||||||
players.append(1) # Add host to players list
|
# Add bots to fill remaining slots
|
||||||
if players.size() == 2:
|
for i in range(2, max_players + 1):
|
||||||
start_game() # Start game if two players are connected
|
add_bot(i)
|
||||||
|
|
||||||
multiplayer_peer.peer_connected.connect(_on_peer_connected) # Connect peer connected signal
|
start_game()
|
||||||
|
|
||||||
func _on_join_pressed(): # Called when the join button is pressed
|
func _on_join_pressed():
|
||||||
$NetworkInfo/NetworkSideDisplay.text = "Client"
|
$NetworkInfo/NetworkSideDisplay.text = "Client"
|
||||||
$Menu.visible = false
|
$Menu.visible = false
|
||||||
multiplayer_peer.create_client(ADDRESS, PORT) # Create a multiplayer client
|
multiplayer_peer.create_client(ADDRESS, PORT)
|
||||||
multiplayer.multiplayer_peer = multiplayer_peer
|
multiplayer.multiplayer_peer = multiplayer_peer
|
||||||
$NetworkInfo/UniquePeerID.text = str(multiplayer.get_unique_id())
|
$NetworkInfo/UniquePeerID.text = str(multiplayer.get_unique_id())
|
||||||
|
|
||||||
func _on_peer_connected(new_peer_id): # Called when a new peer connects
|
func _on_peer_connected(new_peer_id):
|
||||||
if multiplayer.is_server():
|
if multiplayer.is_server():
|
||||||
await get_tree().create_timer(1).timeout
|
await get_tree().create_timer(1).timeout
|
||||||
rpc("add_newly_connected_player_character", new_peer_id) # RPC call to add new player
|
rpc("add_newly_connected_player_character", new_peer_id)
|
||||||
rpc_id(new_peer_id, "add_previously_connected_player_characters", connected_peer_ids) # RPC call to sync existing players
|
rpc_id(new_peer_id, "add_previously_connected_player_characters", connected_peer_ids)
|
||||||
add_player_character(new_peer_id)
|
add_player_character(new_peer_id)
|
||||||
players.append(new_peer_id)
|
replace_bot_with_player(new_peer_id)
|
||||||
if players.size() == 2 and not game_started:
|
|
||||||
start_game() # Start game if two players are connected
|
|
||||||
|
|
||||||
func _on_peer_disconnected(peer_id): # Called when a peer disconnects
|
func _on_peer_disconnected(peer_id):
|
||||||
if multiplayer.is_server():
|
if multiplayer.is_server():
|
||||||
connected_peer_ids.erase(peer_id)
|
connected_peer_ids.erase(peer_id)
|
||||||
players.erase(peer_id)
|
players.erase(peer_id)
|
||||||
if players.size() < 2:
|
add_bot(get_next_available_bot_id())
|
||||||
game_started = false
|
|
||||||
|
|
||||||
func add_player_character(peer_id): # Add a player character to the game
|
func add_player_character(peer_id):
|
||||||
connected_peer_ids.append(peer_id)
|
connected_peer_ids.append(peer_id)
|
||||||
var player_character = player_scene.instantiate()
|
var player_character = player_scene.instantiate()
|
||||||
player_character.set_multiplayer_authority(peer_id)
|
player_character.set_multiplayer_authority(peer_id)
|
||||||
add_child(player_character)
|
add_child(player_character)
|
||||||
player_character.add_to_group("Players",true)
|
player_character.add_to_group("Players", true)
|
||||||
if peer_id == multiplayer.get_unique_id():
|
if peer_id == multiplayer.get_unique_id():
|
||||||
local_player_character = player_character
|
local_player_character = player_character
|
||||||
|
|
||||||
@rpc
|
func add_bot(bot_id):
|
||||||
func add_newly_connected_player_character(new_peer_id): # RPC function to add a new player character
|
var bot_character = player_scene.instantiate()
|
||||||
|
bot_character.set_multiplayer_authority(1) # Set server as authority for bots
|
||||||
|
bot_character.name = str(bot_id)
|
||||||
|
add_child(bot_character)
|
||||||
|
bot_character.add_to_group("Players", true)
|
||||||
|
bot_character.add_to_group("Bots", true)
|
||||||
|
bots.append(bot_id)
|
||||||
|
players.append(bot_id)
|
||||||
|
|
||||||
|
func replace_bot_with_player(player_id):
|
||||||
|
if bots.size() > 0:
|
||||||
|
var bot_id = bots.pop_front()
|
||||||
|
players.erase(bot_id)
|
||||||
|
players.append(player_id)
|
||||||
|
var bot_node = get_node(str(bot_id))
|
||||||
|
if bot_node:
|
||||||
|
bot_node.queue_free()
|
||||||
|
rpc("sync_players", players)
|
||||||
|
|
||||||
|
func get_next_available_bot_id():
|
||||||
|
for i in range(2, max_players + 1):
|
||||||
|
if not i in players:
|
||||||
|
return i
|
||||||
|
return -1
|
||||||
|
|
||||||
|
@rpc
|
||||||
|
func add_newly_connected_player_character(new_peer_id):
|
||||||
add_player_character(new_peer_id)
|
add_player_character(new_peer_id)
|
||||||
|
|
||||||
@rpc
|
@rpc
|
||||||
func add_previously_connected_player_characters(peer_ids): # RPC function to add existing player characters
|
func add_previously_connected_player_characters(peer_ids):
|
||||||
for peer_id in peer_ids:
|
for peer_id in peer_ids:
|
||||||
add_player_character(peer_id)
|
add_player_character(peer_id)
|
||||||
|
|
||||||
func _process(_delta): # Called every frame
|
func _process(_delta):
|
||||||
if multiplayer.is_server() and game_started:
|
if multiplayer.is_server() and game_started:
|
||||||
rpc("sync_turn_index", current_turn_index) # RPC call to sync turn index
|
rpc("sync_turn_index", current_turn_index)
|
||||||
|
|
||||||
func start_game(): # Start the game
|
func start_game():
|
||||||
if multiplayer.is_server():
|
if multiplayer.is_server():
|
||||||
game_started = true
|
game_started = true
|
||||||
connected_peer_ids.sort()
|
connected_peer_ids.sort()
|
||||||
rpc("sync_game_start", connected_peer_ids) # RPC call to sync game start
|
rpc("sync_game_start", connected_peer_ids)
|
||||||
current_turn_index = -1
|
current_turn_index = -1
|
||||||
next_turn()
|
next_turn()
|
||||||
|
|
||||||
@rpc
|
@rpc
|
||||||
func sync_game_start(peer_ids): # RPC function to sync game start
|
func sync_game_start(peer_ids):
|
||||||
connected_peer_ids = peer_ids
|
connected_peer_ids = peer_ids
|
||||||
game_started = true
|
game_started = true
|
||||||
|
|
||||||
@rpc("reliable")
|
@rpc("reliable")
|
||||||
func sync_turn_index(index): # RPC function to sync turn index
|
func sync_turn_index(index):
|
||||||
current_turn_index = index
|
current_turn_index = index
|
||||||
|
|
||||||
func next_turn(): # Move to the next turn
|
@rpc("reliable")
|
||||||
|
func sync_players(new_players):
|
||||||
|
players = new_players
|
||||||
|
|
||||||
|
func next_turn():
|
||||||
if multiplayer.is_server():
|
if multiplayer.is_server():
|
||||||
current_turn_index += 1
|
current_turn_index += 1
|
||||||
if current_turn_index >= connected_peer_ids.size():
|
if current_turn_index >= players.size():
|
||||||
current_turn_index = -1
|
current_turn_index = 0
|
||||||
next_turn()
|
rpc("set_current_turn", players[current_turn_index])
|
||||||
else:
|
if players[current_turn_index] in bots:
|
||||||
rpc("set_current_turn", connected_peer_ids[current_turn_index]) # RPC call to set current turn
|
move_bot(players[current_turn_index])
|
||||||
|
|
||||||
func request_next_turn(): # Request to move to the next turn
|
func request_next_turn():
|
||||||
if multiplayer.is_server():
|
if multiplayer.is_server():
|
||||||
end_current_turn()
|
end_current_turn()
|
||||||
else:
|
else:
|
||||||
rpc_id(1, "server_end_current_turn") # RPC call to end turn on server
|
rpc_id(1, "server_end_current_turn")
|
||||||
|
|
||||||
@rpc("any_peer")
|
@rpc("any_peer")
|
||||||
func server_end_current_turn(): # RPC function to end current turn on server
|
func server_end_current_turn():
|
||||||
if multiplayer.is_server():
|
if multiplayer.is_server():
|
||||||
end_current_turn()
|
end_current_turn()
|
||||||
|
|
||||||
@rpc("any_peer", "call_local")
|
@rpc("any_peer", "call_local")
|
||||||
func set_current_turn(player_id): # RPC function to set the current turn
|
func set_current_turn(player_id):
|
||||||
var players = get_tree().get_nodes_in_group("Players")
|
var players = get_tree().get_nodes_in_group("Players")
|
||||||
for player in players:
|
for player in players:
|
||||||
player.is_my_turn = (player.name == str(player_id))
|
player.is_my_turn = (player.name == str(player_id))
|
||||||
if player.is_my_turn:
|
if player.is_my_turn:
|
||||||
player.start_turn()
|
player.start_turn()
|
||||||
|
|
||||||
func end_current_turn(): # End the current turns
|
func end_current_turn():
|
||||||
if multiplayer.is_server():
|
if multiplayer.is_server():
|
||||||
next_turn()
|
next_turn()
|
||||||
rpc("sync_turn_index", current_turn_index) # RPC call to sync turn index
|
rpc("sync_turn_index", current_turn_index)
|
||||||
|
|
||||||
func _on_message_input_text_submitted(new_text): # Handle message input
|
func _on_message_input_text_submitted(new_text):
|
||||||
if new_text.length() > max_message_input_char:
|
if new_text.length() > max_message_input_char:
|
||||||
new_text = new_text.substr(0, max_message_input_char) + " ... "
|
new_text = new_text.substr(0, max_message_input_char) + " ... "
|
||||||
local_player_character.rpc("display_message", new_text) # RPC call to display message
|
local_player_character.rpc("display_message", new_text)
|
||||||
$MessageInput.text = ""
|
$MessageInput.text = ""
|
||||||
$MessageInput.release_focus()
|
$MessageInput.release_focus()
|
||||||
|
|
||||||
|
func move_bot(bot_id):
|
||||||
|
if multiplayer.is_server():
|
||||||
|
var bot = get_node(str(bot_id))
|
||||||
|
if bot:
|
||||||
|
var target_position = bot.find_random_valid_position()
|
||||||
|
if target_position != bot.current_position:
|
||||||
|
var path = bot.enhanced_gridmap.find_path(Vector2(bot.current_position), Vector2(target_position))
|
||||||
|
|
||||||
|
if path.size() > 1:
|
||||||
|
path.pop_front() # Remove the starting position
|
||||||
|
bot.move_bot_along_path(path)
|
||||||
|
else:
|
||||||
|
print("No valid path found for bot")
|
||||||
|
end_current_turn()
|
||||||
|
else:
|
||||||
|
print("No new valid position found for bot")
|
||||||
|
end_current_turn()
|
||||||
|
else:
|
||||||
|
print("Bot not found")
|
||||||
|
end_current_turn()
|
||||||
|
|||||||
@@ -72,6 +72,25 @@ func find_valid_starting_position() -> Vector2i: # Find a valid starting positi
|
|||||||
|
|
||||||
return Vector2i(0, 0) # Default position if no valid position found
|
return Vector2i(0, 0) # Default position if no valid position found
|
||||||
|
|
||||||
|
func find_random_valid_position() -> Vector2i:
|
||||||
|
var rng = RandomNumberGenerator.new()
|
||||||
|
rng.randomize()
|
||||||
|
|
||||||
|
var max_attempts = 100
|
||||||
|
var attempts = 0
|
||||||
|
|
||||||
|
while attempts < max_attempts:
|
||||||
|
var random_position = Vector2i(rng.randi_range(0, enhanced_gridmap.columns - 1),
|
||||||
|
rng.randi_range(0, enhanced_gridmap.rows - 1))
|
||||||
|
var cell_item = enhanced_gridmap.get_cell_item(Vector3i(random_position.x, 0, random_position.y))
|
||||||
|
|
||||||
|
if cell_item not in enhanced_gridmap.non_walkable_items and random_position != current_position:
|
||||||
|
return random_position # Return valid position
|
||||||
|
|
||||||
|
attempts += 1
|
||||||
|
|
||||||
|
return current_position # Return current position if no new valid position found
|
||||||
|
|
||||||
func _physics_process(_delta): # Called every physics frame
|
func _physics_process(_delta): # Called every physics frame
|
||||||
if is_multiplayer_authority():
|
if is_multiplayer_authority():
|
||||||
rpc("remote_set_position", global_position) # RPC call to sync position
|
rpc("remote_set_position", global_position) # RPC call to sync position
|
||||||
@@ -139,6 +158,24 @@ func move_player_along_path(path: Array): # Move player along calculated path
|
|||||||
end_turn()
|
end_turn()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func move_bot_along_path(path: Array):
|
||||||
|
is_player_moving = true
|
||||||
|
var tween = create_tween()
|
||||||
|
tween.set_trans(Tween.TRANS_CUBIC)
|
||||||
|
tween.set_ease(Tween.EASE_IN_OUT)
|
||||||
|
|
||||||
|
for point in path:
|
||||||
|
var target_position = grid_to_world(Vector2i(point.x, point.y))
|
||||||
|
tween.tween_property(self, "position", target_position, 0.5)
|
||||||
|
|
||||||
|
tween.tween_callback(func():
|
||||||
|
current_position = Vector2i(path[-1].x, path[-1].y)
|
||||||
|
is_player_moving = false
|
||||||
|
enhanced_gridmap.clear_path_visualization()
|
||||||
|
has_moved_this_turn = true
|
||||||
|
end_turn()
|
||||||
|
)
|
||||||
|
|
||||||
func update_player_position(grid_position: Vector2i): # Update player's position
|
func update_player_position(grid_position: Vector2i): # Update player's position
|
||||||
position = grid_to_world(grid_position)
|
position = grid_to_world(grid_position)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user