> Faqs > Cómo veo y modifico las colisiones con el framework Javascript Phaser

Cómo veo y modifico las colisiones con el framework Javascript Phaser

Estoy desarrollando un juego con el framework Javascript Phaser.

¿Es posible reducir el área donde le puede afectar una colisión, para que no incluya toda una imagen o sprite?

Lo que pasa es que las colisiones del esqueleto y el caballero son muy grandes y quiero modificarlas para que no sean tan grandes y que parezcan más creibles.

export class Game extends Phaser.Scene {
    constructor() {
        super({key:'game'});
    };

    preload() {
        this.load.image("background","imagenes/Legacy-Fantasy - High Forest 2.3/Background/Background.png");
        this.load.image("mapa","Fondos/mapa.png");
        this.load.image("mapa_2","Fondos/map.png");
        this.load.spritesheet("caballero_Idle","caballero/Colour2/NoOutline/120x80_PNGSheets/_Idle.png",{ frameWidth: 120, frameHeight: 80 });
        this.load.spritesheet("esqueleto","Skeleton/Sprite Sheets/Skeleton Idle.png",{frameWidth: 24, frameHeight: 30});

    };

    create() {
        //Colisiones del mundo
        this.physics.world.setBoundsCollision(true, true, true, false);

        //Fondo
        this.background = this.physics.add.image(window.innerWidth / 2, window.innerHeight / 2, "background");
        this.background.setScale(window.innerWidth / this.background.width, window.innerHeight / this.background.height);
        this.background.body.allowGravity = false;

        this.mapa_2 = this.physics.add.image(250,800,"mapa_2").setImmovable();
        this.mapa_2.body.allowGravity = false;

        this.mapa = this.physics.add.image(window.innerWidth/2,800,"mapa").setImmovable();
        this.mapa.setScale(window.innerWidth/this.mapa.width)
        this.mapa.body.allowGravity = false;
        this.mapa.body.collider = true;

        //Plataformas

        console.log("Por ahora no tengo plataformas");

        //Personajes

        this.caballero_Idle = this.physics.add.sprite(400,340,"caballero_Idle");
        //this.caballero_Idle.body.allowGravity = false;

        this.esqueleto = this.physics.add.sprite(450,340,"esqueleto");
        this.esqueleto.body.allowGravity = false;

        //Animaciones

        this.anims.create({
            key: 'caballero_Idle',
            frames: this.anims.generateFrameNumbers('caballero_Idle', { start: 0, end: 7 }),
            frameRate: 10,
            repeat: -1,
            yoyo: true,
        });

        this.anims.create({
            key: "esqueleto",
            frames: this.anims.generateFrameNumbers("esqueleto",{start: 0, end: 7}),
            frameRate: 10,
            repeat: -1,
            yoyo: true,
        });

        this.caballero_Idle.anims.play('caballero_Idle');

        this.esqueleto.anims.play("esqueleto");

        //colisiones
        this.background.setCollideWorldBounds(true);
        this.mapa.setCollideWorldBounds(true);
        this.mapa_2.setCollideWorldBounds(true);
        this.caballero_Idle.setCollideWorldBounds(true);
        this.esqueleto.setCollideWorldBounds(true);

        this.background.setBounce(0);
        this.mapa.setBounce(0);
        this.mapa_2.setBounce(0);
        this.caballero_Idle.setBounce(0);
        this.esqueleto.setBounce(0);

        this.physics.add.collider(this.esqueleto,this.caballero_Idle);
        this.physics.add.collider(this.esqueleto,this.mapa);
        this.physics.add.collider(this.caballero_Idle,this.mapa);
        this.physics.add.collider(this.caballero_Idle,this.mapa_2);

        //Controles

        this.cursor = this.input.keyboard.createCursorKeys();

    };

