Is there such thing as a while loop? [SOLVED]

I’m trying to wait until a condition is met, in this case until all enemies have been defeated in a wave. This is my code:

while self.enemies_alive > 0 do
    -- rest of code goes here
end

I’ve used while loops before, more so in Luau (an altered version of Lua). That version requires you to use “wait()” to ensure the script doesn’t time out.

However, when i run this code, my game crashes. I can’t find anything else on the forum or on the internet regarding while loops in defold, so is it a real thing?

If it is, how do i ensure it doesn’t crash my game?

Many thanks!

A while loop like in your example will run until that condition is met, but it will not execute any other code than what you have inside the loop. This means that you will block the entire game engine from running any code. This is why the game crashes/hangs.

You need to restructure your code and check for this condition once per frame. You can perhaps use the life cycle functions to achieve this?


function init(self)
    -- add your game init code here
end

function update(self, dt)
    if self.enemies_alive > 0 then
        -- run code while enemies are alive here
    end
end

The question is how you decrease self.enemies_alive? Perhaps at the place where you decrease this value you can also check if you the new value is zero and then call some code to stop the game and run the code you wanted to put after your while-loop.

A kind of compromise I find myself using when the suggestions by britzl aren’t appropriate is to use a timer to check the condition periodically! It might be overkill to check every frame and more reasonable to check every second. (Of course the opposite is true too - it might be absolutely fine to check every frame!)

So I updated my code:

Code
function spawn_wave(self)
	while self.current_wave < self.max_waves do
		for i = 1,self.enemies_perwave do
			msg.post("#enemy", "spawn_enemy")
			self.total_enemies = self.total_enemies + 1
		end

		print(self.total_enemies,"is the total number of enemies")

		-- do some sort of loop that runs while enemies > 0

		timer.delay(1, true, function()
			if self.total_enemies == 0 then
				timer.cancel(handle))
			end
		end)

		print("the wave has been defeated")

	end
end

function on_message(self, message_id, message, sender)
	if message_id == hash("enemy_dead") then
		self.total_enemies = self.total_enemies - 1
	end
end

And the game still crashes. Should I still replace the main while loop with some sort of ‘timer’ utilization?

What is the error specifically?

There is no error in the output box, but the game freezes, goes unresponsive and crashes.

Are you sure this isn’t an infinite for loop?
You don’t increase the value of self.current_wave inside the loop, so it will just continue forever

1 Like

Dang okay, that was a very helpful reply. You’re right, I just needed to add:

self.current_wave = self.current_wave + 1

Thank you!

Although now I am faced with the issue of it not waiting until self.total_enemies == 0, as checked here:

waitthing = timer.delay(1, true, function()
	if self.total_enemies == 0 then
		timer.cancel(waitthing)
	end
end)

It just passes through it and loads ALL of the waves.

How can i make sure it waits until the wave is complete before making a new one?

You should not use ‘while’ and ‘timer’ together. Get rid of the while loop and just use the timer.
In your last code snippet the timer does nothing but checking if total enemies is zero.

So would the timer not wait until enemies = 0?

The timer in your code does indeed wait but you are not using it correctly.

waitthing = timer.delay(1, true, function()
  -- here goes the code you want to run on every tick,
  -- basically the while loop above but without the while :)
	if self.total_enemies == 0 then
		timer.cancel(waitthing)
	end
end)

Okay, so I put it into my code like so:

function spawn_wave(self) -- issue with this: it creates all the waves and doesnt wait until the wave is complete

	waitthing = timer.delay(1, true, function()
		for i = 1,self.enemies_perwave do -- make it so the maximum number of total_enemies is 5
			msg.post("#enemy", "spawn_enemy")
			self.total_enemies = self.total_enemies + 1
		end

		self.current_wave = self.current_wave + 1
		print(self.total_enemies,"is the total number of enemies")

		-- do some sort of loop that runs while enemies > 0
		if self.total_enemies == 0 then
			timer.cancel(waitthing)
		end
	end)
end

Now my problem is that it doesn’t wait for the wave to be over before looping again.

How would I implement this? Do I need to put an ‘else’ and force it to wait?

Sorry , i have just noticed that I have written complete nonsense, was too hasty and totally out of context. :blush: better answer incoming


For anyone wondering where my answer is:
He shared the project with me and i ended up refactoring his whole script to have a working wave system.

2 Likes