I have quite a lot of NPCs and I was wondering how to check if a player is in a certain area without having to constantly checking if said part inside of area is a humanoid and then checking if its a player, since that causes some performance issues.
It probably causes less performance issues than you think it will (I agree it is inefficient).
That said, I imagine one of the better ways is to use location checkpoints. Where walking through a CanCollide false part will update each player’s personal dictionary of local information (if that’s something that you keep track of). Otherwise it can write to a dictionary of players with their location information. Improper implementation of a system like this could be cause for false positives (so keep track of location changes when you teleport a player, etc…)
There’s a really great Module for it, in resources somewhere. Sorry I can’t find it rn though!
For every LocalPlayer
in game.Players
, you could reference their Character
using LocalPlayer.Character
, then use Region3s to check if the Character
's primary part is in the certain area you wish to reference (feel free to use something else other than Region3s, it was just a suggestion, however you should probably use the HumanoidRootPart as the location of the player).
local players = game:GetService("Players")
local player = players.Player or players.PlayerAdded:wait()
local character = player.Character or player.CharacterAdded:wait()
local HMR = character:WaitForChild("HumanoidRootPart")
local hmrPos = HMR.Position --vector3 value
local areaToCheck = {{xStart, xEnd}, {yStart, yEnd}, {zStart, zEnd}}
task.spawn(function()
while task.wait() do
if hmrPos.X >= areaToCheck[1][1] and hmrPos.X <= areaToCheck[1][1] and
hmrPos.Y >= areaToCheck[2][2] and hmrPos.Y <= areaToCheck[2][2] and
hmrPos.Z >= areaToCheck[3][3] and hmrPos.Z <= areaToCheck[3][3] then
print("Player is inside area.")
else
print("Player is not inside area.")
end
end
end)
Region3 is unintuitive for zoning because it doesn’t support rotation (and also is processed more heavily than other solutions could be). Good zoning should be heavily accessible across your game, and LocalPlayer insinuates client-sided zoning (which is okay to cache for unimportant throttle checks, but updates should happen on the server).
As I stated earlier in this post, zoning can easily be done by building a dictionary of Player object keys and strings.
An example of reasonable server-sided zoning could look like this:
local Players = game:GetService("Players")
local PlayerLocations = {
["LocationDefault"] = "Spawn";
["Locations"] = {
"Spawn";
-- Any other zone you might have
}
}
function PlayerRespawn(Character)
UpdateLocation(Players:GetPlayerFromCharacter(Character), PlayerLocations.LocationDefault)
-- Could be wrote to different defaults
end
function NewPlayer(Player)
Player.CharacterAdded:Wait()
UpdateLocation(Player, PlayerLocations.LocationDefault)
Player.CharacterRemoving:Connect(PlayerRespawn)
end
function UpdateLocation(...)
local Player, ZoneUpdate = ...
assert((type(Player) == "userdata") and (typeof(ZoneUpdate) == "string"), "Unsuccessful zone update.")
PlayerLocations[Player] = ZoneUpdate
print("Updated key.")
end
Players.PlayerAdded:Connect(NewPlayer)
-- When a player leaves, their index is automatically nulled because their key is their player object.
-- A full system would write SpawnDefault into each player key instead of existing as a table-wide default.
Something that doesn’t need to exist inside of a loop wasting resources, should not. Always opt to use events first. Walking through a pre-existing zone checkpoint can also trigger UpdateLocation().
Ideally, each player’s key would contain more information and be wrote into modules with specific defaults.
I found it luckily. Here’s the link in case anyone wants it:
Object Tracker & Area Manager (Get events when an instance enters an Area) - Resources / Community Resources - DevForum | Roblox