How can I wait in a repeat loop in Roblox Lua - lua

game.Workspace.PetRooms.FireRoom.FireRoom.Floor.Touched:Connect(function(hit)
local player = game.Players:GetPlayerFromCharacter(hit.parent)
local char = hit.Parent -- Character
local hum = char:FindFirstChild("Humanoid") -- Humanoid
if hum then -- If humanoid then...
if hum.Health ~= 0 and player.Team == game.Teams.Scientists then -- Makes sure that character is not dead; makes sure that character is a scientist
repeat
wait (10)
hum.Health = hum.Health - 10 -- Kills the character slowly
until hum.Health == 0
end
player.Team = game.Teams.Infected -- Changes the player's team to infected AFTER they die
end
end)
The "wait(10)" is supposed to wait 10 second in between every "- 10" health but the code just waits 10 seconds and then kills the player quickly.

You have this callback connected to the Touched event, and the event will fire every time a player touches the part. If the player is walking across the floor, it will fire every time the player's foot hits it.
What is probably happening is that this event is firing multiple times, and you have a bunch of these repeat-while loops all running at the same time, causing the player's health to drop very quickly.
I would recommend debouncing the connection so that only one loop happens per player :
-- create a map of players touching the floor
local playersTouching = {}
local floor = game.Workspace.PetRooms.FireRoom.FireRoom.Floor
floor.Touched:Connect(function(hit)
-- check that the thing that hit is a player
local char = hit.Parent -- Character
local hum = char:FindFirstChild("Humanoid") -- Humanoid
if hum == nil then
return
end
-- escape if this player is already touching the floor
local playerName = char.Name
if playersTouching[playerName] then
return
end
-- the player was not touching before, so flip the debounce flag
-- everything after this point happens once
playerTouching[playerName] = true
-- check if character is not dead and a scientist
local player = game.Players:GetPlayerFromCharacter(hit.parent)
local isScientist = player.Team == game.Teams.Scientists
local isAlive = hum.Health > 0
if isScientist and isAlive then
-- start a loop to kill the player
while hum.Health > 0 then
wait(10)
hum.Health = hum.Health - 10
end
-- Change the player's team to infected
player.Team = game.Teams.Infected
end
-- clear the debounce flag
playerTouching[playerName] = false
end)

i can't really think of anything besides GetPropertyChangedSignal
try that maybe

Related

Distance finder not printing text

I'm trying to make this sign that, when you step close enough, shows a GUI.
To test it, I made it print("It works!") but It won't print anything.
LocalScript:
local Players = game:GetService('Players')
local LocalPlayer = Players.LocalPlayer
for _,Player in next, Players:GetChildren() do
local character = Player.Character
if character and character.Parent and Player ~= LocalPlayer then
local Magnitude = (LocalPlayer.Character.HumanoidRootPart.Position - character.HumanoidRootPart.Position).magnitude
end
end
while true do
if Magnitude < 10 then
print("It's working!")
end
end
The issue is that you have put a LocalScript into a Part in the Workspace. If you check the LocalScript docs, you'll see that ...
a LocalScript will only run Lua code if it is a descendant of one of the following objects:
A Player’s Backpack, such as a child of a Tool
A Player’s character model
A Player’s PlayerGui
A Player’s PlayerScripts.
The ReplicatedFirst service
So to fix your issue, you either need to
A) convert your code to a Script and access the Player objects through the Players service. or
B) move the LocalScript to a place where it will start executing and update the code accordingly.
If you go the route of Option B, follow these steps :
First, move the LocalScript into StarterPlayer > StarterCharacterScripts. This will cause the script to execute when the player's character spawns into the world.
Then, update the code so that it can find the block and show the distance to the player.
local localPlayer = game.Players.LocalPlayer
-- locate the sign in the world
-- local signGui = game.Workspace:WaitForChild("Part"):WaitForChild("UI")
-- set the range where the sign should appear
local DISTANCE_TO_SHOW_SIGN = 10 -- studs
-- every game tick, calculate the distance between the part and the character
game.RunService.Heartbeat:Connect(function()
-- escape if the player's character doesn't exist
if not localPlayer.Character then
return
end
-- calculate the distance to each of the players
-- if two players are close enough to each other, show the sign
local shouldShowSign = false
local myPosition = localPlayer.Character.HumanoidRootPart.Position
for _, otherPlayer in ipairs(game.Players:GetPlayers()) do
if (otherPlayer ~= localPlayer) and (otherPlayer.Character) then
local theirPosition = otherPlayer.Character.HumanoidRootPart.Position
local distBetween = (myPosition - theirPosition)
-- optimization : when calculating distance, try to avoid using square roots
-- use pythagorean theorem : dist = sqrt(x^2 + y^2 + z^2)
-- instead, use dist^2 = x^2 + y^2 + z^2
if (distBetween * distBetween) < (DISTANCE_TO_SHOW_SIGN ^ 2) then
shouldShowSign = true
break
end
end
end
-- show the sign if two players are close enough together
if shouldShowSign then
print("it's working")
end
-- optimization : only set the visibility when it changes
-- if signGui.Visible ~= shouldShowSign then
-- signGui.Visible = shouldShowSign
-- end
end)
Your code has 3 main issues
1: Its a regular script, not a localscript
2: Your while true do loop will timeout when the server starts
3: Magnitude is only defined when doing for i,v
Try this code in a localscript instead
local Players = game:GetService('Players')
local LocalPlayer = Players.LocalPlayer
local Magnitude
while true do
wait()
for _,Player in next, Players:GetChildren() do
local character = Player.Character
if character and character.Parent and Player ~= LocalPlayer then
Magnitude = (LocalPlayer.Character.HumanoidRootPart.Position - character.HumanoidRootPart.Position).magnitude
end
end
if Magnitude ~= nil then
if Magnitude < 10 then
print("It's working!")
end
end
end

