Detecting in part is in another?

Hello Developers,
Recently I’ve made a spawning system which spawns a random item randomly inside a region3 on the X, Y axis but I need the item to spawn on top of surfaces and not just on the floor. I’ve tried using .Touched and Region3 but Touched wouldn’t register properly and Region3 kept and making the parts position move to the surface position but it would happen anywhere in the region not when the part is actually inside another one.

This is how I calculate the x and y but like I said I do not know how to calculate the y.

	local X, Z = SpawnRegion.Size.X, SpawnRegion.Size.Z
	local X, Z = math.random(1, X), math.random(1, Z)
	local X, Z = (Spawn.Position - Vector3.new(Spawn.Size.X/2)) + Vector3.new(X, 0, 0), (Spawn.Position - Vector3.new(Spawn.Size.Z/2)) + Vector3.new(Z, 0, 0)
	print(X)
	Item.Parent = game.Workspace.ItemSpawns
	Item.Anchored = true
	local Items = Item:GetChildren()
	for i, v in pairs(Items) do
		if v:IsA("Part") then
			v.Anchored = true
		elseif v:IsA("UnionOperation") then
			v.Anchored = true
		end
	end
	local IgnoredPlayers = {}
	for i, Player in pairs(game.Players:GetChildren()) do
		if Player and Player.Character then
			table.insert(IgnoredPlayers, Player.Character)
		end
	end
	local PartsInWhitelist = game.Workspace:FindPartsInRegion3WithIgnoreList(SpawnRegion, IgnoredPlayers, 100)
	Item.Position = Vector3.new(X.X, Spawn.Position + Vector3.new(Spawn.Size.Y/2), Z.Z)

Full script (Region3 for Y axis):

--[Variables]--
local SpawnSettings = require(script.SpawnSettings)
local Spawns = SpawnSettings.Spawns
local Spawn = script.Parent
local SpawnCorner1 = Spawn.Position - Vector3.new(Spawn.Size.X /2, Spawn.Size.Y/2, Spawn.Size.Z/2)
local SpawnCorner2 = Spawn.Position + Vector3.new(Spawn.Size.X /2, Spawn.Size.Y/2, Spawn.Size.Z/2)
local SpawnRegion = Region3.new(SpawnCorner1, SpawnCorner2)
local ServerStorage = game:GetService("ServerStorage")

local function SpawnItem()
	local ItemTypeNumber = 0
	for i, v in pairs(SpawnSettings.Items) do
		ItemTypeNumber = ItemTypeNumber +1
	end
	ItemTypeNumber = math.random(1, ItemTypeNumber)
	local ItemType = SpawnSettings.Items[ItemTypeNumber]
	ServerStorage:WaitForChild(ItemType)
	local ItemNumber = 0
	for i, v in pairs(SpawnSettings.Spawns[ItemType]) do
		ItemNumber = ItemNumber +1
	end
	print(ItemType)
	local ItemNumber = math.random(1, ItemNumber)
	local ItemName = SpawnSettings.Spawns[ItemType][ItemNumber]
--ANYTHING ABOVE IS NOT IMPORTANT TO THE QUESTION--
--ANYTHING ABOVE IS NOT IMPORTANT TO THE QUESTION--
--ANYTHING ABOVE IS NOT IMPORTANT TO THE QUESTION--
	local Item = ServerStorage:WaitForChild(ItemType):WaitForChild(ItemName):Clone()
	local X, Z = SpawnRegion.Size.X, SpawnRegion.Size.Z
	local X, Z = math.random(1, X), math.random(1, Z)
	local X, Z = (Spawn.Position - Vector3.new(Spawn.Size.X/2)) + Vector3.new(X, 0, 0), (Spawn.Position - Vector3.new(Spawn.Size.Z/2)) + Vector3.new(Z, 0, 0)
	print(X)
	Item.Parent = game.Workspace.ItemSpawns
	Item.Anchored = true
	local Items = Item:GetChildren()
	for i, v in pairs(Items) do
		if v:IsA("Part") then
			v.Anchored = true
		elseif v:IsA("UnionOperation") then
			v.Anchored = true
		end
	end
	local IgnoredPlayers = {}
	for i, Player in pairs(game.Players:GetChildren()) do
		if Player and Player.Character then
			table.insert(IgnoredPlayers, Player.Character)
		end
	end
	table.insert(IgnoredPlayers, Spawn)
	local PartsInWhitelist = game.Workspace:FindPartsInRegion3WithIgnoreList(SpawnRegion, IgnoredPlayers, 100)
	Item.Position = Vector3.new(X.X, Spawn.Position + Vector3.new(Spawn.Size.Y/2), Z.Z)
	wait()
	for i, Part in pairs(PartsInWhitelist) do
		local PartCorner1 = Part.Position - Vector3.new(Part.Size.X /2, Part.Size.Y/2, Part.Size.Z/2)
		local PartCorner2 = Part.Position + Vector3.new(Part.Size.X /2, Part.Size.Y/2, Part.Size.Z/2)
		local PartRegion = Region3.new(PartCorner1, PartCorner2)
		table.insert(IgnoredPlayers, Part)
		local PartsInWhitelistParts = game.Workspace:FindPartsInRegion3WithIgnoreList(PartRegion, IgnoredPlayers, 1)
		local p = Instance.new("Part", workspace)
		p.Anchored = true
		p.Transparency = 0.6
		p.Size = PartRegion.Size
		p.CFrame = PartRegion.CFrame
		if PartsInWhitelistParts ~= nil then
			for i, v in pairs(PartsInWhitelistParts) do
				local Y = Part.Position - Vector3.new(Spawn.Size.Y/2)
				Item.Position = Vector3.new(X.X, Y.Y, Z.Z)
			end
		end
	end