    update(){
        if(this.cursor.left.isDown){
            this.caballero_Idle.setVelocityX(-500);
        }else if(this.cursor.right.isDown){
            this.caballero_Idle.setVelocityX(500);
        }else if(this.cursor.up.isDown){
            this.caballero_Idle.setVelocityY(-200);
        }else{
            this.caballero_Idle.setVelocityX(0);
        };

        this.physics.moveToObject(this.esqueleto, this.caballero_Idle, 100);

    };

};

Respuestas

Es posible reducir el área donde le puede afectar una colisión en el framework JavaScript Phaser, ya que es posible ajustar el tamaño y la posición del "hitbox" o caja de colisión del objeto. En Phaser, la caja de colisión no tiene que coincidir exactamente con las dimensiones de la imagen del objeto. Puedes definir un área más pequeña dentro de la imagen, para conseguir ese ajuste del área donde se detectarán las colisiones.

Aquí hay algunas formas de hacerlo:

Ajustar el Tamaño del Hitbox: Puedes cambiar el tamaño del hitbox de un sprite para que sea más pequeño que la imagen del sprite. Esto se puede hacer usando el método setSize() qe tienes en el objeto sprite.

Posicionar el Hitbox: También puedes posicionarlo, incluso después de cambiar el tamaño. Para reposicionar el hitbox dentro de la imagen del sprite puedes usar el método setOffset().

Incluso puedes usar Formas de Colisión Personalizadas: Para situaciones más complejas, donde un rectángulo no es suficiente. En esos casos se podría utilizar polígonos para definir formas de colisión más precisas. Phaser soporta colisiones basadas en polígonos a través de herramientas como PhysicsEditor.

Aquí tienes un ejemplo básico de cómo ajustar el tamaño y la posición del hitbox de un sprite:

// En este ejemplo 'sprite' sería tu objeto de sprites
sprite.setSize(nuevoAncho, nuevoAlto); // Define el tamaño del hitbox
sprite.setOffset(desplazamientoX, desplazamientoY); // Posiciona el hitbox dentro del sprite

Este código reduce el área de colisión a un rectángulo especificado por nuevoAncho y nuevoAlto, y luego lo posiciona dentro del sprite usando los desplazamientos desplazamientoX y desplazamientoY.

Espero que te sirva así... si no pueeds buscar otros polígonos.

Depuración de las colisiones

Ahora, para la parte de tu pregunta sobre ver el espacio que ocupa el área de la colisión... también es posible conseguirlo en Phaser, ya que proporciona una forma de visualizar las áreas de colisión. Lo puedes usar la depuración.

Esto se hace generalmente en la función de actualización (update) o en una función de renderizado específica.

Puedes probar con un código como este para hacer visible área de colisión de un sprite en Phaser 3:

function update() {
    // Dibujar un rectángulo de depuración alrededor del hitbox del sprite
    var graphics = this.add.graphics();
    graphics.clear(); // Limpia el gráfico si ya se dibujó en el último frame
    graphics.lineStyle(2, 0xff0000, 1); // Establece el color y el grosor de la línea

    // Dibuja un rectángulo basado en el tamaño y posición del hitbox del sprite
    graphics.strokeRect(
        sprite.x - sprite.body.offset.x,
        sprite.y - sprite.body.offset.y,
        sprite.body.width,
        sprite.body.height
    );
}

En este código, sprite es el objeto cuya área de colisión quieres visualizar. Se dibuja un rectángulo rojo alrededor del hitbox del sprite para que puedas ver claramente sus límites.

  • graphics.lineStyle(2, 0xff0000, 1) configura el rectángulo con un borde rojo y un grosor de 2 píxeles.
  • graphics.strokeRect() dibuja el rectángulo alrededor del hitbox del sprite.

Si estás utilizando un sistema de física como Arcade, también hay herramientas de depuración específicas para ese sistema, como this.physics.world.createDebugGraphic, que pueden proporcionar más detalles.

Espero que lo puedas adaptar a tu ejemplo concreto.

Miguel Angel
3145 140 209 17
Gracias, esto me ayuda un montón.