Scripts skips for loop problem

Something weirds happening in my script. I’m trying to make a sell function for my towers so it will first loop through the tower and check what it’s wort and then destroy it, but if I don’t put a wait before the destroy which is placed after the loop then it errors:

local sellPrice = 0
	
	sellPrice += mainModule.Towers[tower.Name].Price
	
	for i,v in pairs(mainModule.Towers[tower.Name].Upgrades) do
		if tower.Upgrade.Value >= i then -- Upgrade is not a valid member of tower
			sellPrice += v.Price
		end
	end
	
	task.wait(5) -- when I put the wait it doesn't error
	
	tower:Destroy()

so it skips to the destroy part before finishing the loop, I printed it.

5 Likes

What is the full name of ‘tower’ that errors in the output

3 Likes

“GreenMan” is the full name of the tower

3 Likes

No in the actual console, the part in red it will look something like:
“Part “Workspace.Part””

3 Likes

This is the error: Upgrade is not a valid member of Model “GreenMan”

3 Likes

I am not encountering your problem when I replicate it
Is there anything else changing your tower code-wise

2 Likes

What is mainModule?

Is that a Module Script or an Instance like a folder?

2 Likes

Does this problem still persist if you instead guard (I forgot the actual term for it) the loop?

if tower.Upgrade.Value < i then break end
sellPrice += v.Price

Something else I’d try is if a simple frame skip (using RunService or task.wait() works as well

1 Like

Roblox code is serial which means it’s run in the order it has been written. That for loop should finish before the tower gets destroyed.

To debug this could you remove the wait and place a print there. Make the print say “Moved on from for loop” and then in the for loop add a print saying “Looping”.

If the output is still saying looping after “Moved on from for loop” then the problem could be quite advanced to solve.
If the "Moved on from for loop doesn’t print until after all the “Looping” ones have printed then the problem would be somewhere else in your code.

Send me a screenshot of the output once you’ve done this.

1 Like

I feel like we’re lacking relevant information. It would help if you send the entire script. It could be a simple loading issue, or that you’re holding a reference to an already destroyed instance

1 Like

It’s called a “Guard Clause” and it wouldn’t change anything here. Guard Clauses have the same function as writing:

if not value then 
 -- code here
end

But the reason for using them is to make your code neat and easy to work with:
No Guard Clause:

if not x then 
    if not y then 
       if not z then 
            -- code here
    end 
  end 
end

Guard Clause:

if not x then 
   return 
end 

if not y then 
   return 
end

if not z then 
   return 
end

-- code here

Both of these snippets of code work the exact same except the one with Guard Clauses looks neater and is easier to work with.

Also if you use a Guard Clause in a for loop you’d use “continue” rather than “break” since continue moves onto the next iteration of the loop whilst break would stop the entire loop so it wouldn’t keep looping which would result in that piece of code not working.

I hope this clears everything up :smiley:

1 Like

Thanks for the reminder, but break wouldn’t interrupt everything, though we don’t see anything

I’m mostly asking because I’m wondering when exactly does the :Destroy() happens

1 Like

Break would, since it would exit the for loop meaning that the piece of code to adjust the sell price would never run unless it is the first iteration of the loop.

It’s a fair statement but a Guard Clause would have no effect on it.

1 Like

A minor correction!

The conditions of guard clauses are not interchangeable with their counterpart if-statements. A guard clause is used in place of an if-statement when no code is intended to be executed beyond that if-statement, and is why return, break, and continue are involved.

Normal if-statements are focused on executing their bodies, while guard clauses are focused on abandoning further execution. This means a normal if-statement will have a positive condition, while a guard clause has a negative (inverse) condition:

if shouldntBeHapping then
    -- ...
end

Vs:

if isHappening then
    return
end

TL;DR:

if not x then
    if not y then

    end
end

Is actually equivalent to:

if x then
    return
end

if y then
    return
end
1 Like

Cheers for that! That’s a better way to look at it rather than how I wrote about it. :smiley:

1 Like

I don’t really know how I’m suposed to use that, but to be exact. I run through a module script with all the upgrade prices, the upgrades are called by numbers:

[1] = {Name = "First Upgrade",Price = 155,Damage = 2, Cooldown = 0.8,Range = 35},
[2] = {Name = "Test Upgrade",Price = 200,Damage = 3, Cooldown = 0.75,Range = 40},

In the tower/GreenMan, theres an intvalue of which upgrade the tower is at, so when I loop through I check at which upgrade the tower is at, but then I get the error that upgrade is not a valid member of GreenMan

This seems like an issue that is better resolved in a live context. Add me on Discord @Ziffix, and I’ll be happy to help you over a screen-shared VC. You can alternatively join the Roblox Studio Community server and ping me

I think I know the problem the remote event is fired multiple times at one click.

Maybe try to put;

repeat
    task.wait()
until tower

in replacement of the

(Don’t ctrl + c the script its not properly spaced.)