I want to achieve a Tower Defense Placement System similar to the one in Tower Defense Simulator. All towers shall be placed with a certain distance between them. Some towers can only be placed on higher places (e.g.snipers) while some can be only placed on the ground.
How would I make such a system? Is it worth to take a look at Ego Moose’s Placement System? If so how to check wheter the tower is on a higher place?
I would definitely recommend looking into the Tutorial by ego moose it’s a really great and can be applied to many systems, but in terms of checking distance between towers and if its enough to place, magnitude or even artificial hit boxes can be used. Height can be determined in many ways using rays, getting distance from a plane, or even calculating Altitude in general
TD;lr there are many ways to go about creating a system like this, it does somewhat Boil down to what you find the most sufficient
There are many different ways to handle this, but in my years of creating similar systems for home customization etc, I’ve never been hindered in just taking the simplest approach.
I would put all “towers” inside a folder or model in workspace. Whenever a player is placing a tower, any time the tower moves calculate the distance from the tower that is being placed to every tower inside of the model. If it’s far enough away, great. If it isn’t, recolor the tower that is being placed to red or whatever and don’t allow it to be placed down until the player moves it away.
As for the height, just setting the name of the part that the tower is being placed on to “SpecialHeight” or whatever has always worked for me by using mouse.Target.
Here’s a system I made with the replies of the thread. Sorry for bumping this. I don’t see any placement system scripts in here and I think this will be helpful for devs that are starting out
You should edit this to your liking cuz this is made for my game:
local SYSTEM = {}
--//VARIABLES//--
local towerFolder = game.ReplicatedStorage:WaitForChild("PlaceClones") -- Default is defensive
local CreateEntityEvent = game.ReplicatedStorage:WaitForChild("Remotes").Events.CreateEntity
--//SERVICES//--
local RunService = game:GetService("RunService")
local PhysService = game:GetService("PhysicsService")
function NoCollide(model)
for k,v in pairs(model:GetChildren()) do
if v:IsA"BasePart" or v.Name == "Collider" then
PhysService:SetPartCollisionGroup(v,"t")
end
end
end
function DistanceFromOtherTowers(tower, player)
local defensiveFolder = game.Workspace[player.Team.Name.."DefensiveTroops"]
local hasChild = false
local canPlace = false
local collideTroop = {}
for i,troop in pairs(defensiveFolder:GetChildren()) do
hasChild = true
if troop:IsA("Model") then
if (tower.PrimaryPart.Position - troop.PrimaryPart.Position).magnitude < 6 then
table.insert(collideTroop, troop)
end
end
end
if hasChild and #collideTroop == 0 then
return true
end
if hasChild == false and canPlace == false then
return true
end
end
function SYSTEM:PlaceTower(player, tower, mouse)
if player.dataFolder.IsPlacing.Value == true then return end
player.dataFolder.IsPlacing.Value = true
-- CLONE THE TOWER FROM REPLICATED STORAGE FIRST
local newClone = towerFolder:FindFirstChild(tower):Clone()
newClone.Parent = game.Workspace.PlaceFolder
local isPlaced = false
local canPlace = false
local terminate = false
NoCollide(newClone)
assert(mouse ~= nil, "BUILDING SYSTEM: MOUSE IS INVALID")
assert(newClone ~= nil, "BUILDING SYSTEM: CANNOT CLONE SOMETHING THAT DOESN'T EXIST!")
mouse.Button1Down:Connect(function()
if canPlace == true and isPlaced == false then
isPlaced = true
local placeCFrame = newClone.PrimaryPart.CFrame
newClone:Destroy()
player.dataFolder.IsPlacing.Value = false
CreateEntityEvent:FireServer("Archer", 1, "Defensive", placeCFrame) -- The placing event you should edit this.
terminate = true
end
end)
mouse.Button2Down:Connect(function()
newClone:Destroy()
isPlaced = false
canPlace = false
player.dataFolder.IsPlacing.Value = false
terminate = true
end)
-- GET THE PLAYER'S MOUSE POSITION EVERYTIME THE SCREEN RENDERS
RunService.RenderStepped:Connect(function()
if isPlaced == false and terminate == false then
local newcframe = mouse.Hit -- GET DA POSITION
newClone.HumanoidRootPart.CFrame = CFrame.new(newcframe.X, your height, newcframe.Z)
newClone.HumanoidRootPart.Orientation = Vector3.new(0,0,0)
newClone.Collider.Transparency = 0.5
if mouse.Target.Name == "PlacePart" and DistanceFromOtherTowers(newClone, player) and mouse.Target.Parent.Name == player.Team.Name then
newClone.Collider.BrickColor = BrickColor.new("Sage green")
canPlace = true
else
newClone.Collider.BrickColor = BrickColor.new("Really red")
canPlace = false
end
end
wait()
end)
end
return SYSTEM
Put this in a module script btw. Edit this:
newClone.HumanoidRootPart.CFrame = CFrame.new(newcframe.X, your height, newcframe.Z)
This should be activated from the client. Should know how to use moduleScripts before attempting to use this. Go watch Alvin Blox’s tutorial on it.
Also the newClone.Collider is just a box that acts as the indictor.