end

SpawnItem()

This is what I’m trying to do.

2 Likes

cant you just use GetTouchingParts
just read up on it, appearently that’s not how it works

1 Like

Hello!

I would calculate the y by doing this:

local y = part.Y + part.Size.y/2

You have to get the parts in the region3 and then do the code above.

1 Like

I’m going to update the code with the full script including my region 3 progress. I tried using region 3 like I said but I had no luck.

1 Like

If i understand this correctly you want the item to go ontop of the part?

This would be done by doing:

if PartsInWhitelistParts ~= nil then
		for i, v in pairs(PartsInWhitelistParts) do
			local Y = Part.Position.Y + Part.Size.Y/2 --This is what i've changed!
			Item.Position = Vector3.new(X.X, Y.Y, Z.Z)
		end
end

This works but sometimes its still going up even when its not inside the part. I’m 99% sure my regions are correct aswell

image
image

1 Like

I’m pretty sure you actually can use :getTouchingParts() in this instance. The only thing is that the object in question needs to have a TouchInterest. So if you wrapped your spawned item in an invisible brick that extended to the bounds of the model, put a TouchInterest in it, then you could use that method.

Alternatively, I believe that if you raycast down from the model’s PrimaryPart (given that it’s in a reasonably central location on the model) you should be able to find any parts that it’s currently inside of/above. Then you can just use the properties of the Ray (getting the hit part/position) to move the spawned object up to the hit part’s top surface.

2 Likes

Could you elaborate on why that wouldn’t work?

Just use FindPartOnRay, probably ignoring everything that is not the map with it.
You also do not need to use region3. You can just store a CFrame and a Size vector, that way you can rotate it if you would like (which is not possible with Region3).
Then you can just find the location from something like Region.CFrame * CFrame.new(size.X * rand(), size.Y * rand(), size.Z * rand()) where rand() returns something between -0.5 and 0.5. You can shoot the ray down from the sky or top of the region to find where the floor is.

1 Like

Hope this would help:

With the informations in my tutorial you can compare each corner with the corner of your model, i am working on a corner module script, wait a bit and i can send you the script i made (it work). Thanks for waiting @aIphabox. So, just make a script that check the position, and if it was false then use coroutines or spawn functions for create a loop and always check until if it was in the Region. Its just a idea, but hope it will help you.

1 Like

So, i found it. This is the first part:

local CornerModule = {}

--The Variables
local Helper = require(script.VerticesController)

function CornerModule:IsInRegion(Region, Part)
	--Check if the Region parameter is a Region3
	if typeof(Region) == "Region3" and typeof(Part) == "Instance" then
		if Helper.CheckValues(Part, Region) == true then
			--If all Corners are in the Region3 then return true
			return true										
		else
			--Else return false
			return false
		end
	else
		--If nothing work then the Parameters are incorrect and the Module will launch a error message
		error("CornerModule error message from function GetCorners() : Incorrect Parameters.")
	end
end

return CornerModule

And the second was on Github.
So, hope this now really help you!

1 Like

Sorry @aIphabox, i just see that it already was solved, but i think this can still be helpfull, so i leave this. @Wunder_Wulfe, i not really understand your method, can you try to explicate this more in deep, else this it’s ok