How do I add a replay button to my script?

  1. What do you want to achieve?
    I want the game to restart if the player clicks on the ‘Replay’ button.

  2. What is the issue?
    I’m not sure where to start ._. I’ve tried re-writing/re-arranging the script but it hasn’t been very successful.

game.ReplicatedStorage.Remotes.ChangeStatus.OnClientEvent:Connect(function(Stadium)
	script.Parent.Main.GameStatus.Text = "Waiting..."
	script.Parent.Main.Leave.Visible = true
	script.Parent.Main.Leave.MouseButton1Click:Connect(function()
		game.ReplicatedStorage.Remotes.Leave:FireServer(Stadium)
		script.Parent.Main.Leave.Visible = false
		script.Parent.Main.GameStatus.Text = ''
		script.Parent.Main.Up.Visible = false
		script.Parent.Main.Down.Visible = false
		script.Parent.Main.Left.Visible = false
		script.Parent.Main.Right.Visible = false
		cam.CameraType = Enum.CameraType.Custom
		song:Stop()
		
	end)
	repeat wait(.8)until workspace:FindFirstChild(Stadium.Name).FirstMic.Full.Value == true 
	if workspace:FindFirstChild(Stadium.Name).FirstMic.Full.Value == false then
		script.Parent.GameStatus.Text = ''
		
	else
		wait(3)
		song:Play()
		cam.CameraType = Enum.CameraType.Scriptable
		cam.CFrame = Stadium.CamPart.CFrame
		script.Parent.Main.GameStatus.Text = "Started!"
		script.Parent.Main.Up.Visible = true
		script.Parent.Main.Down.Visible = true
		script.Parent.Main.Left.Visible = true
		script.Parent.Main.Right.Visible = true
		script.Parent.Main.Leave.Visible = false
		song.Ended:Connect(function()
			finished = true
			script.Parent.Main.GameStatus.Text = 'Game Ended!'
			script.Parent.Main.Leave.Visible = true
			script.Parent.Main.Replay.Visible = true
		end)
			
		repeat wait(song.Difficulty.Value) 
			local number = math.round(song.PlaybackLoudness/math.random(40,65))
			local chosenArrow = math.clamp(number,1, #arrowTypes)
			coroutine.wrap(AddArrow)(arrowTypes[chosenArrow])
		until finished == true


	end
end)

I also have a TextButton named ‘Replay’ in my ‘Main’ ScreenGUI.

Hey!
What exactly you mean by “game to restart”? what is the game?

What I see in your client side script is:

  • Server fires a remote, your local script catch that (ChangeStatus remote)
  • Change text to “Waiting”
  • Connecting a button function to “leave”
  • “waiting” for a value.
  • Do an statement after found the value. If value becomes false status text to: " "
  • If the value is true, wait 3 seconds, start a song, change camera, enable some guis
  • When the song is over change text to Game Ended!

So, your game started depends on a call from server to client, to play a song, when the song is over, game is over?
And you want to? let the client to play a song again, change some text in the GUI and wait for the song to end again?

2 Likes

Hi there! Thank you soo very much for your reply!

My game is a dancing minigame where the player presses keyboard buttons to play (similar to FNF).
Here’s a video of what I have so far: https://vimeo.com/791416746
*The video will load in a few minutes, it has to optimize

Yes, when the song ends, the game is over. After the game is over, there will be two buttons for the player to click on— ‘Replay’ or ‘Leave’.

Also, I have a RE in ReplicatedStorage named ‘Leave’ and another named ‘ChangeStatus’ and finally, in my ServerScriptService I have a script (see below).

game.ReplicatedStorage.Remotes.Leave.OnServerEvent:Connect(function(player, Stadium)
	local MainStadium = workspace:FindFirstChild(Stadium.Name)
	for i, v in pairs(MainStadium:GetDescendants()) do
		if v.Name == 'Full' then
			v.Value = false
		end
		if v.Name == "ProximityPrompt" then
			v.Enabled = true
			end
	end
	player.Character.Humanoid.WalkSpeed = 16
	player.Character.Humanoid.JumpHeight = 7.2
end)
1 Like

I see, its looking good so far!

In server side you are firing this at some point: ChangeStatus:FireClient(player) to tell the client to start the song, showing GUIs and connecting buttons.

You would need to fire that again for a player to play the song again along with the GUIs states, etc

So you could connect the retry button in your GUI to a remote, asking the server to fire the ChangeStatus again for that player.

When the player clicks the retry button, the remote fires, server catches that signal, and decide if player can restart game or not, if its allowed, fire ChangeStatus:FireClient(player) for that player.
Just make sure you are not double connecting the buttons when that signal is get by the client.

1 Like

Would this work?

game.ReplicatedStorage.Remotes.ChangeStatus.OnClientEvent:Connect(function(Stadium)
	script.Parent.Main.GameStatus.Text = "Waiting..."
	script.Parent.Main.Leave.Visible = true
	if script.Parent.Main.Leave.MouseButton1Click:Connect(function() then
		game.ReplicatedStorage.Remotes.Leave:FireServer(Stadium)
		script.Parent.Main.Leave.Visible = false
		script.Parent.Main.Replay.Visible = false
		script.Parent.Main.GameStatus.Text = ''
		script.Parent.Main.Up.Visible = false
		script.Parent.Main.Down.Visible = false
		script.Parent.Main.Left.Visible = false
		script.Parent.Main.Right.Visible = false
		cam.CameraType = Enum.CameraType.Custom
		song = nil
		elseif script.Parent.Main.Replay.MouseButton1Click:Connect(function() then
game.ReplicatedStorage.Remotes.ChangeStatus:FireServer(Stadium)
	end)

I dont know, I dont think so, at the final lines you are doing an elseif check, trying to compare a function connected:

elseif script.Parent.Main.Replay.MouseButton1Click:Connect(function() then
game.ReplicatedStorage.Remotes.ChangeStatus:FireServer(Stadium)
	end)

And what is on server side? listening that ChangeStatus.OnServerEvent() ?

1 Like

I see what you mean!

So in my ServerScriptService script, I have to add something like:

game.ReplicatedStorage.Remotes.Replay.OnServerEvent:Connect(function(player, Stadium)
	local MainStadium = workspace:FindFirstChild(Stadium.Name)
	for i, v in pairs(MainStadium:GetDescendants()) do
		if v.Name == 'Full' then
			v.Value = true
		end
		if v.Name == "ProximityPrompt" then
			v.Enabled = false
			end
	end
	player.Character.Humanoid.WalkSpeed = 0	player.Character.Humanoid.JumpHeight = 0
end)

Then, instead of what I previously wrote I’d do:

game.ReplicatedStorage.Remotes.ChangeStatus.OnClientEvent:Connect(function(Stadium)
	script.Parent.Main.GameStatus.Text = "Waiting..."
	script.Parent.Main.Leave.Visible = true
	if script.Parent.Main.Leave.MouseButton1Click:Connect(function() then
		game.ReplicatedStorage.Remotes.Leave:FireServer(Stadium)
		script.Parent.Main.Leave.Visible = false
		script.Parent.Main.Replay.Visible = false
		script.Parent.Main.GameStatus.Text = ''
		script.Parent.Main.Up.Visible = false
		script.Parent.Main.Down.Visible = false
		script.Parent.Main.Left.Visible = false
		script.Parent.Main.Right.Visible = false
		cam.CameraType = Enum.CameraType.Custom
		song = nil
		elseif script.Parent.Main.Replay.MouseButton1Click:Connect(function() then
game.ReplicatedStorage.Remotes.Replay:FireServer(Stadium)
	end)

	repeat wait(.8)until workspace:FindFirstChild(Stadium.Name).FirstMic.Full.Value == true
if workspace:FindFirstChild(Stadium.Name).FirstMic.Full.Value == false then
		script.Parent.GameStatus.Text = ''
		
	else
		wait(3)
		song = game.ReplicatedStorage.Songs:GetChildren()[math.random(#game.ReplicatedStorage.Songs:GetChildren())]
		song:Play()
		cam.CameraType = Enum.CameraType.Scriptable
		cam.CFrame = Stadium.CamPart.CFrame
		script.Parent.Main.GameStatus.Text = "Started!"
		script.Parent.Main.Up.Visible = true
		script.Parent.Main.Down.Visible = true
		script.Parent.Main.Left.Visible = true
		script.Parent.Main.Right.Visible = true
		script.Parent.Main.Leave.Visible = false
		script.Parent.Main.Replay.Visible = false
		song.Ended:Connect(function()
			finished = true
			script.Parent.Main.GameStatus.Text = 'Game Ended!'
			script.Parent.Main.Leave.Visible = true
			script.Parent.Main.Replay.Visible = true
		end)
			
		repeat wait(song.Difficulty.Value) 
			local number = math.round(song.PlaybackLoudness/math.random(40,65))
			local chosenArrow = math.clamp(number,1, #arrowTypes)
			coroutine.wrap(AddArrow)(arrowTypes[chosenArrow])
		until finished == true

	end
end)

I suggest you handle the buttons connections in a different way. Like connecting everything since the beginning, only once.

And rebuild how the player will start, leave and retry the game.

Mainly, you want to keep more stuff server sided, and do checks when player joins, when player clicks start game, leave, retry.

1 Like
Before helping you with your issue you may want to read this:

Looking at your code I think you need to start learning about how to format code and use variables.
First, to make your code readable (not just to yourself! it’s also so others can read the code easier.), declare any Service or Instance at the start of the script:

local ReplicatedStorage = game:GetService("ReplicatedStorage")

Here are a few tips:

  • Don’t use game.Players or game.Workspace. Use game:GetService("Players") and the word workspace.
    Let’s put an example, what’s easier to do here?
script.Parent.Parent.Value = true

Or…

local value = script.Parent.Parent
value.Value = true

To yield the script please use task.wait() instead of wait(). It is way more efficient.

This way, if you ever need it again, you don’t need to type script.Parent.Parent.Parent.Parent.Parent… You can just declare it once!

Not mad because you’re not doing it right, it’s just a suggestion here!

Reading through the post, you have to manage buttons correctly and, as @Dev_Peashie said, keep things server-sided rather than keeping everything on the client.

  • For example, notes should be kept on the client in the case of a lag spike.
  • What you don’t want the client to see or know, in the server.

Sorry, I’d help you rewrite stuff and fixing your script but I can’t right now. If you still need help later, reply to this post and I’ll get back to you.

2 Likes

Thank you for your reply! I’m quite new to all of this — I’m self-taught and only started learning a few months ago.

I would sincerely appreciate your help whenever you are available!

I recommend you if want do a “replay” button for a history game or something like it do rejoin like here:

function rejoin()
  local ts = game:GetService("TeleportService")
  local p = game:GetService("Players").LocalPlayer
  ts:Teleport(game.PlaceId, p)
end

-- here call rejoin function when rejoin button is clicked
rejoin()

It is simple, and works fine, too many games use it, it will be fast, simple and will works better than other things. If you want save data you can use DataStores.

I think it’s better for me to go in Studio in order to help you out, but that’s obviously up to you. I’ve tried to fix the code, but since I am getting confused because you left out some functions or remotes I can’t do much. However I tried what I could…

...Or I think I did.
--- Server ---
local ReplicatedStorage: ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players: Players = game:GetService("Players")
local Remotes: Folder = ReplicatedStorage:WaitForChild("Remotes")
local Replay: RemoteEvent = Remotes:WaitForChild("Replay")

local function BeginGame(Stadium: Model)
	local MainStadium = workspace:FindFirstChild(Stadium.Name)
	for _, part in pairs(MainStadium:GetDescendants()) do
		if part.Name == "Full" then
			part.Value = true
		end
		if part.Name == "ProximityPrompt" then
			part.Enabled = false
		end
	end
end

Replay.OnServerEvent:Connect(function(player: Player, Stadium: Model)
	BeginGame(Stadium)
end)

--- Client ---
local ReplicatedStorage: ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players: Players = game:GetService("Players")
local Remotes: Folder = ReplicatedStorage:WaitForChild("Remotes")
local Songs: Folder = ReplicatedStorage:WaitForChild("Songs")
local ChangeStatus: RemoteEvent = Remotes:WaitForChild("ChangeStatus")
local Leave: RemoteEvent = Remotes:WaitForChild("Leave")

local frame = script.Parent.Main
local Main = {
	["Leave"] = frame.Leave,
	["Replay"] = frame.Replay,
	["GameStatus"] = frame.GameStatus,
	["Up"] = frame.Up,
	["Down"] = frame.Down,
	["Left"] = frame.Left,
	["Right"] = frame.Right
}
local cam = workspace.CurrentCamera
local song: Sound = nil

local function ChangingStatus(Stadium: Model)
	Main.GameStatus.Text = "Waiting..."
	Main.Leave.Visible = true
	local connection 
	connection = Main.Leave.Activated:Connect(function()
		Leave:FireServer(Stadium)
		Main.GameStatus.Text = ""
		for _, ui in Main do
			if not ui:IsA("TextLabel") then
				ui.Visible = false
			end
		end
		cam.CameraType = Enum.CameraType.Custom
		connection:Disconnect()
	end)
	connection:Disconnect()
end

local function BeginSong(Stadium)
	while not workspace:FindFirstChild(Stadium.Name) do task.wait() end
	task.wait(3)
	song = Songs:GetChildren()[math.random(#Songs:GetChildren())]
	song:Play()
	cam.CameraType = Enum.CameraType.Scriptable
	cam.CFrame = workspace:FindFirstChild(Stadium.Name).CamPart.CFrame
	Main.GameStatus.Text = "Started!"
	for _, ui in Main do
		if not ui:IsA("TextLabel") then
			ui.Visible = true
		end
	end

	while task.wait(song.Difficulty.Value) and not finished do
		local number = math.round(song.PlaybackLoudness/math.random(40,65))
		local chosenArrow = math.clamp(number,1, #arrowTypes)
		coroutine.wrap(AddArrow)(arrowTypes[chosenArrow])

		local connection 
		connection = song.Ended:Connect(function()
			connection:Disconnect()
			finished = true
			Main.GameStatus.Text = "Game Ended!"
			Main.Leave.Visible = true
			Main.Replay.Visible = true
			return nil
		end)
		connection:Disconnect()
	end
end

Main.Replay.Activated:Connect(function()
	BeginSong(Stadium)
end)