How to update speed value only if a character is moving in Roblox Studio?

How can I update a players speed only when they are moving (its just easier on the computer than a while true do loop)
I have this:
local player = game:GetService("Players").LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid")
while humanoid.MoveDirection.Magnitude > 0 do
humanoid.WalkSpeed = player.leaderstats.Speed.Value
end
Don't use loops in a game that provides events. This loop will get your code stuck anyway.
The only moment you need to change the speed is when the leader speed changes. So why not implement a handler for the Changed event that updates the other players' speeds.
Example:
https://developer.roblox.com/en-us/api-reference/event/NumberValue/Changed
local function printValue(value)
print(value)
end
Workspace.NumberValue.Changed:Connect(printValue)
Workspace.NumberValue.Value = 20

Keycard door not working when i put the keycard at replicates storage

I have a key card door but it don't work when I put it in replicatesStorage (it is a gamepass key) can somebody help me it only work when put in starterPack it is currently being given with a localScript at StartGui ** here is code:
script.Parent.Touched:Connect(function(hit)
if hit.Parent.Name == "Clearance1" then
script.Parent.CanCollide = false
script.Parent.Transparency = 0.5
wait(0.5)
script.Parent.CanCollide = true
script.Parent.Transparency = 0
end
end)
StarterPack is already replicated, in a way.
If you use ReplicatedStorage, you'll have to add it to PlayerInstance.Backpack.
Also, script.Parent.Touched is server-side only.
If you wanna access the player's backpack, you can use game.Players.PLAYERNAME.Backpack
The way you're doing this is actually not a very good idea. (no offense)
I would recommend leaving the item inside the StarterPack. If you really don't want to, you can programmatically do it by putting it in their Backpack. Like this:
-- Server script
game.Players.PlayerAdded:Connect(function(player) -- Runs when a player joins the game
player.CharacterAdded:Connect(function() -- Runs when that player respawns or their character loads
local itemCopy = game.ReplicatedStorage.Clearance1:Clone() -- Creates a copy of the item
itemCopy.Parent = player.Backpack -- Puts the item in the player's backpack (inventory)
end)
end)
What that code does is: Every time the player spawns, it clones the item and puts it in their inventory.
Now to check if the user has the item when they touch the door, you can do something like this:
-- Server script
script.Parent.Touched:Connect(function(part) -- Activates when a part touches the doorf
local player = game.Players:GetPlayerFromCharacter(part.Parent) -- Gets a player from the part that touched
if player and player.Backpack:FindFirstChild("Clearance1") then -- Makes sure there is a player, and the player has the keycard in their inventory
script.Parent.CanCollide = false -- Makes the part uncollidable
script.Parent.Transparency = 0.5 -- Sets the part to have transparency
wait(0.5) -- Waits half a second
script.Parent.CanCollide = true -- Makes the part collidable
script.Parent.Transparency = 0 -- Makes the part not transparent
end
end)
Every time the part is touched, it checks if it's a player. If it is, it checks if the player has the item. If so, it runs the code.

How do I make a shield that lasts for 30 seconds in Roblox using a dev product?

