Checking for occupied spots adjacent to an existing part

  1. What do you want to achieve?
    A method to check whether a part adjacent to another is occupied
    (if it is then don’t place a part)
    (if it isn’t then do place a part)
  2. What is the issue?
    As of current when a player spawns in (indicated by the red dot) the “baseplate” spawns 4 others, on each x and z axis.

    The issue comes with checking if it should spawn another in a previously occupied space shown below.

    Now the player has moved to another baseplate (indicated by the red dot), but I don’t know how to stop the script from placing another box inside another (represented by the raised box in the middle, which has 2 inside of it)
    image
    This is the simple hierarchy ^^^
  3. What solutions have you tried so far?
    I have tried using FindPartsInRegion3, but can’t exactly get it to work, encountering errors.
local touchPart = script.Parent
local map = game:GetService("ServerStorage"):WaitForChild("Map")
local movementAmount = 2048
local mapGeneration = false

local positivePositionX = false
local negativePositionX = false
local positivePositionY = false
local negativePositionY = false

touchPart.Touched:Connect(function(hit)
	local debounce = false
	local humanoid = hit.Parent.Humanoid
	if humanoid and debounce == false then
		debounce = true
		if mapGeneration == false then
			mapGeneration = true
			local mapPositiveX = map:Clone()
			local basePlate = mapPositiveX:FindFirstChild("Baseplate")
			local basePlate:Parent = workspace
			local currentLocationXmapPositiveX = touchPart.Position.X
			local currentLocationZmapPositiveX = touchPart.Position.Z
			mapPositiveX.Parent = workspace
			local assetsmapPositiveX = mapPositiveX:GetChildren()
			for i, v in pairs (assetsmapPositiveX) do
				v.Position = Vector3.new(currentLocationXmapPositiveX + movementAmount, 0, currentLocationZmapPositiveX)
			end

			local mapPositiveZ = map:Clone()
			local currentLocationXmapPositiveZ = touchPart.Position.X
			local currentLocationZmapPositiveZ = touchPart.Position.Z
			mapPositiveZ.Parent = workspace
			local assetsmapPositiveZ = mapPositiveZ:GetChildren()
			for i, v in pairs (assetsmapPositiveZ) do
				v.Position = Vector3.new(currentLocationXmapPositiveZ, 0, currentLocationZmapPositiveZ + movementAmount)
			end

			local mapNegativeZ = map:Clone()
			local currentLocationXmapNegativeZ = touchPart.Position.X
			local currentLocationZmapNegativeZ = touchPart.Position.Z
			mapNegativeZ.Parent = workspace
			local assetsmapNegativeZ = mapNegativeZ:GetChildren()
			for i, v in pairs (assetsmapNegativeZ) do
				v.Position = Vector3.new(currentLocationXmapNegativeZ, 0, currentLocationZmapNegativeZ - movementAmount)
			end

			local mapNegativeX = map:Clone()
			local currentLocationXmapNegativeX = touchPart.Position.X
			local currentLocationZmapNegativeX = touchPart.Position.Z
			mapNegativeX.Parent = workspace
			local assetsmapNegativeX = mapNegativeX:GetChildren()
			for i, v in pairs (assetsmapNegativeX) do
				v.Position = Vector3.new(currentLocationXmapNegativeX - movementAmount, 0, currentLocationZmapNegativeX)
			end
		end
		debounce = false
	end
end)

P.S. sorry for the sloppy code I’m still new at this

You can check if the Positions of the current part and the spot you are checking are equal. You can also use :FuzzyEq() to prevent rounding errors.

This method should probably be revised from root up. Touched event is easy to implement, but is very inconsistent and unreliable. Numerous connections to Touched isn’t very easy on memory either, so here are some alternatives to determine what tile players reside in:

  • Raycast downwards from every player with a CollisionGroup that only collides with tiles.
  • Mathematically determine the tile by taking the character’s position and comparing it to boundaries.

As for determining what adjacent tiles to fill, you could simply create a 2D array:

local grid = table.create(99, {}); --creates a table with 99 subtables, each representing a column on the y-axis
grid[50][50] = tile:Clone(); --50, 50 can be your center, you can reposition it according to its size and where the origin of the tile grid should be
--when the server detects a player on the a tile, simply check grid[x + 1][y], grid[x - 1][y], grid[x][y + 1], grid[x][y - 1] assuming x and y represent the location of the relevant tile within the grid and create a tile for each tested position if its unoccupied. if the relevant tile as at the side of grid then grid[x + 1][y] or grid[x - 1][y] will throw since grid[x + 1] or grid[x - 1] will be nil, so be sure to check for those before trying to index them

Thank you for the insight, from what I understand using a ray casting and part to part collision would be much better than :touched but I don’t get what you mean by

additionally how would I actually check if the tile being spawned is actually next to the relevant tile
do you know of a source which gives an example of this?

I take it you want to accomplish this? They don’t overlap.

Here’s a template that works with less than 40 lines of code to accomplish this. I did it all client side, but this should give you an idea of what to do and accomplish with some remotes.

It works with rotated pieces as well, should that matter.

regionSpawningSystem.rbxl (23.5 KB)

3 Likes

If we perceive the tiles as if they conform to a 2D grid, each tile would have four values representing the start and finish from bottom to top and left to right (or two coordinates representing opposite ends of the tile).

Say, for instance, the player was located at (1.2, 2.7) of this theoretical grid of tiles:

image

Assuming each tile always has a length and width of 1, we can easily assert that the player is within the tile located two tiles right and three tiles up (can be referenced with grid[2][3]) since that is the only tile in which the point (1.2, 2.7) resides. This is determined by comparing the leftmost x value of the tile (1) and the rightmost x value (2) with the player’s x value (1.2); the same applies with y values.

Verification of whether tiles are adjacent shouldn’t be necessary so long as we correctly create adjacent tiles for vacant positions and register them into our 2D array while positioning them correctly.

Thank you very much, I’d assume this works much like how anime_bb was explaining it? (ray casting from the player and creating a grid?)

His method uses raycasting to determine the tile that the player stands on as well as the presence of adjacent tiles, so there is no 2D array in effect here. The method is nonetheless very reliable and resourceful. I’d mark his reply as a solution since it satisfies your needs.

It doesn’t create a grid. A grid is more data-structurally organized and would be less performance-intensive if that was an issue.

At this point, I always remark that the decision of which to implement is which is easier to code, keep organized, and doesn’t cause a performance bottleneck.

Many scripters get obsessed with over-optimizing and micro-optimizing so much so that it compromises the results of their project.

If the raycasting method works fine for your needs, then I recommend using it. It’s simpler to implement but harder to query (you can’t ask the server very easily if there is a map piece at X/Y position because there is no data grid).

If the abstract grid (stored in Lua data) and querying is what you need, then use the abstract grid method. However, if it is too complicated to code at this time (think your abilities, don’t base off of others’ abilities) then use the raycasting method. I personally would create a grid system if I had a big game in mind. If the extent was just to do what is shown in my short video and nothing more, I’d just use raycasting and be done with things.

These are my opinions, feel free to take what you want out of them.