0

Goal

I'm trying to create a 2D horizontal space shooter in Godot. I've used a CharacterBody2D node for the player, a RigidBody2D node for the asteroids that the player has to dodge and a plain Node for the main scene. My goal is to lower the player's HP when an asteroid collides against the player.

Idea

Given that I'd like to not make the asteroid disappear after the collision, I've chosen to use a RigidBody2D for the asteroid after I found out that there's a signal that detects if the RigidBody2D collides with another PhysicsBody2D: it's name is body_entered(). According to the documentation, the conditions to make this signal work is that the property contact_monitor has to be set to true and that the property max_contacts_reported has to be set high enough to detect all collisions. And so I did it (I set max_contacts_reported to 10, just to be sure that at least 1 collision would be detected). Then I connected the signal to the same RigidBody2D and I put a print statement to see if the signal would work. Then, I set the Player's layer to 1 and its mask to 2, and viceversa with the Asteroid's layer and mask.

The Problem

When I ran the code, collisions between the player and the asteroids happened, but no output has ever appeared. That makes me think that the signal itself is not working, but I can't figure out what's the issue.

I set the property contact_monitor to true and max_contacts_reported to 10 from the inspector of the RigidBody2D (aka the asteroid)

I expected that the RigidBody2D's signal _on_body_entered(body) would print a statement in the console output whenever a collision between the player and an asteroid happens. However, this doesn't happens, despite collisions actually happen (the player is able to stop the movement of the asteroids by blocking their path and can rotate them by touching them in certain angles)!

I found on StackOverflow an answer about the body_entered() signal's using of a RigidBody2D, but I already followed its instructions with no success. Here's the link: text

I'll paste the code of the three nodes below. Thank you in advance!

CharacterBody2D' code

extends CharacterBody2D


@export var speed = 400
@export var health = 100
var screen_size

func _ready():
    screen_size = get_viewport_rect().size
    
#This is an idea of the function that will lower the player's health. 
func hit(value: float):
    health -= value
    print("+++This is your new health: " + str(health) + "+++")

#Register the inputs of the user and converts them in a 2 dimensional vector. Then, it multiplies the vector with the player's speed and it register this result as the velocity of the player. At the end, it clamps the player position inside the viewport.
func _physics_process(_delta):
    var input_direction = Input.get_vector("move_left", "move_right", "move_up", "move_down")
    velocity = input_direction * speed
    move_and_slide()
    position = position.clamp(Vector2.ZERO, screen_size)
    

RigidBody2D's code

extends RigidBody2D

@export var min_speed = -200
@export var max_speed = -500
var speed
var screen_size
var start_pos

# Called when the node enters the scene tree for the first time.
func _ready():
    screen_size = get_viewport_rect().size
    speed = Vector2(randi_range(min_speed, max_speed), 0) #Chooses a random speed between the min_speed and the max_speed. The values are negative because the asteroids will move from right to left. 
    start_pos = Vector2(screen_size.x + 15, (randi_range(1, screen_size.y - 1))) #Chooses a random Y position outside of the viewport, so that any asteroids will suddenly appear in the game window. 
    position = start_pos
    show()

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _integrate_forces(_delta):
    linear_velocity = speed 

#When the asteroid leaves the viewport, it will destroy itself. This signal actually works!
func _on_visible_on_screen_notifier_2d_screen_exited():
        queue_free()

#This is the infamous signal that isn't working! No idea about why it doesn't work... 
func _on_body_entered(body):
    print("The signal is working!")

Main Node's code

extends Node

#I store the asteroid scene inside this PackedScene (the setting is only visible from the inspector of the Main Node)
@export var asteroid_scene: PackedScene

# Called when the node enters the scene tree for the first time.
func _ready():
    $AsteroidTimer.start() #This timer is not "one shot"

#Every time that the timer goes in timeout, an asteroid scene will be instantiated from the PackedScene and will become a child of the Main Node. 
func _on_asteroid_timer_timeout():
    var asteroid = asteroid_scene.instantiate()
    add_child(asteroid)

feather
  • 1
  • 1

0 Answers0