Player tracking function

Hello,

I’ve recently put together a ‘PlayerTracker’ function that detects when a player enters a part, and I’m not ashamed to say I’ve spent a day or two trying to perfect it.

I’m making the function for a Hardpoint game that I am creating for fun, and to learn a little bit more about programming and best practices. If you do not know what a Hardpoint game is, here is an overview I found on a Call of Duty wiki page.

As you will see, I am not using the BasePart.Touched / BasePart.TouchEnded events, as I found early on that they arent very reliable. I also know that ZonePlus exists, but I would rather not use this in my game as I would only use it for what I am trying to do here, and so it would be a waste of performance.

How I plan to have it work

My code
local Players = game:GetService("Players")
local CollectionService = game:GetService("CollectionService")
local RunService = game:GetService("RunService")

local function PlayerTracker()
	local PlayersInPart = {}

	for _, Part in pairs(CollectionService:GetTagged("Hardpoint")) do
		local PlayersCurrentlyIn = {}
		local TouchingParts = workspace:GetPartsInPart(Part)

		for I, TouchingPart in pairs(TouchingParts) do
			local Player

			local Humanoid = TouchingPart.Parent:FindFirstChild("Humanoid")
			if Humanoid then
				local Player = Players:GetPlayerFromCharacter(TouchingPart.Parent)
				if Player then
					PlayersCurrentlyIn[Player] = true
				end
			end
		end
		
		PlayersInPart[Part] = PlayersCurrentlyIn
	end

	return PlayersInPart
end

local TrackPlayerHandle = RunService.Heartbeat:Connect(PlayerTracker)

The reason for this post is so I can ask if I am going about this the right way? My initial plan was to add the players to a table to keep track of them, but then I realised I needed to know what team they were on so that I could work out whether or not the zone was contested, and so that I can speed up the capture depending on how many people are in the zone.

What would be the best way of doing this? Do I keep the player table, then loop through it and get the players teams? Or create a new table and insert the players names under their team name?

I’d appreciate any help you can give on this, and any recommendations on where I can optimise my code.

Thanks

You can still achieve this with a table by making a dictionary with player names as the index and their team as the value.
i.e.

PlayersInPoint = {
    ["Player1"] = 1 --team 1
    ["Player2"] = 2 --team 2
    ["Player3"] = 1
}

You can add players to this table via script very easily by doing
PlayerInPoint[Player.Name] = Player.Team --pseudo code

1 Like

Thank you for your reply!

But what would be the best way to get the number of players from each team from this dictionary?

local Team1, Team2 = 0, 0
for player, team in next, PlayersInPoint do
	if team == 1 then
		Team1 += 1
	elseif team == 2 then
		Team2 += 1
	end
end
1 Like

Thanks for replying!

The table after the initial function looks like:

{
	["Hardpoint_1"] = {
		[Name] = Team 1
	}
}

And when I tried:

local Team1, Team2 = 0, 0
	
	for Player, Team in next, PlayersInPoint() do
		if Team == "Team 1" then
			Team1 += 1
		elseif Team == "Team 2" then
			Team2 += 1
		end
	end
	
	print("Team 1: " .. Team1 .. " - Team2: " .. Team2)	
	
	if Team1 > 0 and Team2 > 0 then
		print("Contested")
	elseif Team1 > 0 and Team2 == 0 then
		print("Team 1")
	elseif Team2 > 0 and Team1 == 0 then
		print("Team 2")
	end

For some reason ‘Team1’ and ‘Team2’ aren’t being added to.

Send your full code not sure what’s really happening there

local Players = game:GetService("Players")
local CollectionService = game:GetService("CollectionService")
local RunService = game:GetService("RunService")

local function PlayersInPoint()
	local PlayersInPoint = {}

	for _, Part in pairs(CollectionService:GetTagged("Hardpoint")) do
		local PlayersCurrentlyIn = {}
		local TouchingParts = workspace:GetPartsInPart(Part)

		for I, TouchingPart in pairs(TouchingParts) do
			local Player

			local Humanoid = TouchingPart.Parent:FindFirstChild("Humanoid")
			if Humanoid then
				local Player = Players:GetPlayerFromCharacter(TouchingPart.Parent)
				if Player then
					PlayersCurrentlyIn[Player.Name] = Player.Team
				end
			end
		end
		
		PlayersInPoint[Part.Name] = PlayersCurrentlyIn
	end

	return PlayersInPoint
end

local TrackPlayerHandle = RunService.Heartbeat:Connect(function()
	local Team1, Team2 = 0, 0
	
	for Player, Team in next, PlayersInPoint() do
		if Team == "Team 1" then
			Team1 += 1
		elseif Team == "Team 2" then
			Team2 += 1
		end
	end
	
	print("Team 1: " .. Team1 .. " - Team2: " .. Team2)	
	
	if Team1 > 0 and Team2 > 0 then
		print("Contested")
	elseif Team1 > 0 and Team2 == 0 then
		print("Team 1")
	elseif Team2 > 0 and Team1 == 0 then
		print("Team 2")
	end
end)

Oh right, you need to loop through all the points first

local Team1, Team2 = 0, 0

for _, Point in next, PlayersInPoint() do
	for Player, Team in next, Point do
		if Team == "Team 1" then
			Team1 += 1
		elseif Team == "Team 2" then
			Team2 += 1
		end
	end
end

This would get you all the players on a team across every hardpoint location in your game. If you want it to be per location you’d need to loop through the points and move the Team1, Team2 variables inside of it and handle it separately.

1 Like

This still doesn’t seem to be working unfortunately

Debug your code. Print out the results of the table.

1 Like

image

I found the issue, ‘Team 1’ on the table wasn’t a string value.

2 Likes

Hello again, I’ve now decided this is what I’d like to do with my code:

This would get you all the players on a team across every hardpoint location in your game. If you want it to be per location you’d need to loop through the points and move the Team1, Team2 variables inside of it and handle it separately.

Though I don’t quite understand how I could do it as you mention above. Would I do this in my PlayersInPoint function or my loop?