Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
1

How can I use a dying function to end a while loop?

Asked by 4 years ago

I've been trying on numerous different attempts and I thought this would be the closest I could get to what I wanted the outcome to be. Any help or hints are appreciated =)

local players       = game:GetService("Players")
local teams         = game:GetService("Teams")
local rs            = game:GetService("ReplicatedStorage")
local showgui       = rs:FindFirstChild("ShowGui")
local touching      = false
local user          = nil
local plr           = nil
local grabbed       = nil

script.Parent.Touched:Connect(function(hit)
    if hit.Parent:FindFirstChild("Humanoid") then
        plr = workspace[hit.Parent.Name]
        user = players:GetPlayerFromCharacter(plr)
        if user ~= nil then
            if user.Robbing.Value == true then
                grabbed = user:WaitForChild("CashCollected")
                touching = true
                print("true")   
                if user.Team.Name == "Citizens" then
                    showgui:FireClient(user,"Show")
                end
            end
        end
    end
end)

script.Parent.TouchEnded:Connect(function(Player2)
    if user ~= nil then
        if user.Robbing.Value == true then
            touching = false
            print("false")
        end
    end
end)

local function died()
    if plr ~= nil then
        plr:FindFirstChild("Humanoid").Died:Connect(function()
        break
    end
end

while wait(1) do
    if user ~= nil then
        died()
        if touching == true and user.Robbing.Value == true then
            print("giving money")
            grabbed.Value = grabbed.Value + 100
            if grabbed.Value == 2500 then
            return end
        end
    end
end

0
your variable indenting is interesting xd starmaq 1290 — 4y
0
sorry i was just trying something new lol wasn't sure if i was gonna stick with it though AnnaVonWachstein 7 — 4y
0
To accept an answer there should be an "Accept Answer" button below the "Post a comment" box on the answer you wish to accept. chess123mate 5873 — 4y

2 answers

Log in to vote
1
Answered by 4 years ago

It much easier than you think! All you have to do is simply get the Humanoid's health and once it reaches 0 health you could break the loop.

Here is a sample that should help you understand how it works.

local player = game.Players.LocalPlayer
local character = player.Character
if not character or not character.Parent then
    character = player.CharacterAdded:wait()
end

while wait(1) do
    print("Hello") -- Your Code Here
    if character.Humanoid.Health == 0 then
        break
    end
end
0
Thanks for the help! I'd give you the "question answered" but I'm not so sure on how to do so. AnnaVonWachstein 7 — 4y
Ad
Log in to vote
0
Answered by 4 years ago
Edited 4 years ago

Your "died" function is trying to listen to an event, ie you're wanting to exit a loop when an event occurs. To do this, you listen to the event but save the connection you've made to a variable so that you can disconnect it when the loop ends. Inside the event listener, you change a boolean variable that you periodically check to see if you should keep running the loop. (This is shown below.)

Notes: * you'll probably want to run that code every time the user touches the brick, so put it in a function (and add debounce - you don't want several 'while' loops running, all giving the player 100s of dollars every second) * (Minor) Use Connect, not connect (which is deprecated) * if user ~= nil then can be shortened to if user then so long as you don't expect user to ever equal false * if touching == true and... can be shortened to if touching and... unless you expect touching to be any random value and only want to do something if it's specifically true * You don't want to be using variables like grabbed to refer to things like a player's CashCollected, since this is a server script that needs to handle many players (if 2+ players try to touch the part at once, one player will be awarded the other player's money as well as his/her own). You should either use a dictionary to track all players's CashCollected objects or make it local to the function(s) that use it (passing it to other functions as needed). For the touching variable, you'll definitely need a dictionary for that one (the key is the player, the value is true or false -- be sure to set it to nil when a player leaves to prevent memory leaks) * Variables should be local to the function they are used in; try to avoid sharing variables between functions (though you always need some and that's okay)

Improved code:

local players       = game:GetService("Players")
local teams         = game:GetService("Teams")
local rs            = game:GetService("ReplicatedStorage")
local showgui       = rs:FindFirstChild("ShowGui")
local touching      = {} -- touching[player] = true if the player is touching script.Parent
local db            = {} -- debounce: ensure the "give money" loop doesn't run more than once simultaneously for any one player

local function mainLoop(player)
    if db[player] then return end
    db[player] = true
    local hasDied = false
    local con = player.Character.Humanoid.Died:Connect(function()
        hasDied = true
    end)
    local grabbed = user:WaitForChild("CashCollected")
    local robbing = player.Robbing
    while wait(1) and not hasDied and grabbed.Value < 2500 do
        if touching[player] and robbing.Value then
            print("giving money")
            grabbed.Value = grabbed.Value + 100
        end
    end
    con:Disconnect()
    db[player] = false
end

script.Parent.Touched:Connect(function(hit)
    if hit.Parent:FindFirstChild("Humanoid") then
        local plr = hit.Parent
        user = players:GetPlayerFromCharacter(plr)
        if user then
            if user.Robbing.Value == true then
                touching[user] = true
                print("true")   
                if user.Team.Name == "Citizens" then
                    showgui:FireClient(user,"Show")
                end
                mainLoop(user)
            end
        end
    end
end)

script.Parent.TouchEnded:Connect(function(hit)
    if hit.Parent:FindFirstChild("Humanoid") then
        user = players:GetPlayerFromCharacter(hit.Parent)
        if user then
            touching[user] = false
            if user.Robbing.Value == true then
                print("false")
            end
        end
    end
end)

players.PlayerRemoving:Connect(function(player)
    -- Cleanup
    db[player] = nil
    touching[player] = nil
end)

By the way, I'm unsure if TouchEnded is guaranteed to work (last time I checked it doesn't); you should periodically check the character's position to see if they've left the area (then do touching[player] = false if so). Also, if the player's arm briefly touches script.Parent (in addition to the torso), money will stop being awarded even if the player's torso is still touching it.

[Edit: DAsanicmaster's answer of checking the humanoid's health is definitely superior in this case, but I leave this answer here because everything else I said is still fine and sometimes you need to listen to an event instead of checking a value.]

0
Reading this actually helped give me a bunch of information I was unaware of. And thanks so much for helping clean up my messy coding xp AnnaVonWachstein 7 — 4y

Answer this question