使用pixi.js开发小游戏须要注意的5个地方

这两天用pixi开发了一款小游戏,属于射击游戏范畴。开局很简单,上来玩就是了。javascript

demo.gif

但其实须要注意的事项也很多。下面简单总结一下,有5点须要注意的地方,若是不注意,容易出现错误,或致使chrome崩溃。html

1、使用 requestAnimationFrame 代替定时器java

requestAnimationFrame比定时器更平滑,同时在性能上也更稳定。jquery

requestAnimationFrame(update);
function update(){
    //对 Sprite 的一些操做
    requestAnimationFrame(update);
}

2、碰撞检测用bumpgit

因为pixi本身并无碰撞检测库,因此不少人须要本身写。但本身写不免会出现问题。而bump是一个很成熟的碰撞检测库。github

对于一些并不是方形(边角是空白的精灵)元素的碰撞,能够采用hitTestCircle函数:chrome

if (b.hitTestCircle(SpriteA, SpriteB, true)) {
    //这里是发生碰撞后的代码
}

但须要在精灵上面定义circular属性为truecanvas

player.circular = true;

3、每隔一段时间出现一架敌机数组

不要使用定时器,而是要在requestAnimationFrame的update中,用一个自增的值来作判断:app

//每隔一段时间,增长一个敌机
time++;
if (time >= 100) {
    //建立一个新的敌机
    time = 0;
}

这样能够避免定时器形成的性能消耗。

4、在精灵对象上设置时间属性,实现定时开火

flyobj = new PIXI.Sprite(flyobjTexture);
flyobj.width = 50;
flyobj.height = 50;
flyobj.position.x = r(0, 512);
flyobj.position.y = 0;
flyobj.circular = true;
flyobj.time=0;//用来计算时间,进行开火
flyobjs.addChild(flyobj);

相应地,在循环敌机精灵群的时候,也会对这个时间属性进行自增,经过数值来增长发射炮弹的效果:

//遍历敌机
flyobjs.children.forEach(flyobj = >{
    flyobj.position.y += 2;
    flyobj.time += 1;
    if (flyobj.time >= 60) {
        //开火
        obj = new PIXI.Sprite(objTexture);
        obj.width = 20;
        obj.height = 20;
        obj.position.x = flyobj.position.x + flyobj.width / 2 - obj.width / 2;
        obj.position.y = flyobj.position.y + flyobj.height;
        obj.circular = true;
        objs.addChild(obj);
        flyobj.time = 1;
    }
    if (flyobj.position.y >= 500) {
        flyobjs.removeChild(flyobj);
    }
    //碰撞检测
    if (b.hitTestCircle(flyobj, player, true)) {
        setTimeout(() = >{
            loop = false;
            gameover();
        },
        100);
    }
});

5、被消灭的敌机、超出画布边界的精灵、由于碰撞消失的精灵,只要从Container中移除就能够了。

flyobjs.children.forEach(flyobj = >{
    if (b.hitTestCircle(flyobj, bullet, true)) {
        bullets.removeChild(bullet);
        flyobjs.removeChild(flyobj);

        //消灭的敌机+1
        number += 1;
        numberText.text = number;
    }
});

最后放上所有代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../pixi.min.js"></script>
    <script src="../bump.js"></script>
    <script src="../jquery-3.5.1.js"></script>
    
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        .box {
            margin: 0 auto;
            width: 500px;
            height: 500px;
            position: relative;
            text-align: center;
        }
        #gameover{
            display: none;
        }
        .flex{
            position: absolute;
            width:100%;
            height: 100%;
            display: flex;
            flex-flow: column;
            justify-content: center;
        }
        h1{
            color:#fff;
        }
        button{
            width:200px;
            height:40px;
            border-radius: 10px;
            margin:10px auto;
        }
    </style>
</head>
<body onload="init();">
    <div id="box" class="box">
        <div id="gameover">
            <div class="flex">
                <h1>GAME OVER</h1>
                <button id="restart">restart</button>
            </div>
        </div>
    </div>
