My "while loop" keeps on crashing the game

4.3 Godot Version

Question
` (Top Down 2d)
I have it so when I click this ball moves until it is off screen so to do that I tired to use a while loop.

func shoot():
while $VisibleOnScreenNotifier2D.is_on_screen() == true:
position.x += speed

as soon as I send out the shoot command and the ball is on screen the game crashes and im wondering
Why?
and how can I fix it?

1 Like

The notifier doesn’t update immediately, so this will just run forever

3 Likes

Edit: @athousandships above is correct of course. I just wanted to add some additional comments.

I presume you have simplified your question for the forum post (which is always a good idea) but here it looks like your shoot function is also doing your movement. This is not a good idea.

func shoot():
     # here you just need to instantiate your bullet and let it run

Your bullet (or ball or whatever) should have it’s own process function in which you do the movement. Then in that process function you can check to see if it is now off screen, and if it is, remove it. Something like this:

if not $VisibleOnScreenNotifier2D.is_on_screen():
        call_deferred("queue_free")

When using ‘while’ statements, you have to be very careful that it will not end up in an infinite loop, otherwise, as you have seen, the process will never end and the program will crash. This is a very common problem and why I would mostly avoid them (of course they have their uses but they can be dangerous if not implemented carefully).

At the very least you must always make sure the loop condition is updated within the loop body so it eventually becomes false to stop the loop.

3 Likes

Thank you so much for your help but I still don’t understand how to get the bullet to keep moving until it is off the screen.

You can use this code:

func shoot():
  while true:
    if not $VisibleOnScreenNotifier2D.is_on_screen(): break
    position.x += speed
1 Like

I’m trying this and it’s still crashing.

I think the problem is not with the loop. Can you share the error?

1 Like

Again, the visibility notifier doesn’t update immediately, the loop will never end, it needs a frame to draw to update

2 Likes

I reviewed these documents and realized that it is indeed the case, but do you have a way to use it?
I use this:

var speed = 30
var in_screen = false

func shoot():
	$VisibleOnScreenNotifier2D.screen_exited.connect(exited)
	in_screen = true

func _process(delta):
	if in_screen:
		position.x += speed * delta

func exited():
	in_screen = false
1 Like

I would be worried this will try to make a new connection every time you shoot. Perhaps you should move this connection to the _ready function.

1 Like

This works thank you so much.

Well, basically the code is called once and continues until it leaves the scene, so I prefer not to create a new function, and as long as each bullet is fired once, it makes sense and is fine.
But yes, if it is called a few times, it must be transmitted

1 Like