I’ve been attempting to make an optimized, performance based tower defense game now and had a question in mind.
What’s the best way tower defense game nowadays handle UNIT selecting and deselecting? At the moment I have 1 centralized client module that handles “Placement” and also handles selecting and deselecting units by keeping track of the user’s mouse and what they click. The module keeps tracking of all placed unit for this, as in when the user clicks a model and its a valid unit, → show range and unit info in a frame. THIS IS MY QUESTION Is this how should I handle unit selection and deselection? Should I make a clickable invisible part for each unit instead?
My general way of handling placement in my placement module
local function updatePlacement()
local context = {
UIS = UIS,
workspace = workspace,
RaycastParams = RaycastParams.new(),
currentModel = currentModel,
yRotation = yRotation,
placementHeightOffset = placementHeightOffset,
currentPlacementType = currentPlacementType,
PLACEABLE_ZONE_NAME = "PlaceableZone",
PATH_ZONE_NAME = "PathZone",
highlight = highlight,
lastValidCFrame = lastValidCFrame,
LocalPlayer = LocalPlayer,
mobilePlacementOffset = mobilePlacementOffset,
mobileFineTuneOffset = mobileFineTuneOffset,
}
context.RaycastParams.FilterDescendantsInstances = {currentModel}
context.RaycastParams.FilterType = Enum.RaycastFilterType.Blacklist
if isMobile then
MobilePlacementLogic.updatePlacement(context)
lastValidCFrame = context.lastValidCFrame
else
PCPlacementLogic.updatePlacement(context)
lastValidCFrame = context.lastValidCFrame
end
if currentModel and placementUnitRange then
if lastValidCFrame then
if not placementRangeShown then
RangeDrawerClient.showRange(currentModel, placementUnitRange)
placementRangeShown = true
end
else
if placementRangeShown then
RangeDrawerClient.hideRange(currentModel)
placementRangeShown = false
end
end
end
end
And UNIT Selection method in my module
-- Click/tap logic for selecting/deselecting units
local function onUnitClick()
local mouse = Players.LocalPlayer:GetMouse()
mouse.Button1Down:Connect(function()
if placing then return end
local target = mouse.Target
if not target then
clearCurrentSelection()
if UnitDeselectedEvent then UnitDeselectedEvent:FireServer() end
return
end
local parentModel = target:FindFirstAncestorOfClass("Model")
if parentModel then
if isTemplateModel(parentModel) then
clearCurrentSelection()
if UnitDeselectedEvent then UnitDeselectedEvent:FireServer() end
return
end
local success, result = pcall(function()
return GetUnitOwner:InvokeServer(parentModel)
end)
if success and typeof(result) == "Instance" and result:IsA("Player") then
selectUnit(parentModel)
else
clearCurrentSelection()
if UnitDeselectedEvent then UnitDeselectedEvent:FireServer() end
end
else
clearCurrentSelection()
if UnitDeselectedEvent then UnitDeselectedEvent:FireServer() end
end
end)
end