</body>
    <script type="text/javascript">
        function keyboard(keyCode) {
            let key = {};
            key.code = keyCode;
            key.isDown = false;
            key.isUp = true;
            key.press = undefined;
            key.release = undefined;
            //The `downHandler`
            key.downHandler = event => {
                if (event.keyCode === key.code) {
                    if (key.isUp && key.press) key.press();
                    key.isDown = true;
                    key.isUp = false;
                }
                event.preventDefault();
            };
            //The `upHandler`
            key.upHandler = event => {
                if (event.keyCode === key.code) {
                    if (key.isDown && key.release) key.release();
                    key.isDown = false;
                    key.isUp = true;
                }
                event.preventDefault();
            };
            //Attach event listeners
            window.addEventListener(
                "keydown", key.downHandler.bind(key), false
            );
            window.addEventListener(
                "keyup", key.upHandler.bind(key), false
            );
            return key;
        }
        function init() {
            let type = "WebGL"
            if (!PIXI.utils.isWebGLSupported()) {
                type = "canvas"
            }
            
            //碰撞检测的
            b = new Bump(PIXI);
            
            PIXI.utils.sayHello(type);
            app = new PIXI.Application({
                width: 500,         // default: 800
                height: 500,        // default: 600
                antialias: true,    // default: false
                transparent: false, // default: false
                resolution: 1       // default: 1
            });
            app.renderer.backgroundColor = 0x061639;
            document.getElementById('box').appendChild(app.view);
            PIXI.loader
                .add([
                    "../images/player.png",
                    "../images/flyobj.png",
                    "../images/bullet.png",
                    "../images/obj.png"
                ])
                .on("progress", loadProgressHandler)
                .load(setup);
            function loadProgressHandler(loader, resource) {
                console.log("loading: " + resource.url);
                console.log("progress: " + loader.progress + "%");
            }
            function setup() {
                console.log("All files loaded");
                var playerTexture = PIXI.Texture.from("../images/player.png");                
                player = new PIXI.Sprite(playerTexture);
                player.circular = true;
                player.width = 50;
                player.height = 70;
                player.position.x = 512 / 2;
                player.position.y = 512 / 2;
                player.vx = 0;
                player.vy = 0;
                
                //消灭多少个敌机
                const style = new PIXI.TextStyle({
                    fontSize: 20,
                    fill: "white"
                });
                numberText = new PIXI.Text('0',style);
                numberText.position.x = 30;
                numberText.position.y = 30;
                app.stage.addChild(numberText);
                
                
                //敌机资源
                flyobjTexture = PIXI.Texture.from("../images/flyobj.png");
                //敌机数组
                flyobjs = new PIXI.Container();
                app.stage.addChild(flyobjs);
                
                
                //子弹资源
                bulletTexture = PIXI.Texture.from("../images/bullet.png");
                //子弹数组
                bullets = new PIXI.Container();
                app.stage.addChild(bullets);
                
                
                //敌机子弹资源
                objTexture = PIXI.Texture.from("../images/obj.png");
                //敌机子弹数组
                objs = new PIXI.Container();
                app.stage.addChild(objs);
                
                app.stage.addChild(player);
                //键盘事件
                var left = keyboard(37);
                var up = keyboard(38);
                var right = keyboard(39);
                var down = keyboard(40);
                //空格,开火
                var space = keyboard(32);
                space.press =()=>{
                    bullet = new PIXI.Sprite(bulletTexture);
                    bullet.width = 6;
                    bullet.height = 10;
                    bullet.position.x = player.position.x+player.width/2-bullet.width/2;
                    bullet.position.y = player.position.y;
                    bullet.circular = true;
                    bullets.addChild(bullet);
                }
                
                left.press = () => {
                    player.vx = -4;
                    player.vy = 0;
                };
                left.release = () => {
                    player.vx = 0;
                    player.vy = 0;
                };

                right.press = () => {
                    player.vx = 4;
                    player.vy = 0;
                };
                right.release = () => {
                    player.vx = 0;
                    player.vy = 0;
                };

                up.press = () => {
                    player.vx = 0;
                    player.vy = -4;
                };
                up.release = () => {
                    player.vx = 0;
                    player.vy = 0;
                };

                down.press = () => {
                    player.vx = 0;
                    player.vy = 4;
                };
                down.release = () => {
                    player.vx = 0;
                    player.vy = 0;
                };
                
                restart();
                
                requestAnimationFrame(update);
            }
            
            function r(min, max) {
                return Math.floor(Math.random() * (max - min)) + min
            }
            
            function gameover(){
                $('#gameover').show();
            }
            
            function restart(){
                //消灭的敌机数量
                number=0;
                numberText.text=number;
                
                //建立敌机的time
                create_flyobj_time=0;
                //loop 控制游戏是否进行的全局
                loop=true;
                player.position.x=500/2-player.width/2;
                player.position.y=500-player.height;
                
                flyobjs.children=[];
                objs.children=[];
                bullets.children=[];
                loop=true;
                $('#gameover').hide();
            }
            
            function update() {
                console.log(flyobjs.children.length,objs.children.length,bullets.children.length)
                if(loop){
                    player.position.x += player.vx;
                    player.position.y += player.vy;

                    //避免超出画布
                    if(player.position.x<=0){
                       player.position.x=0;
                    }
                    if(player.position.x>=500-player.width){
                       player.position.x=500-player.width;
                    }
                    if(player.position.y<=0){
                       player.position.y=0;
                    }
                    if(player.position.y>=500-player.height){
                       player.position.y=500-player.height;
                    }

                    //遍历敌机
                    flyobjs.children.forEach(flyobj => {
                        flyobj.position.y += 2;
                        flyobj.time+=1;
                        if(flyobj.time>=60){
                            //开火
                            obj = new PIXI.Sprite(objTexture);
                            obj.width = 20;
                            obj.height = 20;
                            obj.position.x = flyobj.position.x+flyobj.width/2-obj.width/2;
                            obj.position.y = flyobj.position.y+flyobj.height;
                            obj.circular = true;
                            objs.addChild(obj);
                            flyobj.time=1;
                        }
                        if (flyobj.position.y >= 500) {
                            flyobjs.removeChild(flyobj);
                        }
                        //碰撞检测
                        if (b.hitTestCircle(flyobj, player, true)) {
                            setTimeout(() => {
                                loop = false;
                                gameover();
                            }, 100);
                        }
                    });
                    
                    //遍历子弹
                    bullets.children.forEach(bullet => {
                        bullet.position.y -= 4;
                        if (bullet.position.y <= 0) {
                            bullets.removeChild(bullet);
                        }
                        //碰撞检测
                        flyobjs.children.forEach(flyobj => {
                            if (b.hitTestCircle(flyobj, bullet, true)) {
                                bullets.removeChild(bullet);
                                flyobjs.removeChild(flyobj);
                                
                                //消灭的敌机+1
                                number+=1;
                                numberText.text=number;
                            }
                        });
                        //
                    });
                    
                    //遍历敌机子弹
                    objs.children.forEach(obj => {
                        obj.position.y += 4;
                        if (obj.position.y >= 500) {
                            objs.removeChild(obj);
                        }
                        //碰撞检测
                        bullets.children.forEach(bullet => {
                            if (b.hitTestCircle(obj, bullet, true)) {
                                bullets.removeChild(bullet);
                                objs.removeChild(obj);
                            }
                        });
                        if (b.hitTestCircle(obj, player, true)) {
                            loop=false;
                            gameover();
                        }
                        //
                    });

                    //每隔一段时间,增长一个敌机
                    create_flyobj_time++;
                    if (create_flyobj_time >= 100) {
                        console.log('new fly obj');
                        flyobj = new PIXI.Sprite(flyobjTexture);
                        flyobj.width = 50;
                        flyobj.height = 50;
                        flyobj.position.x = r(0, 512);
                        flyobj.position.y = 0;
                        flyobj.circular = true;
                        flyobj.time=0;//用来计算时间,进行开火
                        flyobjs.addChild(flyobj);
                        create_flyobj_time = 0;
                    }
                }
                
                requestAnimationFrame(update);
            }
            
            
            //
            $('#restart').click(function(){
                restart();
            });
        }
    </script>
</html>

后记:这个游戏写到这里,的确是能够玩了。但其实继续完善和优化的空间很大。好比设置本身飞机有几条命,显示飞机的血值,不按期出现大礼包,吃到炸弹能够瞬间让整个屏幕的敌机都爆炸等。之后有时间我会继续完善。

在线体验:https://wbjs.github.io/pixi_g...

github 地址: https://github.com/wbjs/pixi_...

欢迎你们star。

相关文章
相关标签/搜索