diff --git a/Tower.lua b/Tower.lua new file mode 100644 index 0000000..bccc475 --- /dev/null +++ b/Tower.lua @@ -0,0 +1,42 @@ +local Tower = {} +Tower.__index = Tower + +function Tower:new(model, position, range, damage, fireRate, effect) + local self = setmetatable({}, Tower) + self.model = model:Clone() + self.model.Position = position + self.model.Anchored = true + self.model.Parent = workspace + self.range = range + self.damage = damage + self.fireRate = fireRate or 1 -- shots per second + self.effect = effect -- set of params for effect + self.lastFire = 0 + return self +end + +function Tower:canAttack(enemy) + if not enemy.alive or not enemy.model or not enemy.model.PrimaryPart then return false end + local dist = (self.model.Position - enemy.model.PrimaryPart.Position).Magnitude + return dist <= self.range +end + +function Tower:attack(enemies, dt) + self.lastFire = self.lastFire + dt + if self.lastFire >= (1 / self.fireRate) then + for _, enemy in ipairs(enemies) do + if self:canAttack(enemy) then + enemy:damage(self.damage) + + if self.effect then + enemy:applyEffect(self.effect.name, self.effect.params) + end + + self.lastFire = 0 + break -- Only attack one enemy per fire + end + end + end +end + +return Tower diff --git a/TrackEnemy.lua b/TrackEnemy.lua index 1bed92e..7db7b44 100644 --- a/TrackEnemy.lua +++ b/TrackEnemy.lua @@ -7,12 +7,45 @@ function TrackEnemy:new(model, name, health, speed) self.model = model self.name = name self.health = health + self.baseSpeed = speed self.speed = speed self.alive = true self.currentWaypoint = 1 + self.effects = {} return self end +function TrackEnemy:applyEffect(effectName, params) + self.effects[effectName] = { + duration = params.duration, + tick = params.tick, + value = params.value, + elapsed = 0 + } +end + +function TrackEnemy:updateEffects(dt) + for name, effect in pairs(self.effects) do + effect.elapsed = effect.elapsed + dt + if name == "burn" and effect.tick then + if effect.elapsed >= effect.tick then + self:damage(effect.value) + effect.elapsed = effect.elapsed - effect.tick + end + elseif name == "slow" then + self.speed = self.baseSpeed * effect.value + elseif name == "freeze" then + self.speed = 0 + end + + effect.duration = effect.duration - dt + if effect.duration <= 0 then + self.effects[name] = nil + self.speed = self.baseSpeed + end + end +end + function TrackEnemy:damage(amount) self.health = self.health - amount if self.health <= 0 then @@ -28,7 +61,8 @@ function TrackEnemy:die() end end -function Trackenemy:moveToWaypoints(waypoints, dt) +function TrackEnemy:moveToWaypoints(waypoints, dt) + self:updateEffects(dt) if not self.currentWaypoint then self.currentWaypoint = 1 end local target = waypoints[self.currentWaypoint] if target then diff --git a/TrackLogic.lua b/TrackLogic.lua index c940918..9f2f472 100644 --- a/TrackLogic.lua +++ b/TrackLogic.lua @@ -1,5 +1,41 @@ local RunService = game:GetService("RunService") +local Tower = require(script.Parent.Tower) local Waves = require(script.Parent.Waves) + +local towerTypes = { + { + name = "Basic", + model = workspace.BasicTowerModel, + range = 20, + damage = 10, + fireRate = 1, + }, + { + name = "Slow", + model = workspace.SlowTowerModel, + range = 15, + damage = 5, + fireRate = 0.5, + effect = {name = "slow", params = {duration = 2, value = 0.5}} + }, + { + name = "Fire", + model = workspace.FireTowerModel, + range = 18, + damage = 8, + fireRate = 1, + effect = {name = "burn", params = {duration = 3, tick = 1, value = 2}} + }, + { + name = "Freeze", + model = workspace.FreezeTowerModel, + range = 12, + damage = 0, + fireRate = 0.5, + effect = {name = "freeze", params = {duration = 1}} + } +} + local waypoints = { -- Fill with your waypoint Parts workspace.Waypoint1, workspace.Waypoint2, @@ -7,8 +43,13 @@ local waypoints = { -- Fill with your waypoint Parts -- etc. } - +local selectedTowerType = towerTypes[1] local enemies = {} -- Table to hold TrackEnemy objects +local towers = {} + +function selectTowerType(index) + selectedTowerType = towerTypes[index] +end local function spawnWave(waveData) coroutine.wrap(function() @@ -17,6 +58,7 @@ local function spawnWave(waveData) local enemyModel = group.model:Clone() enemyModel.Parent = workspace local enemy = TrackEnemy:new(enemyModel, group.name, group.health, group.speed) + table.insert(enemies, enemy) end if group.delay and group.delay > 0 then @@ -28,6 +70,40 @@ end spawnWave(Waves[1]) +local function isOnTrack(position) + for _, waypoint in ipairs(waypoints) do + if (waypoint.Position - position).Magnitude < 5 then -- 5 studs + return true + end + end + return false +end + +UserInputService.InputBegan:Connect(function (input, gameProcessed) + if gameProcessed then return end + if input.UserInputType == Enum.UserInputType.MouseButton1 then + local mouse = game.Players.LocalPlayer():GetMouse() + local position = mouse.Hit.p + if not isOnTrack(position) then + local tower = Tower:new( + selectedTowerType.model, + position, + selectedTowerType.range, + selectedTowerType.damage, + selectedTowerType.fireRate, + selectedTowerType.effect + ) + table.insert(towers, tower) + end + end +end) + +RunService.Heartbeat:Connect(function(dt) + for _, tower in ipairs(towers) do + tower:attack(enemies, dt) + end +end) + RunService.Heartbeat:Connect(function(dt) for i, enemy in ipairs(enemies) do if enemy.alive then