Hello,
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.
https://streamable.com/h6grx0
(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