CollectionService, .Touched events and tracking Hit parts

I am trying to create a single script to handle all “damage” parts that NPCs use to attack a player, such as projectiles. When the part is created, it gets tagged by CollectionService and a .Touched event created for it. My problem is trying to ensure a Player does not get damaged twice by the same Projectile.
I normally prevent this by adding the Player to a tracking table in the controlling script, which subsequent .Touched events check first to stop the duplicate hits, ie:

local player = Players:GetPlayerFromCharacter(part.Parent)
modelsHit[player] = true

I am trying to recreate this using nested tables and failing, due to how I am trying to insert the objects I believe:

local objects = {}		-- Table to track added Objects and Player hits

local function onDamagePartTouched(part, object)	-- OnTouch DAMAGE Part
	local player = Players:GetPlayerFromCharacter(part.Parent)
	if player then
		-- Add checkif Player in "modelsHit" later...
		table.insert(objects[object], modelsHit[player]) --<<<-- THIS --
		local humanoid = part.Parent:FindFirstChildOfClass("Humanoid")
		humanoid:TakeDamage(10)
		wait(3)
		table.remove(objects[object], modelsHit[player])
	end
end

local function onDamagePartAdded(object)	-- TAG Damage Part on Creation
	if object:IsA("BasePart") then
		table.insert(objects, object)
		local touchedPart = object
		connections[object] = object.Touched:Connect(function(part)
			onDamagePartTouched(part, touchedPart)	-- Pass hit Part and Touched object
		end)
	end
end

I think I expected the data layout to be:

objects = {
	Part1 = {
			Player1 = true,
			Player2 = true
			}
	}
	Part2 = {
	}
}

I don’t seem to be able to add the Player into each Parts modelsHit list.
Ambition exceeds technical ability once again.

2 Likes

You are not adding the object to the table correctly, in this line:

table.insert(objects, object) 
-- you are adding it to the end of table 
-- so it would be an array not a dictionary 

What you should do is make the object be the key and create a table for holding the players:

objects[object] = {}

Also, if you’re doing this then you need to detect when the object gets destroyed and remove it from the table, if you don’t then you would leak memory:

object.AncestryChanged:Connect(function()
    if (not object:IsDescendantOf(game)) then
         objects[object] = nil -- setting it to nil removes it from the table
    end
end)

If you want to learn more about memory leaks you can read this : Garbage Collection and Memory Leaks in Roblox - What you should know

Also, there is another problem with how you are adding players to the table, if you want it to have to format you described. Its the same thing you did for the objects table:

table.insert(objects[object], modelsHit[player]) -- this line 
--should be:
objects[object][player] = true
1 Like

Thank you very much that worked perfectly. I always seem to have a problem with creating/referencing tables when they start to get nested but your simple explanation was perfect. Thanks for the cleanup hint as well.

1 Like