-
What do you want to achieve?
So, I have been working on a Tower Defense game solo, and I am attmepting to make a track tower for the first time. Now, I have a module function to control enemy and track unit spawns, and they are quite similar, however, when spawning a unit the function will stop working if the for loop in it does not go through all the way. This usually happens because the unit damages an enemy and gets destroyed when it doesn’t have enough health to kill the enemy. -
What is the issue?
As briefly stated above, if my unit for a tower in my tower defense game dies from damaging enemies, it causes no more units to be spawned. It’s really annoying because I don’t know what is causing this issue as I get no output errors, and on paper the code shouldn’t have any issues. -
What solutions have you tried so far?
This problem is quite specific so I didn’t expect to find anything on the Devforum. However, at first I thought it was an issue caused by lacking a wait time between spawning units. However, once I disabled the unit’s damage script, the function works fine and doesn’t stop executing. I also thought it could be solved with putting some returns, as maybe the function isn’t concluding when the unit is destroyed, however that didn’t seem to wor either. I am not sure what is causing the script to simply stop running so I thought I would take to the devforum to get some in put.
Here is any relevant code needed to analyze the issue:
Spawn Function:
function waveManager.SpawnUnit(tower, level, unitName)
print("Spawning ".. unitName)
local map = workspace:FindFirstChild(replicatedStorage.MatchData.MapName.Value)
local paths = map:FindFirstChild("UnitCheckpoints")
local numPaths = #paths:GetChildren()
local unit = replicatedStorage.Towers[tower][level][unitName]:Clone()
unit.HumanoidRootPart.Position = map.UnitCheckpoints:FindFirstChild("0").Position
unit.Parent = workspace.Units
unit.Name = unitName
for i = 1, numPaths - 1, 1 do
if unit ~= nil then
local trackPart = paths[i]
local previousVal = i - 1
local previousTrack = paths[previousVal]
if unit ~= nil and unit.PrimaryPart ~= nil then
unit:SetPrimaryPartCFrame(previousTrack.CFrame)
else
return
end
local endPoint = {
Position = trackPart.CFrame.Position
}
local speed
local tweenInfo
local tween
if unit and unit:FindFirstChildOfClass("Humanoid") then
speed = ((paths:FindFirstChild(i).Position - paths:FindFirstChild(previousVal).Position).Magnitude) / (1 + unit:FindFirstChild("Humanoid").WalkSpeed)
tweenInfo = TweenInfo.new(speed, Enum.EasingStyle.Linear, Enum.EasingDirection.Out)
tween = tweenService:Create(unit.PrimaryPart, tweenInfo, endPoint)
else
return
end
if tween ~= nil then
tween:Play()
tween.Completed:Wait()
end
if i == numPaths - 1 and unit ~= nil then
unit:Destroy()
end
elseif unit == nil then
return
end
end
end
Unit Damage Script:
local pirate = script.Parent
local enemyFolder = workspace.Enemies
local nearbyEnemies = {}
local attacking = false
local function Attack(enemy, damage)
--idleAnim:Stop()
attacking = true
local attackSound = pirate.Humanoid:FindFirstChild("AttackSound")
attackSound:Play()
local humanoid = script.Parent.Humanoid
local animator = humanoid.Animator
local attack = humanoid.Attack
local animTrack = animator:LoadAnimation(attack)
animTrack.Priority = Enum.AnimationPriority.Action
animTrack:Play()
if enemy ~= nil then
local enemyHealth = enemy.Humanoid.Health
if pirate.Configuration.Health.Value > enemyHealth then
pirate.Configuration.Health.Value -= enemyHealth
enemy:Destroy()
print("Pirate has ".. pirate.Configuration.Health.Value .." health leftover")
elseif pirate.Configuration.Health.Value == enemyHealth then
pirate:Destroy()
enemy:Destroy()
elseif pirate.Configuration.Health.Value < enemyHealth then
enemy.Humanoid:TakeDamage(pirate.Configuration.Health.Value)
pirate:Destroy()
end
end
attacking = false
end
local function CheckTargets()
local targetEnemy
local highestDistance = 0
local furthest
for _, enemy in pairs(enemyFolder:GetChildren()) do
if enemy and enemy.HumanoidRootPart and pirate.PrimaryPart then
if (pirate.PrimaryPart.Position - enemy.HumanoidRootPart.Position).Magnitude <= pirate.Configuration.Range.Value and nearbyEnemies[enemy] == nil then
table.insert(nearbyEnemies, enemy)
end
for _, enemyToAttack in pairs(nearbyEnemies) do
if enemyToAttack:FindFirstChild("Configuration") ~= nil and enemyToAttack:FindFirstChild("Configuration").Distance.Value > highestDistance then
highestDistance = enemyToAttack.Configuration.Distance.Value
furthest = enemyToAttack
if (pirate.PrimaryPart.Position - furthest.HumanoidRootPart.Position).Magnitude <= pirate.Configuration.Range.Value then
Attack(furthest, pirate.Configuration.Health.Value)
end
end
end
end
end
for _, enemy in pairs(enemyFolder:GetChildren()) do
for i, closeEnemy in pairs(nearbyEnemies) do
if enemy ~= nil and enemy.HumanoidRootPart and pirate.PrimaryPart then
if (pirate.PrimaryPart.Position - enemy.HumanoidRootPart.Position).Magnitude > pirate.Configuration.Range.Value then
if closeEnemy == enemy then
table.remove(nearbyEnemies, i)
end
end
end
end
enemy.Humanoid.Died:Connect(function()
for i, closeEnemy in pairs(nearbyEnemies) do
if enemy == closeEnemy then
table.remove(nearbyEnemies, i)
end
end
end)
end
end
pirate.PrimaryPart:GetPropertyChangedSignal("CFrame"):Connect(function()
CheckTargets()
wait(0.1)
end)
Unit Spawn Script:
local replicatedStorage = game:GetService("ReplicatedStorage")
local spawnModule = require(game.ServerScriptService.SpawnModule)
local tower = script.Parent
while true do
spawnModule.SpawnUnit(tower.Name, tower.Configuration.Level.Value, tower.Configuration.UnitName.Value)
wait(0.1)
end
I’m really hoping I can find some way to fix this bug, as I would like to add more unit spawning towers to my game in the near future, however this has been a HUGE road block for me getting the opportunity to make any progress.
Edit: I am thinking there needs to be a way I can forcefully end the function, as maybe when trying to spawn the unit I need to make sure the function isn’t ongoing any longer. However, clearly what I have tried is not working at the moment.