Josephbrad1234
Josephbrad1234

Reputation: 11

Godot - Game freezes when Area2D Monitoring turned on

So when my player falls off the map, I want the level to reload. I have used an area2d with a collisionshape2d to create an area that will call a function when the player collides with this area. However, when the game is run with this code included, the player will animate through a few frames then the game completely freezes before I can even move the player.

func _on_Area2D_body_entered(body):
   get_tree().reload_current_scene()

If I delete this code, or set monitoring to off, and re-run the game it will not freeze.

Below is a screenshot of my level design.

Level design

Any help would be greatly appreciated :) - Is this a bug or am I doing something stupid?

When I set a breakpoint on the get_tree().reload_current_scene() line the following report shows

debugger

does this mean the player is colliding with a tile - If this is the case I don't see how as the program freezes before the player touches the ground.

Upvotes: 1

Views: 319

Answers (1)

Theraot
Theraot

Reputation: 40220

As I said in the comments, this line:

get_tree().reload_current_scene()

Returns a value.

Now, you have said that 0 is "continuously outputted". In this context 0 means OK, in other words: it was able to reload the scene. The problem is the "continuously" part. It means that the scene reloads and then this code is triggered, and then it reloads again, and then this code is triggered again, and so on.

Now, apparently the Area2D is colliding with the TileMap. That makes sense. If it is a collision between the Area2D and a tile upon loading the scene, you would get the observed behavior. And the way the Area2D and TileMap are positioned in the scene supports the idea.


And about fixing it. I'll give you three solutions, either of these will work, with their drawbacks and caveats:

  • Don't have the Area2D positioned in a way that intersects non-passable tiles. This is easy to do by moving the Area2D further down, or by removing any tiles that overlap it.

    The drawback with this approach is that it is fragile. You may forget in the future and move the Area2D or add tiles or something else that make the problem return. Also, it might not work well with your intended scenario design.

  • Change the collision_mask and collision_layer in such way that the tiles and the Area2D do not collide. As long as the bits from the mask do not overlap the bits from the layer of the other and viceversa, Godot will not even check for a collision between them.

    The main drawback with this approach is that you have limited number of layers.

    There is also the fact that it is less intuitive that simply placing things in such a way they don't collide.

    To make it easier to work with, assign layers to different kinds of things… Go to your Project Settings, on the General Tab, under Layer Names, and 2D Physics, and give them names (e.g. "environment", "enemies", "enemy bullets", "player", "player bullets", "items", "others").

    Then you can assign to each object on collision_layer what they are, and on collision_mask set every thing they MUST collide with. With the caveat that Godot will check both ways.

    In this case you would set the collision_layer of the player character physics object (the KinematicBody2D) to "player" (or similar), and put the collision_mask of the Area2D to the same, so they collide. Have the collision_layer of the TileMap set to something else (e.g. "environment") that is not in the collision_mask of the Area2D, so the Area2D and the TileMap do not collide. And set the collision_mask of the player character to something that include the layer you set to the TileMap, so the player character also collides with it. I hope that makes sense.

  • And, of course, you can filter on the Area2D, with a little of code. It can be checking the class, or node group, or the name of the physics body. For example you can insert at the start of the method something like this: if body.name != "player": return. So that it exits the method before it reaches reload_current_scene unless it is the correct physics body.

    The drawback with this approach is that it is still checking and registering the collision, so it has worse performance that using collision_mask and collision_layer. But it will work, and it will perform OK for a small to mid sized game.

For more complex situations, you may employ a combination of these approaches (because, as I said, there is a limited number of layers, so you need to add filtering on top of it). I have a more detailed explanation of how to setup physics objects, including the techniques mentioned here, in another answer.

Upvotes: 2

Related Questions