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
Related
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 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
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
So im trying to make a gamepass (developer products to get money via Robux) gui, and while testing it a few times, it worked, until i reached a certain value of around 400,000-500,000 bananas (thats my currency) it stopped working. Also, earlier when making my game, when i purchase something that has costs over 1 million bananas, it appears to decrease, but when i get some banana seeds (sellable item) and sell it, it resets back to before i bought the 1 million banana item (e.g from 1.3 million then i purchase it, then it becomes 300,000, but when the value gets modified (example: via selling seeds) it changes back to before it got bought (1.3 million)) and also im working on a Admin GUI and i wanna make a gui to give money, obviously i knew it wasn't going to work in the first place.
Leaderstats script:
Script name: leaderstats
Script type: server side
Script code:
game.Players.PlayerAdded:Connect(function()
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
local coins = Instance.new("IntValue", leaderstats)
coins.Name = "Bananas"
local resets = Instance.new("IntValue", leaderstats)
resets.Name = "Rebirths"
local bananaseeds = Instance.new("IntValue", leaderstats)
bananaseeds.Name = "BananaSeeds"
end)
My gamepass handler script (ServerScriptService):
Type: server side
Name: DevPrdctHndlr
Code:
local mps = game:GetService("MarketplaceService")
mps.ProcessReceipt = function(reciptInfo)
if reciptInfo.ProductId = 1146099164 then
--[Donate to me!]
local player = game.Players:GetPlayerByUserId(reciptInfo.PlayerId)
player.leaderstats.BananaSeeds.Value =
player.leaderstats.BananaSeeds.Value + 10000
player.leaderstats.Bananas.Value =
player.leaderstats.Bananas.Value + 50000
return Enum.ProductPurchaseDecision.PurchaseGranted
end
end
Buy SmoothPlasticWand script (its a shop gui textbutton):
Type: localscript
Name: BuyScript
Location: game.StarterGui.ShopGui.ShopFrame.SmoothPlasticWand.BuyScript
Code:
local Button = script.Parent
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local currency =
game.Players.LocalPlayer.leaderstats:WaitForChild("Bananas")
Button.MouseButton1Up:Connect(function()
if currency.Value >= 1000000 then
ReplicatedStorage.ReplicatedWands.SmoothPlasticWand:Clone().Parent = game.Players.LocalPlayer:WaitForChild("Backpack")
game.Workspace.Musounds.Buy:Play
currency.Value = currency.Value - 1000000
end)
Im sorry if this question is a duplicate, im still a noob at StackOverflow and im sorry if this question isn't detailed enough, i will provide additional details if you want.
The short answer to your question is : do the work on the server.
The server is the source of truth for all values. When the world is changed with a server Script, that change is replicated to out to all players. But when the world is changed with a LocalScript, that change only appears in that specific player's world.
So when you use the MouseButton1Up handler on your button in a LocalScript, you are only changing the player's local view of that value, and you are not changing the actual source of truth. One fix for this is to use a RemoteEvent in your LocalScript to signal to the server that there's a change that needs to be made.
So create a RemoteEvent in ReplicatedStorage and name it something like BuyItem
In your LocalScript :
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local BuyItem = ReplicatedStorage.BuyItem
local Button = script.Parent
Button.MouseButton1Up:Connect(function()
-- tell the server that the player would like to buy the item
BuyItem:FireServer("SmoothPlasticWand")
end)
And then, in a Script somewhere, handle the signal coming from the client:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local BuyItem = ReplicatedStorage.BuyItem
-- set up a price table for items
local prices = {
SmoothPlasticWand = 1000000,
-- add more items here
-- SomeOtherWand = 10,
}
-- listen for the player wanting to buy things
BuyItem.OnServerEvent:Connect(function(player, itemName)
-- check that it's a real item
assert(type(itemName) == "string", "Expected itemName to be a string")
assert(prices[itemName], "Could not find a price for " .. itemName)
-- check that the player has enough money
local itemPrice = prices[itemName]
local currency = player.leaderstats.Bananas
if currency.Value >= itemPrice then
-- give the player their wand
local wand = ReplicatedStorage.ReplicatedWands[itemName]:Clone()
wand.Parent = player.Backpack
-- subtract how much the wand cost
currency.Value = currency.Value - itemPrice
end
end)
Now, because the server Script is handling the change to currency.Value, that change will properly show up for everyone and make the change permanent.
Maybe for safety, do something like this to reset it to what it should be. Basically make a variable which captures the value of the currency, then make the currency that same value as a fail-safe
--Put This Right After The Item Is Bought
StoredBananas.Value = coins.Value
--This Goes After The Currency Change When Buying So That It Sets It To The Correct Price After It Glitches Out.
coins.Value = StoredBananas.Value
So I'm trying to develop a small coin collecting game on Roblox, and am pretty new to scripting. Basically Every 0.25 - 1.5 seconds, a small part is cloned from (-254, 2, -255) (one corner of the baseplate), to (254, 2, 255) (the opposite corner). That works, but im trying to loop over every object in workspace named coin, and when one is touched, run code (for now im just trying to destroy the object but ill probably just update the Coins leaderstat). It doesn't give me any errors, it just doesnt work. I've also looked all over the internet, and cant find anything.
Code in ServerScriptStorage (spawns cubes and already works, but showed it for help.):
local runservice = game:GetService("RunService")
local interval = math.random(0.25, 1.5)
local coin = game.ServerStorage.coin
local counter = 0
local x = math.random(-254, 254)
local z = math.random(-255, 255)
runservice.Heartbeat:Connect(function(step)
counter = counter + step
if counter >= interval then
counter = counter - interval
local copy = coin:Clone()
copy.Parent = workspace
copy.Position = Vector3.new(x, 2, z)
x = math.random(-254, 254)
z = math.random(-255, 255)
interval = math.random(0.25, 1.5)
end
end)
script in desktop that handles the touching:
for _, v in pairs(workspace:GetChildren()) do
if v.Name == "coin" then
print("foo")
end
end
I hope this is enough to help!
Well as you are new to scripting in roblox let me give you your answer with good practices that may help you a lot.
First in this scenario you dont need to use Heartbeat, instead you could simple use a while loop or a recursive function and a simple wait().
Also you better create a "Coins" Folder in workspace in order to not check other objects
local waitTime = math.random(25,150)/100 --random time between 0.25 and 1.5
while true do --forever loop
wait(waitTime) --waits desired time
local coin = game.ServerStorage.coin:Clone() --cloning your coin
coin.Parent = workspace.Coins --Coins folder
coin.Position = Vector3.new(math.random(0,10),2,math.random(0,10)) --you must use your own position
coin.Touched:Connect(function(hitPart) --here is the touched function
local plr = game.Players:FindFirstChild(hitPart.Parent.Name) --check if the hitPart is part of a player
if plr then
plr.leaderstats.Coins.Value = plr.leaderstats.Coins.Value + 1--here you can increment your coins value in your own value
coin:Destroy()--destroys the coin
end
end)
waitTime = math.random(25,150)/100 --set a new random value to wait next
end
Also you mentioned something about loop every coin in workspace, thats why I said it is better to create a separate folder. So I made a localscript inside StarterPlayerScripts with the following code:
local RunService = game:GetService("RunService") --service
RunService.RenderStepped:Connect(function() --function on every game frame
for i,v in pairs(workspace.Coins:GetChildren()) do --loop on every coin
v.Orientation = Vector3.new(v.Orientation.X,v.Orientation.Y+5,v.Orientation.Z) --increasing Orientation just on Y in order to rotate them
end
end)
I'm doing this on localscript because is just a visual effect and it is never a good idea to send that many functions that quickly serverside. Here is the game I made for you:
https://www.roblox.com/games/5842250223/Help-for-TextBasedYoutube
You can edit the place.
In other words to answer "How to run code when any object with the same name is touched?"
You need to set the function for the object when creating it.
Edit: Also is not a good idea to send to many request to the server in short periods of time, I would recommend you to create a coin ever 2 to 3 seconds or more.