Search code examples
pythongame-developmentgodotgdscript

Godot: CharacterBody2D or Area2D for an object that needs collision AND to queue_free?


I'm working on the game Breakout which is a game similar to Pong where a ball bounces off a paddle and you have to aim in order to hit a brick. When you hit the brick you score a point and the brick disappears. Each of my bricks is an Area2D because I need access to the on_body_entered signal.

extends Area2D

func _on_body_entered(body):
    score += 1
    queue_free() 

When the ball hits the brick that scripts run which is exactly what I want to happen. The problem with this is the block simply disappears upon being hit and the ball keeps going straight through it. I'm trying to implement proper collision so when the brick disappears, the ball bounces off it, similar to the bounce when the ball hits the paddle (which is a CharacterBody2D).

The ball is also a CharacterBody2D

extends CharacterBody2D

var speed: int = 6

func _ready():
    var target_position = Vector2(575, 645)
    var direction = global_position.direction_to(target_position)
    velocity = direction.normalized() * speed

func _physics_process(delta):
    var collision = move_and_collide(velocity)
    
    if collision != null:
        velocity = velocity.bounce(collision.get_normal())

Based on this information, how can I implement proper logic on the brick to get the ball to bounce off it as it disappears?


Solution

  • The queue free is not the problem. move_and_collide does simply not detect collisions with areas.

    To keep your ball logic the same I would do the same as described in the docs here :

    Change your Brick from an Area2D to an StaticBody2D. Change your _on_body_entered method into a simple hit method:

    func hit():
        score += 1
        queue_free() 
    

    Since the ball already detects collisions, he also is able to interact with the object he is colliding with. To do this you get the collider from the collision object and check, of it has a a method called "hit". If the object does have the function, call it after you changed your direction:

    func _physics_process(delta):
        var collision = move_and_collide(velocity)
    
        if collision:
            velocity = velocity.bounce(collision.get_normal())
            if collision.get_collider().has_method("hit"):
                collision.get_collider().hit() 
    

    Now your Brick has the same behaviour as your paddle when colliding with the ball, but also gets freed after the collision, because it has a hit function, the ball can call.