Connecting signals between multiple dynamically created entities to detect collisions between physics bodies

Godot Version

4

Question

Hi there,

I’m trying to recreate an old iOS game I used to play using Godot and I’m running into some issues. I think most likely it’s how I’ve organised my scenes that is causing the issues but I would like some help.

I have a “main” scene. This contains a child scene that is called “player” located on the far right of the viewport. When a user clicks on the screen the player rotates a “ball” around a center point, when the mouse is released I instantiate a new scene called "“projectile” at the position of the ball and it shoots off in the direction of the rotation. This is created in the “player” script. This projectile is a characterbody2D, but movement is all handled via code. It uses move_and_bounce to bounce off of “walls” that are in my main scene. I only ever allow one projectile, so clicking and releasing removes any existing projectile from the scene. This works ok.

In my “main” scene, I also have a script attached to it called “main” this script makes use of a timer and instantiates a “block” every second. These blocks are rigidbody2Ds and move horizontally across the screen (gravity is disabled). They move at a constant “linear_velocity” and again make use of move_and_collide so I can detect if they get passed the “player” by hitting a hidden area. This collision detection works fine so I know if I’m in a game over state.

The issue I have is that I need the “block” that is dynamically created in the “main” script to signal if it has collided with the “projectile” that is created via the “player” script which itself is a child of the “main” script. Is there a way to do this? Have I set my scene hierarchy up in the wrong way? Or is my choice of physics bodies wrong? Ultimately I want to be able to have my blocks also “bounce” off each other and have collisions with projectiles alter their trajectory and slowly explode them (giving a chance for the player to try and cleverly smash blocks into other blocks)

I can obviously provide more code, but I’m new to this and most of it is making use of built in collision detection signals.

Thanks

Could you post the collision code for the gameover? I would filter your collisions by name, especially since there is only one player and one ball the names shouldn’t get jumbled up by Godot.

In the block’s script, check collisions with a if statement by the collider’s name.

func _on_body_entered(body: Node2D) -> void:
    if body.name == "Player":
        game_over.emit()
    elif body.name == "Ball":
        score_point.emit()
        self.queue_free()

Hey,

Thanks for replying. The game over state works. fine, it’s the collision between the ball and block that isn’t working and as I say both Nodes are created dynamically but in different scripts.

This is the code in my block, but the _on_body_entered never fires (the signal is wired up in the inspector:

extends RigidBody2D

func _on_body_entered(body: Node) -> void:
	print("body entered")

I propose putting the script I posted onto the block’s scene, that way it handles game over or being hit. If you want to keep the game over script elsewhere then you only need the condition for “Ball”. Maybe you have contact monitoring disabled?

Emitted when a collision with another PhysicsBody2D or TileMap occurs. Requires contact_monitor to be set to true and max_contacts_reported to be set high enough to detect all the collisions. TileMaps are detected if the TileSet has Collision Shape2Ds.

body the Node, if it exists in the tree, of the other PhysicsBody2D or TileMap.

from: RigidBody2D — Godot Engine (stable) documentation in English

The game over script exists in my “main” scene, I actually have a shape2D in that scene behind the “player” which is what the block collides with to determine game over

func _on_death_zone_area_2d_body_shape_entered(body_rid: RID, body: Node2D, body_shape_index: int, local_shape_index: int) -> void:

	if(body.is_in_group("Projectile")):
		body.queue_free()
	if(body.is_in_group("Blocks")):
		#end game
		body.queue_free()

However I’ve just played with the contact monitoring you mentioned and I’m now seeing my signal firing. I wasn’t aware of that property!

Thanks very much for your help

1 Like

Super! and groups are much better than comparing names; thank you for showing the end result!