Can I get some help connecting 2D game levels via KinematicObject crossing a "goal" using signals?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By kayfleisch

Alright. First time working in Godot. I’ve tried solving this via tutorials and docs, previous posts but nothing is working. Working on making a simple game to learn the process. It’s all in 2D.

The game: KinematicBody2D (player controls) try’s to knock a ball (KinematicBody2D, not controlled) into a goal. The goal is created by making a gap in the walls, so only a small part of the rectangular arena allows the ball to pass through, there is art to show the entrance of the goal, but the actual Area2D box representing the goal is not in the scene. I want to use a signal to connect the action of passing through the goal to initiate the next level.

What I’ve tried (and not succeeded with):
I made a Sprite with Area2D I titled Hitbox, and a CollisionShape as children of the Sprite. I placed the shapes at the line between goal and arena.

Here is my script:

extends Sprite

func on_Hitbox_body_entered(body) → void:
if body.is_in_group(“ObjectGroup”):
" + str(int(get_tree() + 1) + “.tscn”)

I have the ball titled Object and in a group called ObjectGroup
I have all the Levels titled Level_1, Level_2,Level_3, etc (I got this idea for the level change from a youtube video)

I’ve also tried the following script

extends Sprite

func on_hitbox_area_entered(area: Area2D) → void:
if area.is_in_group(“Object”):
" + str(int(get_tree() + 1) + “.tscn”)

When I run the project, the ball goes through the goal, but the level does not change. I have the signal connecting the Hitbox to the Sprite, and I’ve loaded the above scripts into the sprite. I have the sprite in each scene, connected to the Node at the base of the level.

Happy to provide more info, I hope I provided enough. I’m very new to this, assume I don’t know/understand. Thank you in advance!

:bust_in_silhouette: Reply From: PunchablePlushie

If your ball is a kinematic body, then area_entered signal won’t get triggered because that signal is for other areas only. You should keep using body_entered.

the ball goes through the goal, but the level does not change

To me, it seems like either the signal is not being emitted, or the condition (is_in_group) is not true. Make sure that the signal and the condition are working properly using print().
So you can try something like this:

extends Sprite

func _on_Hitbox_body_entered(body) -> void:
  print("Signal Triggered!")
  if body.is_in_group("ObjectGroup"):
      print("Condition Passed!")
      get_tree().change_scene("res://Level" + str(int(get_tree() + 1) + ".tscn")

You can also use assert to check if the condition returns true or not, however that’ll pause the execution if the condition happens to return false.


Hopefully that’ll give you a better idea of what the issue is.

If the issue is with the signal:

  • Make sure you’re using the correct signal (body_entered).
  • Make sure the signal is connected properly (you should see a green signal icon to the left side of the method).
  • Check the collision layer/mask of both the goal area and the ball body.
    Here’s a short 10min video by GDQuest about layers and masks, if you’re not familiar with them.

If the issue is with the condition, you can either double check your groups and make sure that everything is set up properly or instead of checking the group, check the class.
To do that, load/preload your ball script into a variable or constant. Then use is to check if body extends the ball script:

extends Sprite

const Ball = preload("")

func _on_Hitbox_body_entered(body) -> void:
  print("Signal Triggered!")
  if body is Ball:
      print("Condition Passed!")
      get_tree().change_scene("res://Level" + str(int(get_tree() + 1) + ".tscn")

Alternatively, you can use the class_name keyword in your ball script if you don’t want to load it into a variable first.

extends KinematicBody2D
class_name Ball

However, that’ll make become available when adding new nodes to the scene because class_name adds the script as a new type to the editor.