【问题标题】:Phaser Pixel Perfect collision for a mazePhaser Pixel 完美碰撞迷宫
【发布时间】:2022-10-14 23:03:05
【问题描述】:

我正在制作迷宫游戏,需要确保迷宫墙可以碰撞。对于如何做到这一点,我有两个想法:

  1. 制作单独的迷宫墙,将它们排列成我想要的迷宫形状,然后为每一个设置碰撞检测。

  2. 为整个迷宫的墙壁制作一个精灵,并使用像素完美碰撞来让游戏在墙壁之间进行,并且仍然被它们击中。

    由于我发现在游戏中设置静态精灵的 x 和 y 坐标的过程很繁琐,我真的希望不必使用第一种解决方案。但我以前从未真正用任何语言编写过像素完美碰撞,我正在努力寻找一个涵盖 Phaser 3 或一般理解的网站。有人可以提供一个例子吗?

【问题讨论】:

    标签: collision phaser-framework pixel-perfect


    【解决方案1】:

    最好的解决方案是使用tilemaptileset(s) 并使用(开源)工具Tiled(你甚至可以使用碰撞形状,而不是通常的盒子here an example)。
    顺便说一句,这种方法是我推荐的方法。

    但是为了让事情变得简单,并且没有额外的工具,一个选项是将移相器的 tilemap 与一个数组一起使用(这里是 some other examples ),在这里你只需要定义一个网格/地图(和至少一层),然后你就可以使用它来进行碰撞。唯一的问题是,如果您想在整个迷宫中使用单个大图像,则必须将碰撞的瓷砖与图像上的迷宫相匹配。

    此解决方案不是像素完美的,因为碰撞在拼贴中,但如果您需要更多细节,您可以使拼贴更小。(虽然您可以提高碰撞精度,但在collideoverlap 函数link to documentation 中)

    这里有一些演示代码:

    document.body.style = 'margin:0;';
    
    var config = {
        type: Phaser.AUTO,
        width: 400,
        height: 150,
        zoom: 1.25,
        scene: { create },
        banner: false
    }; 
    
    var level1 = [[1,1,1,1,1,1],
        [1,0,0,0,0,1],
        [1,1,1,0,0,1],
        [1,0,0,1,0,1],
        [1,0,0,0,0,1],
        [1,1,1,1,1,1]];
        
    var level2 = [[ 1,1,1,1,1,1,1,1,1,1,1,1 ],
        [ 1,1,1,1,1,1,1,1,1,1,1,1 ],
        [ 1,1,0,0,0,0,0,0,0,0,1,1 ],
        [ 1,1,0,0,0,0,0,0,0,0,1,1 ],
        [ 1,1,1,1,1,1,0,0,0,0,1,1 ],
        [ 1,1,1,1,1,1,0,0,0,0,1,1 ],
        [ 1,1,0,0,0,0,0,0,0,0,1,1 ],
        [ 1,1,0,0,0,0,0,0,0,0,1,1 ],
        [ 1,1,0,0,0,0,0,0,1,0,1,1 ],
        [ 1,1,0,0,0,0,0,0,0,0,1,1 ],
        [ 1,1,1,1,1,1,1,1,1,1,1,1 ],
        [ 1,1,1,1,1,1,1,1,1,1,1,1 ]];
        
    var level3 = [[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
        [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
        [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
        [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
        [1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1],
        [1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1],
        [1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1],
        [1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1],
        [1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1],
        [1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1],
        [1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1],
        [1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1],
        [1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1],
        [1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1],
        [1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1],
        [1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1],
        [1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1],
        [1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1],
        [1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,1],
        [1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1],
        [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
        [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
        [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
        [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]];
    
    function create () {
        
        this.add.text(10, 10, 'Tile size
    16 x 16').setFontSize('12px');
        this.add.text(150, 10, 'Tile size
    8 x 8').setFontSize('12px');
        this.add.text(290, 10, 'Tile size
    4 x 4').setFontSize('12px');
        
        // Just empty tileset so that it can be overlayed over a background image
        let g = this.make.graphics({x: 0, y: 0, add: false});
        g.generateTexture('empty-block', 16, 16);
    
        // When loading from an array, make sure to specify the tileWidth and tileHeight
        var map = this.make.tilemap({ data: level1, tileWidth: 16, tileHeight: 16 });
        var tiles = map.addTilesetImage('empty-block');
        var layer = map.createLayer(0, tiles, 10, 40);
    
        map.setCollision(1);
    
        // Just to visualize the collision Tiles
        var debugGraphics = this.add.graphics();
        map.renderDebug(debugGraphics);
        
        //Map with smaller tiles
        // When loading from an array, make sure to specify the tileWidth and tileHeight
        var map2 = this.make.tilemap({ data: level2, tileWidth: 8, tileHeight: 8 });
        var tiles2 = map2.addTilesetImage('empty-block');
        var layer2 = map2.createLayer(0, tiles2, 140, 0);
    
        map2.setCollision(1);
    
        // Just to visualize the collision Tiles
        map2.renderDebug(debugGraphics);
        
        //Map with much smaller tiles        
        // When loading from an array, make sure to specify the tileWidth and tileHeight
        var map3 = this.make.tilemap({ data: level3, tileWidth: 4, tileHeight: 4 });
        var tiles3 = map3.addTilesetImage('empty-block');
        var layer3 = map3.createLayer(0, tiles3, 140, 0);
    
        map3.setCollision(1);
    
        // Just to visualize the collision Tiles
        map3.renderDebug(debugGraphics);
    
    }
    
    new Phaser.Game(config);
    <script src="https://cdn.jsdelivr.net/npm/phaser@3.55.2/dist/phaser.min.js"></script>

    您可以使图块更小,并且可以使用图块定义碰撞大批或者CSV或者json或者...,太多的瓷砖可能会导致性能问题,所以不要让它们太小。

    【讨论】:

    • 这个解决方案看起来可行,但是关于 1 和 0 的数组,我需要多大才能制作 900 x 900 像素的地图?
    • @EmptyStone 这取决于碰撞的墙壁/物体应该有多大,以及玩家有多大。我个人会根据迷宫选择至少玩家大小或更大的图块大小(这样玩家可以轻松适应并且不会卡住)。我希望这有帮助。
    • @EmptyStone 如果我的回答有助于/解决您的问题,请考虑接受它,并带有绿色复选标记。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-30
    • 2014-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-03
    相关资源
    最近更新 更多