How to make a variable unique to every player, or are there better alternatives?

Lemme give a quick example of this:
-Let’s say there’s a touch part and the code is the following:

local part= script.Parent

part.Touched:Connect(function(hit))
if hit.Parent:FindFirstChild(“Humanoid”) then
local x = 0
for i = 1,5 do
x = x + 1
wait(1)
if x == 5 then
hit.Parent.Humanoid.Health = 0
end
end
end

Assuming another dude touches the part before the timing is up, it resets the x back to 0( because the variable is shared) which is problematic for what I’m trying to make which includes multiple players touching a part at once and at possibly of dying. I thought about making the x unique by trying to reference the player in the variable, but obviously that has failed. Is there a solution to this? Thank you. Btw I fully realize that I am not using debounce, and that is on purpose.

2 Likes

Sorry for the bad code, I am currently not on laptop, but the code should be pretty simple as it’s a basic touch event.

2 Likes
Old Post

Let me introduce to you my most favorite object in Lua: Tables.

You can use Tables in a Dictionary format in order to do what you’re trying to accomplish. Dictionaries have keys and values. Here’s an example:

Dict = {
   hello = 5,
   bye = "hey",
   [game.Workspace] = function() print("yeah, it's flexible alright!") end
}
print(Dict.hello)
print(Dict["bye"])
print(Dict[game.Workspace]())

Now, let’s use this to do what you want.

local part = script.Parent

local data = {}

part.Touched:Connect(function(hit)
	if hit.Parent:FindFirstChild(“Humanoid”) then
		hum = hit.Parent.Humanoid
		-- initialize the item inside data if it doesn't exist
		if data[hum] == nil then
			data[hum] = 0
		end

		for i = 1,5 do
			data[hum] = data[hum] + 1
			wait(1)
			if data[hum] == 5 then
				hum.Health = 0
			end
		end
	end
end

NOTE: Just wanted to say you can simplify your code here by doing this:

script.Parent.Touched:Connect(function(hit)
	if hit.Parent:FindFirstChild(“Humanoid”) then
		wait(5)
		hit.Parent.Humanoid.Health = 0
	end
end

EDIT: Just reread your question and noticed something. Your variable x is not shared as it’s not in a global/higher scope. Each time that event is fired, x is completely unique.

Anyway, I’m not totally sure what you want exactly. Could you try to explain it again?

2 Likes

All you gotta do is get the UserId. Every UserId is unique.

Example Variable: Player_223382

That’s odd for me it ended making my code go crazy lol. I printed x and it ends up being kind of mixed. It was as if the code favored one client over another even though it’s not _G.

-I found a way out of this situation which is the use of remote events, but that has its own set of issues with exploits, and requires a lot more code.

1 Like

One practical use(to give a better representation) is let’s say there’s an ice part, and it freezes every Robloxian that touches it gets frozen for 3 rounds of 5 seconds(-20 hp per 5 seconds which is why using a script is convenient cause health can only be changed by scripts and not local scripts) and any longer than that they die unless saved by someone by thawing.

In this case the x is the number of rounds which is needed for a much longer period of time. The fact that it somehow ends up being shared just ruins everything.

I know of two good ways to achieve this:

  1. (Preferred by me): Use a table and in it store the names/userids of every player in the game.
local playerVar = {}

game.Players.PlayerAdded:Connect(function(player)
  playerVar[player.Name] = 0 --Whatever you want the variable to be
end)

game.Players.PlayerAdded:Connect(function(player)
  playerVar[player.Name] = nil
end)
  1. You could just insert a/an IntValue, StringValue, BoolValue, ObjectValue and so on inside the player.
game.Players.PlayerAdded:Connect(function(player)
  local value = Instance.New("IntValue") --Or whatever value you want
  --Change it accordingly
end)

Those are cool alternatives.

-However, the first solution I thought of already. You still can’t really define a “unique” table. You can insert players in the table, but that doesn’t really accomplish much as the issue lies within the x number of times(because it is not unique it causes functional problems) something happens to them.

-The 2nd one can cause memory leak when the player just decides to ditch the game halfway which is what actual occurred to me. As soon as I destroyed the string value when it is no longer needed errors start popping.

I do not understand what you mean by 3 rounds of 5 seconds. Wouldn’t the health only be 40 at that point?

But here’s a way you could do this.

local frozenTable = {}

IcePart.Touched:connect(function(hit)
    local hum = hit.Parent:FindFirstChild("Humanoid")
    -- if the humanoid is already frozen, it won't enter this if statement
    if hum ~= nil and not frozenTable[hum] then
        frozenTable[hum] = true
        while true do -- you can make this a for loop if you want to double make sure it ends
            wait(5)
            if hum.Parent ~= nil and frozenTable[hum] then
                -- he's still frozen, lets damage him
                hum:Damage(20);
            else
                if hum.Parent == nil or frozenTable[hum] = false then
                    frozenTable[hum] = nil
                end
                break -- kills the loop
            end
        end
    end
end)

RemoteEvent.OnServerEvent:connect(function(player,action,hum) 
    if action == "thaw" then
        -- do some checks to make sure they are close enough to thaw, then
        frozenTable[hum] = false
    end
end)

I usually don’t put loops with long waits inside of an event like that because it can cause issues. For example, if a player gets thawed but frozen instantly after, there will be two while loops removing his health, making it double the speed.

To make sure you don’t have this issue, you need the table to contain two peices of data. One, whether the player is thawed or not. And two, some kind of unique identification for that while loop. If they are still frozen, but the unique ID is different than when the loop first started, you can assume that the player got thawed then frozen within the 5 second wait, so break the loop.

EDIT: Also, it’s probably best to use the player object to track rather than humanoid. With humanoid tracking, you need to make sure it gets removed from the table or you could get have a leak.

Another way to combat the issue is the have one while loop that handles damaging and thawing players. Actions are put into a queue. So that way, the player will always be thawed first before frozen and no hidden issues should occur. It’s more work than the previous example, but its neater and works better imo.

1 Like

That was my strat as well lol at first since it looks like it works(table.remove once the player dies or is saved) and yes that’s what I meant by 3 rounds of 5 seconds(every 5 seconds the player would lose 20 hp which is kind of like freezing to death). The hp would be 40, but then the player dies after the 3 rounds because the player has been frozen for too long.

The biggest problem in that code is the while true do loop which for some reason makes the game confused since only one person can loop at once(I have tested the same code myself). I have fixed it by actual looping in the local scripts, even though I hoped that I didn’t need to do that(firing remote events for hp into the server is kind of risky because exploiters can spam it). :+1:t2:

This shouldn’t be the case, or literally every game would break. Can you send me exactly what you tried? Because I’m pretty sure that issue wouldn’t happen with the code I shared.

Well I fixed my code, and you can test it out yourself since it doesn’t work lol(I thought it would work at first too). If you still want to see my old and new code for learning purposes though I’ll be glad to send it lol.