Easiest way to use Region3 to decide what room a player is in

This is what I got so far, problem is tho if I have a dozen rooms, do I need to do this same thing for every individual room, and then check each individual Region3 for PartsInRegion3 or is there a more fluid way to just return what ‘part’ a player is inside of??

local RegionPart1 = PlayersPlot.Extras.Room01
local RegionPart2 = PlayersPlot.Extras.Room02

local Part1Pos1, Part1Pos2 = (RegionPart1.Position - (RegionPart1.Size / 2)), (RegionPart1.Position - (RegionPart1.Size / 2))
local Part2Pos1, Part2Pos2 = (RegionPart2.Position - (RegionPart2.Size / 2)), (RegionPart2.Position - (RegionPart2.Size / 2))
		
local Region1 = Region3.new(Part1Pos1, Part1Pos2)
local Region2 = Region3.new(Part2Pos1, Part2Pos2)

I don’t really wanna resort to .Touched either

I don’t have ROBLOX Studio on me atm, but I believe this should work…
Assuming you have all the rooms in a model/folder in workspace, why not simply loop through each of the rooms in the folder?

for i, room in ipairs(workspace["Rooms"]:GetChildren()) do
    local RegionPart1 = room.Extras.Part01
    local Part1Pos1, Part1Pos2 = (RegionPart1.Position - (RegionPart1.Size / 2)), (RegionPart1.Position - (RegionPart1.Size / 2))
    local region = Region3.new(Part1Pos1, Part1Pos2)

    for i,v in pairs(workspace:FindPartsInRegion3(region,nil)) do
           if v.Name == "HumanoidRootPart" then
                 print("Character is in: "..room.Name)
           end
    end
end

I just typed this up on my laptop real fast, so don’t expect it to work flawlessly, but wouldn’t something like that work?

That would just get the Region3 of Part01 only.

If you’re just trying to tell which room a player is in, why can’t you track which room they are in inside a dictionary and just update the room each time they enter/leave a room. I feel this would be a good option as it doesn’t require anything complicated. This would depend on the scenario and mechanics of entering/leaving rooms to be of use, though.

If you really want to use Region3, or the first option isn’t applicable, you could always do a magnitude check first to get the general area of the player and then use region3 on the smaller rooms individually. This means you could reduce from say 12 rooms to 3 or 4 (obviously depending on sizes/positions of rooms this could be more or less efficient)

Not exactly sure what you mean here??

@mario118118’s suggestion of dictionaries seems the most sound to me, you could just make a Region3 for the room they are currently in and the rooms they are allowed to transition to, and whenever the Region3 they are cast from isn’t their own, then you would just go to that Region3’s key.

Semi-pseudocode would probably look like this:

local Space = { --[[
	[Region3] = {
		Current = this Region3, 
		Neighbors = {
			neighboring Region3s
		}, 
		Trigger = function() end 
	}
--]] }

local START = -- the Region3 they were found in

local Interface = Space[START]

local Filter = {Interface.Current, unpack(Interface.Neighbors)}

while true do
	local found = false
	for _, r3 in ipairs(Filter) do

		local parts = workspace:FindPartsInRegion3WithWhiteList(r3, --[[ { character(s) } ]], 1)

		if parts then

			-- character is in this r3
			if r3 ~= Interface.Current then

				-- character is not in the current r3, switch nodes!
				Interface = Space[r3]
				Filter = {Interface.Current, unpack(Interface.Neighbors)}
				Interface.Trigger()
				found = true
				break

			end
		else

			-- character is not in this r3, search the next one

		end
	end
	if not found then
		-- player is not in any of the r3's, they are probably hacking!
	end
	wait() -- or similar
end

Which part?

Track the player’s current room: This option depends on how your room system is set up so it could work slightly differently but; if you have a cut scene for transitioning between each room you could keep a dictionary on the server which tracks the room the player is in.

local playerDic = {}

local function moveRooms(player, newRoom)
    playerDic[player.Name] = newRoom
end

local function getCurrentRoom(player)
    return playerDic[player.Name]
end

This could be coupled with region3 as @goldenstein64 is suggesting above (checking adjacent rooms to see if the player moved using region3 and keeping the current room in the dictionary), or could use some other method that part is up to you.

Magnitude checks: By this, I mean to loop through each room part and check if the magnitude of the distance between the character and the room is smaller than a pre-defined value or the largest axis of the room’s size. You could then use region3 on each of the returned rooms and this would mean you are using region3 on less rooms as just all of them.

You could also use a different method where you check if the magnitude between the player and the room is smaller than the rooms largest size axis, and then check each axis individually, but I’m not sure if this would be more efficient than checking region3’s for the few rooms where the player could be in the room instead.

For example:

-- get the distance between the player and the room.
local function getDistFromRoom(player, room)
    return (player.Character.HumanoidRootPart.Position - room.Position).Magnitude
end

-- get the largest axis of size for the room
local function getMaxSize(room)
    local size = room.Size
    return math.max(math.max(size.X, size.Y), size.Z) -- bit weird
end

-- check if the players position is within the room
local function isPlayerInRoom(player, room) 
    local playerPos = player.Character.HumanoidRootPart.Position
    local roomPos = room.Position
    local roomSize = room.Size
    local minX, maxX, minY, maxY, minZ, maxZ = roomPos.X - roomSize.X, roomPos.X + roomSize.X, roomPos.Y - roomSize.Y, roomPos.Y + roomSize.Y, roomPos.Z - roomSize.Z, roomPos.Z + roomSize.Z
    return (playerPos.X > minX) and (playerPos.X < maxX) and (playerPos.Y > minY) and (playerPos.Y < maxY) and (playerPos.Z > minZ) and (playerPos.Z < maxZ)
end



local function playerInRoom(player, room)
    if getDistFromRoom(player, room) < getMaxSize(room) then -- they might be in the room!
         return isPlayerInRoom(player, room)
         -- return true if the player is in the room, or false
    end
    return false -- not in the room.
end

This method I just came up with so it be a bad way of doing things, however I believe it would be quicker than checking each axis individually for every room.

Hope that explained it a bit better! :smiley:

I wrote this on my phone while walking, and it only just sent so hopefully everything works ok and makes sense!

1 Like