Phaser 3:更改 "Hitbox"/没有物理的 sprite 交互区域

Phaser 3: Change "Hitbox"/Interactive area of sprite without physics

我正在创建的游戏不需要任何物理,但是您可以通过使用 sprite.setInteractive({cursor: "pointer"});sprite.on('pointermove', function(activePointer) {...}); 和类似的方法将 over/clicking 悬停在精灵上时进行交互。但是我注意到两个问题:

  1. 精灵有一些区域是透明的。点击那些透明区域还是会触发交互功能,不太理想。

  2. 在播放精灵动画时,交互区域似乎并没有完全(根本没有?)改变,因此如果精灵在比前一个大的帧上结束,最终会变小我无法互动的区域。

我想到的一个选择是在我的 sprite 上创建一个多边形,它覆盖了我想要交互的区域。然而在我这样做之前,我只是想问一下是否有更简单的方法来解决这些问题。

这可能不是最好的解决方案,但我会这样解决这个问题。 (如果我不想用物理,如果对性能影响不大的话)

我会检查event-handler,如果在mouse-position像素是透明的左右,这比使用 bounding-boxes.

更准确,工作更少

You would have to do some minor calculations, but it should work well.

btw.: if the origin is not 0, you would would have to compensate in the calculations for this. (in , the origin offset is implemented)

这里是点击事件的演示:

let Scene = {
    preload ()
    {
        this.load.spritesheet('brawler', 'https://labs.phaser.io/assets/animations/brawler48x48.png', { frameWidth: 48, frameHeight: 48 });
    },
    create ()
    {
        // Animation set
        this.anims.create({
            key: 'walk',
            frames: this.anims.generateFrameNumbers('brawler', { frames: [ 0, 1, 2, 3 ] }),
            frameRate: 8,
            repeat: -1
        });
        
        // create sprite
        const cody = this.add.sprite(200, 100).setOrigin(0);
        cody.play('walk');
        cody.setInteractive();
        
        // just info text
        this.mytext =  this.add.text(10, 10, 'Click the Sprite, or close to it ...', { fontFamily: 'Arial' });

        // event to watch
        cody.on('pointerdown', function (pointer) {
            // calculate x,y position of the sprite to check
            let x = (pointer.x - cody.x) / (cody.displayWidth / cody.width)
            let y = (pointer.y - cody.y) / (cody.displayHeight / cody.height);
            
            // just checking if the properties are set
            if(cody.anims && cody.anims.currentFrame){
                let currentFrame = cody.anims.currentFrame;
                let pixelColor = this.textures.getPixel(x, y, currentFrame.textureKey, currentFrame.textureFrame);

                // alpha > 0 a visible pixel of the sprite, is clicked 
                if(pixelColor.a > 0) {
                    this.mytext.text = 'Hit';
                } else {
                    this.mytext.text = 'No Hit';
                }
                
                // just reset the textmessage
                setTimeout(_ => this.mytext.text = 'Click the Sprite, or close to it ...' , 1000);
            }
        }, this);
    }
};

const config = {
    type: Phaser.AUTO,
    width: 400,
    height: 200,
    scene: Scene
};

const game = new Phaser.Game(config);
<script src="https://cdn.jsdelivr.net/npm/phaser@3.55.2/dist/phaser.js"></script>

刚才自己也在努力寻找答案..

Think Make Pixel Perfect 就是您要找的东西。

this.add.sprite(x, y, key).setInteractive(this.input.makePixelPerfect());

https://newdocs.phaser.io/docs/3.54.0/focus/Phaser.Input.InputPlugin-makePixelPerfect