Very customizable tower system for a tower defense game

I want to achieve an extremely customizable tower system which would allow me to create unique towers without having to create a completely new script for them, such as a money and a damage tower using the same script.

Since I want each of my towers to have a unique mechanic to them for example one tower would have a minigun that has a rev up and cooldown period or a tower that is made to buff other towers.

I have tried making new script for each of the towers and then cloning it but it seems very messy and I would like a better system where each tower was updated by a singular script, but still keep their unique functionalities.

1 Like

You said what you want and you said what you tried, but if this is to help you scripting towers that you already tried to script, it’s better show your script (even if it’s messy) so it’s possible to others help you easily, instead of some of them just ignore your topic

I don’t have any code to show what I want to achieve, I am only mentioning that I script each tower in seperate scripts, disable them and when I place towers I clone the script to the tower then I enable them and I meant that it’s messy is with the fact that each tower placed has it’s own script instead of 1 script handling all the logic like I can do with enemies since all they do is follow a selected path with a given speed.

You could use a mix of attributes, module scripts, and the collection service. In my small example the module function FindTarget is optional and Attack is required. If you make it too generic then you will end up repeating the same amount of code, it might be better to stick with your original system.
image

-- TowerCollector --
--!strict
local collectionService = game:GetService("CollectionService")

local function add_tower(new: Model)
	local subtower = require(new:FindFirstChildOfClass("ModuleScript"))
	
	while new and new.Parent do
		local target -- find target
		
		-- can specifiy which parts to overwrite
		if subtower.FindTarget then
			target = subtower.FindTarget(new)
		else
			-- find target our own way
		end

		subtower.Attack(new, target)
		task.wait(0.5)
	end
end

for _, tower in collectionService:GetTagged("Tower") do
	task.defer(add_tower, tower) -- use defer to keep going even though we loop in add_tower
end
collectionService:GetInstanceAddedSignal("Tower"):Connect(add_tower)

-- MoneyTower Module --
local money = {}

function money.FindTarget(self: Model)
	return nil
end

function money.Attack(self: Model, target: Instance?)
	self.Owner.Value.leaderstats.Money += 1
end

return money

-- MinigunTower Module --
local minigun = {}

function minigun.Attack(self: Module, target: Instance?)
	local humanoid = target:FindFirstChildOfClass("Humanoid")
	if humanoid then
		humanoid.Health -= 1
	end
end

return minigun
1 Like

This is exactly as the type of system I wanted, I sort of forgot about collection service and how useful it can be, thank you!