Making a Game - Resetting the Game - EP 23
by Damien
Video Tutorial
Aims of this Tutorial
- Ask all players whether they want a rematch or not.
- If they all do, reset the game with all the players still in the game.
- If they do not, reset the clients to the lobby and have the server ready to accept new connections again.
Asking the players
This part is very simple. We just add 2 buttons to the banner that announces the victor on either side. One says 'Rematch' and the other says 'Exit'. We then connect each of those to new functions in the arena script.
Rematch
Since everyone needs to hit the rematch button for us to rematch, we can put code in the rematch function that we can expect to have run before restarting. We therefore delete our players on the client when we hit rematch. The code for the client is as follows.
func _on_RematchButton_pressed():
$WinnerPanel/RematchButton.disabled = true
$Camera.clear_register()
for player_id in players.keys():
players[player_id].queue_free()
players.clear()
winner_name = null
rpc_id(1, "request_rematch", get_tree().get_network_unique_id())
You may notice a function that we have not written yet in here. The camera needs to get rid of the old players in its array of all players to follow. This function is given below.
func clear_register():
players.clear()
locked = false
index = 0
We also need to create the remote procedure call on the server that we specified earlier. This will keep track of who has told us they want a rematch and once we get a verification from everyone, we can go ahead and start the rematch. The following is code from the server.
remote func request_rematch(id) -> void:
if (not id in rematch_requests) and id in get_parent().ids:
rematch_requests.append(id)
if len(rematch_requests) == len(get_parent().ids):
start_rematch()
func start_rematch() -> void:
for player_id in players.keys():
players[player_id].queue_free()
players.clear()
yield(get_tree(), "idle_frame")
deaths = 0
rematch_requests.clear()
init()
rematch_requests
is an array to hold the ids of players who want to rematch. You will notice that we have a weird line of code: yield(get_tree(), "idle_frame")
. This is what we do to wait one frame. This gives time to the queue_free()
to take effect before the init()
function creates more players. This is enough code to do a complete rematch since we are basically reusing the code that we had for just starting the game!
Exiting the Game
If only one player asks to exit, we can no longer play the game since we have insufficient players. So when we have the player click the exit button, we just make an rpc call and then we get told later to close our connection. The code on the client is:
# Arena.gd
func _on_ExitButton_pressed():
get_parent().exit_button_pressed()
# RootNode.gd
func exit_button_pressed():
rpc_id(1, "request_exit")
This rpc call on the server is going to tell everyone to quit and then start a timer to quit itself. This code is shown below.
func end_game() -> void:
$Arena.queue_free()
console_print("Ending Game...")
# Reset root node data
ids = []
ready_ids = []
name_dict = {}
color_dict = {}
peer.close_connection()
peer.create_server( PORT, MAX_PLAYERS )
peer.refuse_new_connections = false
remote func request_exit() -> void:
console_print("Exit requested...")
rpc("exit_requested")
$ExitTimer.start()
When we exit the game, we also need to reset the data specific to the players who we just kicked out. We can then start up a new server and accept connections. The rpc call on the client will make the clients disconnect and go to the lobby.
func switch_to_lobby():
$Arena.queue_free()
var lobby = Lobby.instance()
add_child(lobby)
$Lobby/StartButton.connect("pressed", self, "_on_StartButton_pressed")
console_print('Switching back to Lobby...')
peer.close_connection()
remote func exit_requested():
switch_to_lobby()
This removes all traces of the previous game, like the server did, and creates a new lobby to allow the player to connect to a new game. We also need to reconnect the start button as we just made a new one that will not be connected.