How do I detect collisions on an anchored object for a placement system?

I have recently scripted a placement system for this game Im working on the problem is that I dont know how to detect collisions on the object being placed.

Code:


local Placement = {}
	local TowerStats = require(game.ServerScriptService.Modules.TowerStats)
	local Towers = game.ServerStorage.Towers
	function Placement.PlaceTower(Player, Item, Position)
		local Clone = Towers[Item]:Clone()
		local Stat1, Stat2 = Clone["Branch 1"], Clone["Branch 2"]
		local Value = TowerStats["Calc"..Item](Stat1, Stat2)
		
		if Player.Stats.Money.Value >= Value.Cost then
			Player.Stats.Money.Value = Player.Stats.Money.Value - Value.Cost
			Clone.Parent = game.Workspace
			Clone:SetPrimaryPartCFrame(CFrame.new(Position) + Vector3.new(0,2,0))
			Clone[Item].Disabled = false
		else
			Clone:Remove()	
		end
		
	end
	


return Placement

The “Towers” variable is not a table! Try doing something like this instead: (Although you don’t need a table, its considered best practice)

local Towers = game.ServerStorage.Towers:GetChildren() --Returns a table

I would use the Part:GetTouchingParts(). Like this:

local Part = game.Workspace.Part
local Touching = Part:GetTouching() -- Returns a table of touching parts.

Having a bit of a problem with that function

Code:

local function PlaceItem(Button)
	local TempClone = game.ReplicatedStorage.Towers[Button.Tower.Value]:Clone()
	TempClone.Parent = game.Workspace
	TempClone.PrimaryPart.CanCollide = false
	TempClone:SetPrimaryPartCFrame(Player.Character.HumanoidRootPart.CFrame:ToWorldSpace(Starting))
	local Stepped = RunService.Stepped:Connect(function()
		local MouseRay = Mouse.UnitRay
		local Cast = Ray.new(Vector3.new(Mouse.Origin), Vector3.new(MouseRay.Direction) * 1000)
		local IngoreList = {TempClone , Player.Character}
		local Hit, Pos = workspace:FindPartOnRayWithIgnoreList(Cast, IngoreList)
		TempClone:SetPrimaryPartCFrame(CFrame.new(Mouse.Hit.p)*Starting)
	end)
	
Connections[Mouse] = Mouse.Button1Down:Connect(function()
		local Touching = TempClone.PrimaryPart:GetTouchingParts()
		print(Touching)
		if Touching ~= TempClone or Touching ~= game.Workspace.Towers:GetChildren() then
			local Positions = Mouse.Hit.p
			Place:InvokeServer(Positions + Vector3.new(-2,-.5,-2) , Button.Tower.Value)
			Connections[Mouse]:Disconnect()
			Stepped:Disconnect()
			TempClone:Remove()
		else
			print(Touching)
		end
	end)	
end

I dont know what to do.

I don’t know for sure but I assume there are no parts at all in the table Touching. If you read the docs linked by @HawDevelopment, it says that if the part has CanCollide to false then it returns an empty table. I’ve never dealt with :GetTouchingParts() so I may be wrong for that issue.

I will say that it returns a part object so you will first have run a for loop through the Touching table(the table with :GetTouchingParts(). Then for each v (for I, v in pairs(Touching)) in the table you’ll have to run a for loop through all of the towers in the workspace (for x, y in pairs(game.Workspace.Towers:GetChildren())To compare them I would do “if v.Parent ~= TempClone and v.Parent ~= y then”.

Note I am typing this on my phone and trying to do my best. It’s kind of hard to explain and elaborate as I can’t type code blocks. Hopefully that helps and the variable names are up to your choosing. If you still need help I’ll try in the morning.

2 Likes
local Touching = TempClone.PrimaryPart:GetTouchingParts()
--- Created this variable to use for creating a tower
local createTower = true

for i, part in pairs(Touching) do
   for v, tower pairs(game:GetService("Workspace"):FindFirstChild("Towers"):GetChildren()) do
        if part.Parent == TempClone or part.Parent == tower then
            createTower = false
            break
        end 
    end
    if createTower == false then
        break 
    end
end

if createTower == true then
    --- Your same code, but after every Touching part is tested and can create
	local Positions = Mouse.Hit.p
	Place:InvokeServer(Positions + Vector3.new(-2,-.5,-2) , Button.Tower.Value)
	Connections[Mouse]:Disconnect()
	Stepped:Disconnect()
	TempClone:Remove()
--- Unnecessary elseif could just do else
elseif createTower == false then
	print("Was Touching Tower")
end

This code is not perfect and may be completely wrong, but I will explain a bit more. I created the createTower variable in order to track if you are able to create a new tower where you click. If it is true then it will create your tower based on your old code (the last if statement in my code). If it is false it will just print text, obviously optional in any code.

The loops:

for i, part in pairs(Touching) do

This loops through all of the parts in your table that you get from :GetTouchingParts(). Every part in the table because the value of part. You see similar code as something like i, v in pairs() if you happen to be unfamiliar with for-loops.

for v, tower in pairs(game:GetService("Workspace"):FindFirstChild("Towers"):GetChildren()) do

Firstly, the :GetService() and :FindFirstChild() aren’t required. I use them to ensure the Service, in this case workspace, has been created, and I used :FindFirstChild() to ensure I’ve found the child. You can still do game.Workspace.Towers or workspace.Towers. Second, the loop will be like the first for-loop where it will go through every tower in your folder.


If-statement explanation:

if part.Parent == TempClone or part.Parent == tower then

Here I first compare the part’s (obtained from the first for-loop) parent to your TempClone model. The second statement I do is compare the same part’s parent to the current tower in the loop.
How it works: Part A will be compared to the TempClone as well as Tower A (example). If they are not equal then Part A is compared to TempClone again but now is compared to Tower B, and so on until all towers are tested. Part B would work the same way after Part A tests all towers.

For example, if Part A.Parent is equal to Tower B then the if-statement (from above) becomes true meaning the code inside runs.
This being said, you first change the createTower to false because there is a Tower there and you don’t want to create a tower. Next, I break the for-loop (for v, tower in pairs…). I break it because there isn’t a point to continue since you aren’t creating a tower anyways. With if createTower == false then, I break the first for-loop (for i, part in pairs…) for the same reason.

[NOTE] If you have any folders or models in your TempClone or Towers in the workspace, this could cause problems because the part.Parent would be the folder/model rather than the tower itself. Just a warning. You could either remove folders/models or add other for-loops.


Now that either createTower is false or the for-loops finish and createTower is true, thelast if-statement at the bottom runs. This is the if-statement where if createTower is true, will run your previous code that will create a tower at the position clicked. If it is false then it just prints text (again optional).

I hope I explained everything well enough and considering you are making a placement system I could have probably left out some details, but nonetheless hopefully this code will either work or help guide you on the correct path. Do note that you still may want to check the :GetTouchingParts() documentation because of the CanCollide = false thing that may be an error. Have a good day and sorry for such a long response!

1 Like

The parts are set to cancollide = false, How can i make this if that is the case?

Let’s take this to discord, this thread is getting too cluderet.

1 Like

you can give a touch interest to every part, you can do this by connecting each part to a empty touched function after that gettouchingparts will work

1 Like

Make sure to disconnect them after placement though!

2 Likes

I would go with what @Thedagz and @KeysOfFate said. I haven’t used TouchInterests before, so I am not the best to help you with how to use them. You could either look up in the documentation, look through the DevForum, or just ask them for some help. Either way good luck.