这两天用pixi开发了一款小游戏,属于射击游戏范畴。开局很简单,上来玩就是了。javascript
但其实须要注意的事项也很多。下面简单总结一下,有5点须要注意的地方,若是不注意,容易出现错误,或致使chrome崩溃。html
1、使用 requestAnimationFrame
代替定时器java
requestAnimationFrame比定时器更平滑,同时在性能上也更稳定。jquery
requestAnimationFrame(update); function update(){ //对 Sprite 的一些操做 requestAnimationFrame(update); }
2、碰撞检测用bump
git
因为pixi本身并无碰撞检测库,因此不少人须要本身写。但本身写不免会出现问题。而bump是一个很成熟的碰撞检测库。github
对于一些并不是方形(边角是空白的精灵)元素的碰撞,能够采用hitTestCircle
函数:chrome
if (b.hitTestCircle(SpriteA, SpriteB, true)) { //这里是发生碰撞后的代码 }
但须要在精灵上面定义circular属性为true
canvas
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。