I am currently trying to make a placement system for a tower defense game, however I’ve never made some so I am quite confused on how to do this. I tried making a simple quick system to base it off of, however I don’t think it’s as efficient as I want it to be.
(ignore the prints i forgot to disable that)
As you can see in the video, what you’re placing follows the mouse, however the way to check if you actually can place is based on blocks. I decided to use blocks instead of regions as this is on the client, and if they’re not cheating, it will show where you can and can’t place blocks, however the server is the final decider if they can or can’t place the tower there.
My issue is the boundaries and the server. I don’t want the player to place very far from itself, which I’ve already got that coded. I also don’t want them to be able to place over a track, or on top of another tower, and this is where my issue is. I was thinking of using Region3, but I’m bad at Region3 so its gonna get confusing for me. I was also thinking of using a module called ZonePlus (ZonePlus v3.2.0 | Construct dynamic zones and effectively determine players and parts within their boundaries), however the main use of this is to use parts, and I can’t do that as
mouse.Hit.Position registers those Parts.
Here is the client side of the code, let me know if you want to see the server side:
local player = game.Players.LocalPlayer local mouse = player:GetMouse() local placeRemote = game.ReplicatedStorage:WaitForChild("Remotes"):WaitForChild("PlaceTower") local runService = game:GetService("RunService") local contextAction = game:GetService("ContextActionService") local YOffset = 1.3 local maxDist = 25 local defender = game.ReplicatedStorage.Towers.Defender:Clone() defender.Parent = workspace player.CharacterAppearanceLoaded:Wait() local function pingServer(something, inputState) if inputState == Enum.UserInputState.End then local magnitude = (player.Character.HumanoidRootPart.Position - defender.PrimaryPart.Position).magnitude if magnitude <= maxDist then local result = placeRemote:InvokeServer(defender:GetAttribute("ToPlace"), mouse.Hit.Position) print(result) end end end contextAction:BindAction("Place Tower", pingServer, true, Enum.UserInputType.MouseButton1) local function changeColor(tower, status) local color if status == true then defender.Color.Value = true color = BrickColor.new("Really red") else defender.Color.Value = false color = BrickColor.new("Bright green") end for i,v in ipairs(defender:GetDescendants()) do if v:IsA("BasePart") then v.BrickColor = color end end end mouse.TargetFilter = defender runService.Heartbeat:Connect(function() local mousePos = mouse.Hit.Position local magnitude = (player.Character.HumanoidRootPart.Position - defender.PrimaryPart.Position).magnitude print(mouse.Target) if magnitude >= maxDist then if defender.Color.Value == false then defender.Color.Value = true changeColor(defender, true) end elseif mouse.Target.Name == "Bad" then if defender.Color.Value == false then defender.Color.Value = true changeColor(defender, true) end elseif mouse.Target.Name == "Good" then if defender.Color.Value == true then defender.Color.Value = false changeColor(defender, false) end end defender:SetPrimaryPartCFrame(CFrame.new(mousePos.X, mousePos.Y + YOffset, mousePos.Z)) end)
Let me know of any solutions you got! Thanks
edit: wrong video