TD Placement Raycasting

Hey DevForum! I’m making a tower defense game for fun, and when making the placement of the towers it is looking really un-smooth. (I’m having a brain fart for the word)

I think that if there is some way to make the raycast completely ignore the tower and just continue raycasting to the baseplate it would make it 100x more smooth. Right now the raycast just doesn’t do anything if the mouse is over the tower. Here is my code:

local runService = game:GetService("RunService")
local repStorage = game:GetService("ReplicatedStorage")
local players = game:GetService("Players")

local player = players.LocalPlayer
local mouse = player:GetMouse()

local ground = workspace:WaitForChild("Baseplate")

local towerModel = nil

game:GetService("UserInputService").InputBegan:Connect(function(input)
	if input.KeyCode == Enum.KeyCode.E then
		towerModel = repStorage.Towers["Soldier"]:Clone()
		towerModel.Parent = workspace
		towerModel:PivotTo(CFrame.new(mouse.Hit.Position.X, 1.5, mouse.Hit.Position.Z))
	end
end)

mouse.Move:Connect(function()
	if towerModel then
		local target = mouse.Hit.Position
		local unit = workspace.CurrentCamera:ScreenPointToRay(mouse.X, mouse.Y, 1)
		
		local raycastParams = RaycastParams.new()
		raycastParams.FilterDescendantsInstances = {towerModel}
		raycastParams.FilterType = Enum.RaycastFilterType.Exclude
		
		local raycastResults = workspace:Raycast(unit.Origin, unit.Direction*10000, raycastParams)
		if raycastResults and raycastResults.Instance == ground then
			towerModel:PivotTo(CFrame.new(target.X, 0, target.Z))
		end
	end
end)

mouse.Button1Down:Connect(function()
	if towerModel then
		towerModel.Parent = workspace.PlacedTowers
		towerModel = nil
	end
end)

Thanks in advance! :grin:

If you want just the baseplate to be taken into account, you could set your RaycastParams FilterType to Include and then just set the FilterDescendantsInstances to the baseplate.

But if you want just the tower to be excluded, you need to pass your raycastParams to your workspace:Raycast call, it’s missing here:

local raycastResults = workspace:Raycast(unit.Origin, unit.Direction*10000)

^this line should be

local raycastResults = workspace:Raycast(unit.Origin, unit.Direction*10000, raycastParams)

Wow, I can’t believe thats what I missed… :disappointed_relieved:

It’s doing something else weird now, any ideas why?

Edit: I also changed the code in the main post to match mine.

1 Like

Think it’s because you’re using the mouse.Hit, the mouse raycast is isolated from any other raycasts. The RaycastResult will have a Position property, try using that instead of mouse.Hit.

It’s probably advisable in all cases to be using UserInputService anyway in place of the mouse.

So your final mouse.Move connection would look something like:

mouse.Move:Connect(function()
	if towerModel then
        local raycastParams = RaycastParams.new()
        raycastParams.FilterType = Enum.RaycastFilterType.Exclude
		raycastParams.FilterDescendantsInstances = {towerModel}
        
		local mouse = userInputService:GetMouseLocation()
		local unit = workspace.CurrentCamera:ViewportPointToRay(mouse.X, mouse.Y, 1)
		local raycastResults = workspace:Raycast(unit.Origin, unit.Direction*1000, raycastParams)
		if raycastResults and raycastResults.Instance == ground then
			local target = raycastResults.Position
			towerModel:PivotTo(CFrame.new(target.X, 0, target.Z))
		end
	end
end)

It worked perfectly! Thank you so much for all the help!

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.