When someone buys my dev product I want them to get a visible shield that lasts for 30 seconds.
Here's the code I have tried:
local mpService = game:GetService("MarketplaceService")
local Debris = game:GetService("Debris")
local function giveForcefield(player, duration)
local character = player.Character
if character then
local forceField = Instance.new("ForceField")
forceField.Visible = true
forceField.Parent = character
if duration then
Debris:AddItem(forceField, duration)
end
end
end
mpService.ProcessReceipt = function(purchaceInfo)
local plr = game:GetService("Players"):GetPlayerByUserId(purchaceInfo.PlayerId)
if purchaceInfo.ProductId == xxxxxxx then
game.Players.PlayerAdded:connect(function(plr)
repeat wait() until plr.Character
local char = plr.Character
giveForcefield(plr, 30)
local forceField = Instance.new("ForceField")
forceField.Visible = true
forceField.Parent = char
end)
end
return Enum.ProductPurchaseDecision.PurchaseGranted
end
I can buy the dev product but after the code runs nothing happens.
I have tried a lot of things but I am a bit lost.
Can I get some help, please?
Both of the ways that you have coded for creating and destroying the ForceField are valid, but as Piglet has suggested, your code simply isn't getting called. Your code is saying, "once someone buys this product, wait for another player to join and spawn into the game, then give that new player the forcefield."
Often times, game.Players.PlayerAdded:connect(function(plr) is used as a way to get access to a Player object, but you have already gotten the Player object by calling GetPlayerByUserId, so you can just use that to get access to the Character model.
On an unrelated note, you should only mark a product as PurchaseGranted once the product has been successfully given. By having PurchaseGranted as the default return state, you run the risk of someone buying a product that hasn't been configured yet, and you will just end up taking their money without giving them anything in return.
local PlayerService = game:GetService("Players")
local Debris = game:GetService("Debris")
mpService.ProcessReceipt = function(purchaceInfo)
-- make sure that the player is still in the game
local plr = PlayerService:GetPlayerByUserId(purchaceInfo.PlayerId)
if not plr then
warn("Player could not be found. They might have left")
return Enum.ProductPurchaseDecision.NotProcessedYet
end
if purchaceInfo.ProductId == xxxxxxx then
-- check if their character has spawned
local char = plr.Character
if not char then
warn("Could not find player's character in game")
return Enum.ProductPurchaseDecision.NotProcessedYet
end
-- grant the force field
local forceField = Instance.new("ForceField", char)
-- destroy the force field after a few seconds
local duration = 30
Debris:AddItem(forceField, duration)
-- mark this item as granted
return Enum.ProductPurchaseDecision.PurchaseGranted
end
-- not sure what thing they bought
warn("Unprocessed item receipt", purchaseInfo)
return Enum.ProductPurchaseDecision.NotProcessedYet
end

Low NumberValue does nothing for the script

Instead of depending on the Humanoid's health, I decided to go with custom health. The new health goes by value and works well and I wanted to make it where the character froze for a few seconds and then teleported them to a specific Vector3 value.
I tried writing the script differently, but all of them didn't work at all. I even tried to get it to where the player's position was different but that failed as well.
--Responsible for healing a player's humanoid's health
-- declarations
local Figure = script.Parent
local Head = Figure:WaitForChild("Head")
local Humanoid = Figure:WaitForChild("Humanoid")
local PlayerHealth = game.Players.LocalPlayer.Character.Data.Health
local Player = game.Players.LocalPlayer.Character.Humanoid
if PlayerHealth.Value < 30 then
Player.WalkSpeed = 0
wait(5)
Player.WalkSpeed = 16
end
The script refused to work in general. Even when it was enabled and put in the right place, it never worked.
If I understood it right, you want to teleport the character to a position when it's health reaches a value lower than 30 after frozing it for a few seconds. Then you should check the PlayerHealth value every time it's value changed by connecting it to a function to catch the moment where it health falls below 30:
local Figure = script.Parent
local Head = Figure:WaitForChild("Head")
local Humanoid = Figure:WaitForChild("Humanoid")
local Data = Figure:WaitForChild("Data") --In any case if the data loads after the script runs
local PlayerHealth = game.Players.LocalPlayer.Character.Data.Health
local Player = game.Players.LocalPlayer.Character.Humanoid
PlayerHealth.Changed:connect(function()--Here you check the value every time it changes.
if PlayerHealth.Value < 30 then
Player.WalkSpeed = 0
wait(5)
-- you can add teleportation here.
--Figure:MoveTo(Position)
Player.WalkSpeed = 16
end
end)
Here are some fixes, if this is a server script then change to this:
local Figure = script.Parent
local Head = Figure:WaitForChild("Head")
local Humanoid = Figure:WaitForChild("Humanoid")
local Player = game.Players:GetPlayerFromCharacter(Figure) --It will get the player from his character as server scripts can't access LocalPlayer
local Health = Player:WaitForChild("Data"):WaitForChild("Health")
Health.Changed:Connect(function()
if Health.Value < 30 then
Player.WalkSpeed = 0
wait(5)
-- Add more code here
Player.WalkSpeed = 16
end
end)
else if it was a local script then just change this
local Player = game.Players:GetPlayerFromCharacter(Figure)
to
local Player = game.Players.LocalPlayer
Hope it worked, don't forget to select it as a correct answer and please like it =D

Resources