I’m trying to make a countdown that counts down from 5 to 0, while changing lights on my light post at the same time how I want them to. I want it to fire this countdown for all players when someone clicks the “Start Race” button. I first started by making one script that did it all (with no remote events), which I put in the StartGui. I got some help with it to understand that I need to use Remote Events to accomplish this. So, I took the code from the original script and tried using Remote Events.
I need help with the scripts I made to do this, as they’re not doing anything when I click the “Start Race” button, even though there are no apparent errors in the output. I’m likely doing something wrong with the Remote Events and how I integrated them, as I’m new to them.
Here’s a screenshot of the Explorer, and the script and localscript I’m using.
In Script:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RemoteEvent = ReplicatedStorage:WaitForChild("RemoteEventCountdown")
local text = game.StarterGui.ScreenGui.Countdown
local button = game.StarterGui.ScreenGui.StartRace
local seconds = game.ReplicatedStorage.Time
text.Visible = false
button.MouseButton1Click:connect(function(play)
text.Visible = true
RemoteEvent:FireAllClients()
end)
In LocalScript:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RemoteEvent = ReplicatedStorage:WaitForChild("RemoteEventCountdown")
RemoteEvent.OnClientEvent:connect(function()
local text = game.StarterGui.ScreenGui.Countdown
local button = game.StarterGui.ScreenGui.StartRace
local seconds = game.ReplicatedStorage.Time
text.Text = seconds.Value -- Makes the text in the TextLabel the same as what is in the "Time" Value under ScreenGui.
--text.Visible = false
local function PreStage()
local prestagelights = game.Workspace["Racing System"]["Countdown Lights"].RaceTimer3.StageSigns.PreStageLights:FindFirstChildOfClass("PointLight")
local prestagelightsparts = game.Workspace["Racing System"]["Countdown Lights"].RaceTimer3.StageSigns.PreStageLights:GetChildren()
for _, prestagelightsparts in pairs(prestagelightsparts) do
if prestagelights then
prestagelights.Enabled = true
end
end
for _, prestagelightsparts in pairs(prestagelightsparts) do
prestagelightsparts.Material = Enum.Material.Neon
end
end
local function Stage()
local stagelights = game.Workspace["Racing System"]["Countdown Lights"].RaceTimer3.StageSigns.StageLights:FindFirstChildOfClass("PointLight")
local stagelightsparts = game.Workspace["Racing System"]["Countdown Lights"].RaceTimer3.StageSigns.StageLights:GetChildren()
for _, stagelightsparts in pairs(stagelightsparts) do
if stagelights then
stagelights.Enabled = true
end
end
for _, stagelightsparts in pairs(stagelightsparts) do
stagelightsparts.Material = Enum.Material.Neon
end
end
local function Red()
local RedLights = game.Workspace["Racing System"]["Countdown Lights"].RaceTimer3.RedLights.Lights:FindFirstChildOfClass("PointLight")
local RedLightsParts = game.Workspace["Racing System"]["Countdown Lights"].RaceTimer3.RedLights.Lights:GetChildren()
for _, RedLightsParts in pairs(RedLightsParts) do
if RedLights then
RedLights.Enabled = true
end
end
for _, RedLightsParts in pairs(RedLightsParts) do
RedLightsParts.Material = Enum.Material.Neon
end
end
local function Yellow()
local YellowLights = game.Workspace["Racing System"]["Countdown Lights"].RaceTimer3.YellowLights.Lights:FindFirstChildOfClass("PointLight")
local YellowLightsParts = game.Workspace["Racing System"]["Countdown Lights"].RaceTimer3.YellowLights.Lights:GetChildren()
for _, YellowLightsParts in pairs(YellowLightsParts) do
if YellowLights then
YellowLights.Enabled = true
end
end
for _, YellowLightsParts in pairs(YellowLightsParts) do
YellowLightsParts.Material = Enum.Material.Neon
end
end
local function Green()
local GreenLights = game.Workspace["Racing System"]["Countdown Lights"].RaceTimer3.GreenLights.Lights:FindFirstChildOfClass("PointLight")
local GreenLightsParts = game.Workspace["Racing System"]["Countdown Lights"].RaceTimer3.GreenLights.Lights:GetChildren()
for _, GreenLightsParts in pairs(GreenLightsParts) do
if GreenLights then
GreenLights.Enabled = true
end
end
for _, GreenLightsParts in pairs(GreenLightsParts) do
GreenLightsParts.Material = Enum.Material.Neon
end
end
local function Countdown() -- Makes the countdown code into a local function.
text.Visible = true
if seconds.Value == 5 then
PreStage()
end
while seconds.Value > 0 do
seconds.Value = seconds.Value - 1
wait(1)
script.Parent.Text = seconds.Value -- Makes the TextLabel countdown from whatever number is in the "Time" Value under ScreenGui.
if seconds.Value == 3 then
Stage()
end
if seconds.Value == 2 then
Red()
end
if seconds.Value == 1 then
Yellow()
end
if seconds.Value == 0 then
script.Parent.Text = "GO!"
Green()
end
if script.Parent.Text == "GO!" then
wait(1)
text.Visible = false
end
end
-- Waits for _ seconds, and then makes the TextLabel not visible.
end
end)
local text = game.StarterGui.ScreenGui.Countdown
local button = game.StarterGui.ScreenGui.StartRace
You’re using starterGui rather than the actual player Gui. The Guis that users see on the screen are NOT in the StarterGui. They are instantly replicated from the StarterGui into every player’s “PlayerGui” (located within the player). The most ideal way to handle this would be to just have a local script inside the GUI, so you can reference the GUI with “script.Parent” or whatever. Notice how I said local script, because it is more optimal to run LocalScripts on Guis so that everything is handled only on a client-to-client basis.
The second issue I notice is that your “onClientEvent” function never runs. All you do is define functions in it, but never actually run the functions.
Try fixing these two things and let me know if the problem still persists, then I’ll take a deeper look into your script.
I completely forgot about the first thing you noticed, even though I’ve ran into the same problem before. So would I change it to this?:
local text = game.PlayerGui.ScreenGui.Countdown
local button = game.PlayerGui.ScreenGui.StartRace
And for the second thing you mentioned, how do I run the “onClientEvent” function? I thought that the “RemoteEvent:FireAllClients()” in the Script is supposed to fire it. By the way, I’ve only been doing Roblox Lua scripting for about 3 weeks now, and I’m new to the concept of RemoteEvents. Thanks very much for help!
local text = game.PlayerGui.ScreenGui.Countdown
local button = game.PlayerGui.ScreenGui.StartRace
Not quite. What Roblox does is, every time a player joins, things in the “StarterGui” are replicated (cloned and then moved) into the player’s PlayerGui. When you join the game in Studio, go into the explorer and go to Players > MJTFreeTime, and you will see there is “PlayerGui.” Every player has their own PlayerGui. This means that it is best to handle GUIs with a local script that is inside of the Gui (because if it were server sided, you would have 1 script that will constantly need to control the Guis of a large number of people). What I recommend you do is that you remove this “server to client” communication entirely and just run this script fully locally. Or, you could switch the two functions around, since it would make more sense for the “Red(),” “Countdown(),” etc. functions to be run on the server while the Gui handler is run on the client.
When I said your functions aren’t running, it had nothing to do with your use of onClientEvent or FireAllClients()-- you are using both of those correctly. The issue was that you were only defining the functions (you were writing local function something() end) but never actually called the function in the script.
About running it locally, the problem with that is that I want all players in the game to have the countdown show up. That’s why I ended up trying to use Remote Events.
When you say to have the GUI handler on the local script, would I just switch the code out between the server and local script? I did find a problem with that a few days ago, where you can’t use “FireAllClients()” if you’re firing from a local script to a server script.
Is there a way you’d recommend I try to switch out the GUI handler to be the local script? Thanks very much.
Yeah, I got the part where he said that I forgot to call the Countdown() function.
If I used a localscript in the GUI to be the GUI handler and detect if someone clicked it, like what my server script is doing, my question is, how would I do that while being able to do FireAllClients()? As I was saying before, from what I understand, FireAllClients() can only be used from a serverscript to a localscript.
Ah, I wasn’t thinking about the fact that you need to fire all clients after clicking a screenGUI button. I suppose what you could do is have the local script handle the Click, have it fire a remote event to the server, and the server could then do :FireAllClients() back to the client which would, then, start the countdown and stuff. Definitely not the most efficient way, though. I wish I could think of something better. It’d be nice if Roblox allowed you to do :FireAllClients from the client, but you aren’t able to.
Another way to do it, is to have a boolValue in either workspace or replicated storage.
Whenever some clicks the start game, you would change the boolValue to True.
Then in your local script, you would detect that the bool Value has changed, check if the new value is true and if it is, then you would hide the Gui (this is the local script in your Gui).
I think this is another way to set up this event.
First I’m trying the 3 RemoteEvent approach. I’ve been trying to do this, but when I click the Start Race button it doesn’t do anything. I also, just now, tried placing the two server scripts inside of StarterPlayer—StarterPlayerScripts, but still got nothing.
Here’s a screenshot of the explorer, and the scripts I’ve been trying to make work so far:
Explorer Screenshot:
Server Script:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RemoteEvent1 = ReplicatedStorage:WaitForChild("RemoteEventCountdown")
local RemoteEvent2 = ReplicatedStorage:WaitForChild("RemoteEventCountdown2")
RemoteEvent1.OnServerEvent:Connect(function(play)
RemoteEvent2:FireAllClients(play)
end)
LocalScript:
local LocalPlayer = game.Players:WaitForChild("LocalPlayer")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RemoteEvent1 = ReplicatedStorage:WaitForChild("RemoteEventCountdown")
local RemoteEvent2 = ReplicatedStorage:WaitForChild("RemoteEventCountdown2")
local button = LocalPlayer.PlayerGui.ScreenGui.StartRace
button.MouseButton1Click:connect(function(play)
RemoteEvent1:FireServer(play)
end)
LocalScript2:
local LocalPlayer = game.Players:WaitForChild("LocalPlayer")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RemoteEvent1 = ReplicatedStorage:WaitForChild("RemoteEventCountdown")
local RemoteEvent2 = ReplicatedStorage:WaitForChild("RemoteEventCountdown2")
RemoteEvent2.OnClientEvent:Connect(function()
local text = LocalPlayer.PlayerGui.ScreenGui.Countdown
local button = LocalPlayer.PlayerGui.ScreenGui.StartRace
local seconds = ReplicatedStorage:WaitForChild("Time")
text.Text = seconds.Value -- Makes the text in the TextLabel the same as what is in the "Time" Value under ScreenGui.
text.Visible = false
local function PreStage()
local prestagelights = game.Workspace["Racing System"]["Countdown Lights"].RaceTimer3.StageSigns.PreStageLights:FindFirstChildOfClass("PointLight")
local prestagelightsparts = game.Workspace["Racing System"]["Countdown Lights"].RaceTimer3.StageSigns.PreStageLights:GetChildren()
for _, prestagelightsparts in pairs(prestagelightsparts) do
if prestagelights then
prestagelights.Enabled = true
end
end
for _, prestagelightsparts in pairs(prestagelightsparts) do
prestagelightsparts.Material = Enum.Material.Neon
end
end
local function Stage()
local stagelights = game.Workspace["Racing System"]["Countdown Lights"].RaceTimer3.StageSigns.StageLights:FindFirstChildOfClass("PointLight")
local stagelightsparts = game.Workspace["Racing System"]["Countdown Lights"].RaceTimer3.StageSigns.StageLights:GetChildren()
for _, stagelightsparts in pairs(stagelightsparts) do
if stagelights then
stagelights.Enabled = true
end
end
for _, stagelightsparts in pairs(stagelightsparts) do
stagelightsparts.Material = Enum.Material.Neon
end
end
local function Red()
local RedLights = game.Workspace["Racing System"]["Countdown Lights"].RaceTimer3.RedLights.Lights:FindFirstChildOfClass("PointLight")
local RedLightsParts = game.Workspace["Racing System"]["Countdown Lights"].RaceTimer3.RedLights.Lights:GetChildren()
for _, RedLightsParts in pairs(RedLightsParts) do
if RedLights then
RedLights.Enabled = true
end
end
for _, RedLightsParts in pairs(RedLightsParts) do
RedLightsParts.Material = Enum.Material.Neon
end
end
local function Yellow()
local YellowLights = game.Workspace["Racing System"]["Countdown Lights"].RaceTimer3.YellowLights.Lights:FindFirstChildOfClass("PointLight")
local YellowLightsParts = game.Workspace["Racing System"]["Countdown Lights"].RaceTimer3.YellowLights.Lights:GetChildren()
for _, YellowLightsParts in pairs(YellowLightsParts) do
if YellowLights then
YellowLights.Enabled = true
end
end
for _, YellowLightsParts in pairs(YellowLightsParts) do
YellowLightsParts.Material = Enum.Material.Neon
end
end
local function Green()
local GreenLights = game.Workspace["Racing System"]["Countdown Lights"].RaceTimer3.GreenLights.Lights:FindFirstChildOfClass("PointLight")
local GreenLightsParts = game.Workspace["Racing System"]["Countdown Lights"].RaceTimer3.GreenLights.Lights:GetChildren()
for _, GreenLightsParts in pairs(GreenLightsParts) do
if GreenLights then
GreenLights.Enabled = true
end
end
for _, GreenLightsParts in pairs(GreenLightsParts) do
GreenLightsParts.Material = Enum.Material.Neon
end
end
local function Countdown() -- Makes the countdown code into a local function.
text.Visible = true
if seconds.Value == 5 then
PreStage()
end
while seconds.Value > 0 do
seconds.Value = seconds.Value - 1
wait(1)
script.Parent.Text = seconds.Value -- Makes the TextLabel countdown from whatever number is in the "Time" Value under ScreenGui.
if seconds.Value == 3 then
Stage()
end
if seconds.Value == 2 then
Red()
end
if seconds.Value == 1 then
Yellow()
end
if seconds.Value == 0 then
script.Parent.Text = "GO!"
Green()
end
if script.Parent.Text == "GO!" then
wait(1)
text.Visible = false
end
Countdown()
end
-- Waits for _ seconds, and then makes the TextLabel not visible.
end
end)
end
end)
Okay, you’re now making everything much more complicated, I can’t really even understand the scripts you sent since they’re all over the place. So let’s start fresh and rethink how the script is supposed to work.
All you will need to do is this (like I said, maybe there’s a more efficient way but this is what comes to my head.)
Then, on the SAME local script mentioned before, you will want:
RemoteEvent.OnClientEvent:Connect(function()
-- Countdown and all of the other stuff you wanted
end)
Remember, in the LocalScript when you reference the GUI, make sure you use :WaitForChild() and stuff. Or, you could just insert the local script right into the GUI so you can make a script.Parent type of path instead.
Hey, that’s a much better way to work with it, thanks. I did it that way, but it still didn’t work. Keyword: “didn’t”.
It finally worked! Turns out, I simply called the “Countdown()” before the wrong “end”. I just called the countdown function in the function by accident lol.
Thanks so much you guys for helping me out! There’s still a couple things I gotta try to do to the countdown, but I’ve been struggling with this problem for over a week.