so there are 2 scripts: script and localscript.
The script determines how many seconds there will be and then it fires it to all player clients & the localscript changes the text to seconds. But when i tested the game the countdow freezes either at a number or a random number anyway here's the script again:
script:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:WaitForChild("IntermissonEvent")
local secondsRemaining = 15
for t = secondsRemaining, 0, -1 do
remoteEvent:FireAllClients(t)
wait(1)
end
localscript:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:WaitForChild("IntermissonEvent")
local function onTimerUpdate(seconds)
script.Parent.Text =(seconds)
wait(15)
script.Parent.Parent.CountdownText.Visible = false
script.Parent.Parent.IntermissionText.Visible = false
script.Parent.Parent.TextLabel.Text ="Vote for a Map!"
script.Parent.Parent.MapVotingFrame.Visible = true
end
remoteEvent.OnClientEvent:Connect(onTimerUpdate)
Your LocalScript is running all of this logic every single time the server fires the event. Instead of waiting, check the value with an if-then.
local function onTimerUpdate(seconds)
script.Parent.Text = tostring(seconds)
if seconds == 0 then
script.Parent.Parent.CountdownText.Visible = false
script.Parent.Parent.IntermissionText.Visible = false
script.Parent.Parent.TextLabel.Text = "Vote for a Map!"
script.Parent.Parent.MapVotingFrame.Visible = true
end
end
Related
Cant figure out what the problem is
while wait(.5) do
local children = game.Players:GetChildren("Humanoid")
for i = 1, #children do
local hum = children[i] .Character.Humanoid
hum.HeadScale.Value = children[i].leaderstats.Points.Value/50 +1
hum.BodyHeightScale.Value = children[i].leaderstats.Points.Value/50 +1
hum.BodyWidthScale.Value = children[i].leaderstats.Points.Value/50 +1
hum.BodyDepthScale.Value = children[i].leaderstats.Points.Value/50 +1
hum.WalkSpeed = children[i].leaderstats.Points.Value/3.12
hum.JumpPower = children[i].leaderstats.Points.Value
hum.MaxHealth = children[i].leaderstats.Points.Value+25
end
end
was trying to get a simple size script to work.
The attempt to index nil with Humanoid error is telling you that the object that you are trying to grab the Humanoid out of doesn't exist. This line specifically :
local hum = children[i].Character.Humanoid
When a player joins the game, there is an indeterminate amount of time before their character model actually spawns into the world. So between when they join and when their character spawns, the Player.Character property is nil.
Your code does not handle the possibility that the character model is nil, and you are trying to access the humanoid immediately.
A safer approach is not to use a loop, but to observe changes to the leaderstats values and react to those changes. So in your code that creates your leaderstats objects, do something like this :
local Players = game:GetService("Players")
local function updateCharacter(hum : Humanoid, points : number)
local bodyScale = (points / 50) + 1
local walkSpeed = points / 3.12
local jump = points
local health = points + 25
hum.HeadScale.Value = bodyScale
hum.BodyHeightScale.Value = bodyScale
hum.BodyWidthScale.Value = bodyScale
hum.BodyDepthScale.Value = bodyScale
hum.WalkSpeed = walkSpeed
hum.JumpPower = jump
hum.MaxHealth = health
end
Players.PlayerAdded:Connect(function(player)
-- when a player joins the game, give them a leaderstats folder
local leaderstatsFolder = Instance.new("Folder")
leaderstatsFolder.Name = "leaderstats"
local pointsValue = Instance.new("IntValue", leaderstats)
pointsValue.Name = "Points"
pointsValue.Value = 0 -- or load from dataStores
leaderstatsFolder.Parent = player
-- listen for changes to the points and resize the character
pointsValue.Changed:Connect(function(newValue)
-- escape if the character doesn't exist
local character = player.Character
if character then
updateCharacter(character.Humanoid, newValue)
end
end)
-- when the character model spawns into the world, update it immediately with the player's point size
player.CharacterAdded:Connect(function(character)
updateCharacter(character.Humanoid, pointsValue.Value)
end)
end)
I seem to be having an issue of every time I want to pass a function when an event happens such as a Humanoid.Died() or a BindableEvent it runs the function 20+ times, also adding to an IntegerValue that many times as well. I have tried debounces, BindableEvents, connection:Disconnect(), etc. Is there something I'm doing wrong or missing?
Updated original code:
function module.damageHumanoid(attacker, player, humanoid, damage)
local connection
local debounce = false
connection = humanoid.Died:Connect(function()
if not debounce then
debounce = true
connection:Disconnect()
module.onDeath(player)
end
end)
if player:FindFirstChild("damage") == nil then
newFolder = Instance.new("Folder")
newFolder.Name = "damage"
newFolder.Parent = player
end
if newFolder:FindFirstChild(tostring(attacker)) == nil then
record = Instance.new("IntValue")
record.Name = tostring(attacker)
record.Parent = newFolder
end
if record.Value >= 100 then -- sanity check
else
record.Value = record.Value + damage
end
return humanoid:TakeDamage(damage)
end
Which triggers this code:
function module.onDeath(player)
if player:FindFirstChild("damage") ~= nil then
local folder = player:WaitForChild("damage")
local contents = folder:GetChildren()
for i,v in pairs(contents) do
local item = folder[tostring(v)]
damages[item.Name] = item.Value
end
end
local debounce = false
if not debounce then
debounce = true
module.handleKill(damages)
end
end
This is the sword script's function:
function Blow(Hit)
if not Hit or not Hit.Parent or not CheckIfAlive() or not ToolEquipped then
return
end
local RightArm = Character:FindFirstChild("Right Arm") or Character:FindFirstChild("RightHand")
if not RightArm then
return
end
local RightGrip = RightArm:FindFirstChild("RightGrip")
if not RightGrip or (RightGrip.Part0 ~= Handle and RightGrip.Part1 ~= Handle) then
return
end
local character = Hit.Parent
if character == Character then
return
end
local humanoid = character:FindFirstChildOfClass("Humanoid")
if not humanoid or humanoid.Health == 0 then
return
end
local player = Players:GetPlayerFromCharacter(character)
if player and player == Player then
return
end
UntagHumanoid(humanoid)
TagHumanoid(humanoid, Player)
module.damageHumanoid(plur, player, humanoid, Damage)
end
So I guess the way I was trying to use debounce isn't correct anymore. I referred to the Roblox documentation and found this: https://create.roblox.com/docs/scripting/scripts/debounce
If anyone would like to know what ended up working for me here it is:
humanoid.Died:Connect(function()
if not humanoid:GetAttribute("Killed") then
humanoid:SetAttribute("Killed", true)
module.onDeath(player)
task.wait(10)
humanoid:SetAttribute("Killed", true)
end
end)
I'm trying(I'm very new) to make a game where you have to attack each other with a boat. There is a button on each island and when you press it, a boat should appear. (this works so far)
But as soon as you want to spawn a new boat it removes everyones boat. I thought it makes sense to use player.id but this still won't work. Does anyone know the solution?
Below you will find the code thats hidden in a part.
Thanks!
CODE:
local cd = script.Parent.ClickDetector
local boat = script.Parent.Parent.Firstboat
local button = script.Parent
local debounce = false
game.Players.PlayerAdded:Connect(function(player)
print(player.UserId)
local plruserid = player.UserId
print(player.Name)
boat.Parent = game.ServerStorage
cd.MouseHoverEnter:Connect(function()
button.Transparency = 0.5
end)
cd.MouseHoverLeave:Connect(function()
button.Transparency = 0
end)
cd.MouseClick:Connect(function()
local SetNameToBoat = plruserid
print (SetNameToBoat)
local oldboat = workspace:FindFirstChild(SetNameToBoat)
if not debounce then
if oldboat then
oldboat : destroy()
end
debounce = true
local NewBoat = boat:clone()
NewBoat.Name = (SetNameToBoat)
NewBoat.Parent = game.Workspace
wait(5)
debounce = false
end
end)
end)
I simplified the code and found the solution:
local cd = workspace.Button:WaitForChild('ClickDetector')
local boat = game:GetService('ServerStorage'):WaitForChild('Boat')
local button = workspace:WaitForChild('Button')
local debounce = false
cd.MouseHoverEnter:Connect(function()
button.Transparency = 0.5
end)
cd.MouseHoverLeave:Connect(function()
button.Transparency = 0
end)
cd.MouseClick:Connect(function(player)
local plruserid = player.UserId
local SetNameToBoat = plruserid
print(SetNameToBoat)
local oldboat = workspace:FindFirstChild(SetNameToBoat)
if not debounce then
if oldboat then
oldboat:destroy()
end
debounce = true
local NewBoat = boat:clone()
NewBoat.Name = SetNameToBoat
NewBoat.Parent = game.Workspace
wait(5)
debounce = false
end
end)
So I am trying to make a game, but cant keep the stats. I already have a working death counter but can't figure out how to save it, it resets everytime I rejoin. Here are two codes I've tried:
1)
local pointsDataStore = game:GetService("DataStoreService"):GetDataStore("Deaths")
game.Players.PlayerAdded:Connect(function(player)
local playerKey = "Player_" .. player.UserId
local success, err = pcall(function()
pointsDataStore:UpdateAsync(playerKey, function(oldValue)
local newValue = oldValue or 0
newValue = newValue + 0
return newValue
end)
end)
end)
2)
local DS = game:GetService("DataStoreService"):GetDataStore("Points")
game.Player.PlayerAdded:connect(plr)
local leaderstats = Instance.new("Model",plr)
leaderstats.Name = "leaderstats"
local currency = Instance.new("IntValue", leaderstats)
currency.Name = "Deaths"
currency.Value = 1
while wait(5) do
DS:SetAsync(plr.userId.."_DS", currency.Value)
end
end)
I would load the value from a datastore when the player joins, then increment it on each death and also save it to the datastore.
Note, that for triggering death, the script is using the Humanoid.Died event.
local deathsStore = game:GetService("DataStoreService"):GetDataStore("Deaths")
function playerAddedHandler(plr)
-- key that is used to store the death value
local playerKey = "Player_" .. plr.UserId
-- Add leader board
local leaderstats = Instance.new("Folder", plr)
leaderstats.Name = "leaderstats"
-- Add "Deaths" column to leader board
local deaths = Instance.new("IntValue", leaderstats)
deaths.Name = "Deaths"
-- Load Deaths value from previous game
deaths.Value = deathsStore:GetAsync(playerKey)
-- Hook up event handler that is triggered when character dies
plr.CharacterAdded:Connect(function(char)
char.Humanoid.Died:Connect(function()
-- increment death value on the leader board
plr.leaderstats.Deaths.Value = plr.leaderstats.Deaths.Value + 1
-- save the value in our deaths datastore
local success, err = pcall(function()
deathsStore:SetAsync(playerKey, plr.leaderstats.Deaths.Value)
end)
end)
end)
end
game.Players.PlayerAdded:Connect(playerAddedHandler) -- call function "playerAddedHandler" every time a player joins the game
Also. Don't forget to enable datastore usage, otherwise it will give you a 403 error in your output. You do that on the roblox website in your game's basic settings:
Here's the error and what I've tried.
Error: Workspace.Part.Script:4: attempt to index nil with 'leaderstats'
My code:
Making Leaderstats:
game.Players.PlayerAdded:Connect(function(plr)
local ls = Instance.new("Model")
ls.Name = "leaderstats"
ls.Parent = plr
local m = Instance.new("IntValue")
m.Name = "Stars"
m.Value = 0
m.Parent = ls
end)
Touch Code:
local collected = false
script.Parent.Touched:Connect(function()
if collected == false then
game.Players.LocalPlayer.leaderstats.Stars.Value = game.Players.LocalPlayer.leaderstats.Stars.Value + 1
end
collected = true
end)
A server script would suit your need better. In a localscript, the change would only appear for the player. Also, it's better practice to use the Players service offered by Roblox. Here's an example:
local Players = game:GetService('Players')
local collected = false
script.Parent.Touched:Connect(function(partTouched)
if partTouched.Parent:IsA('Model') and partTouched.Parent:FindFirstChild('Humanoid') and partTouched:IsA('BasePart') then -- Is this a player? If so, then..
local player = Players:GetPlayerFromCharacter(partTouched.Parent)
if collected == false then
player.leaderstats.Stars.Value += 1 -- shorter syntax
end
collected = true
--script.Parent:Destroy() optional if this part won't be used again.
end
end)
If you're planning to use this for many parts, using a central ModuleScript would save you lots of changing things back and forth: https://developer.roblox.com/en-us/api-reference/class/ModuleScript