如何使用pixi.js制作'打飛機(jī)'小游戲

什么是pixi.js

Pixi.js使用WebGL,是一個(gè)超快的HTML5 2D渲染引擎。作為一個(gè)Javascript的2D渲染器,Pixi.js的目標(biāo)是提供一個(gè)快速的、輕量級(jí)而且是兼任所有設(shè)備的2D庫(kù)。提供無(wú)縫 Canvas 回退,支持主流瀏覽器,包括桌面和移動(dòng)。 Pixi渲染器可以開(kāi)發(fā)者享受到硬件加速,但并不需要了解WebGL。

如何引入pixi.js

1.安裝模塊
代碼中引入:import * as PIXI from 'pixi.js';
2.cdn
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/4.5.1/pixi.min.js"></script>

創(chuàng)建pixi實(shí)例完整流程

1.創(chuàng)建一個(gè)應(yīng)用(application)(包含舞臺(tái)stage)
2.加載資源(loader)
3.創(chuàng)建游戲場(chǎng)景
4.將場(chǎng)景插入舞臺(tái)(addchild)
5.把畫(huà)布插入dom(append)
6.創(chuàng)建精靈(sprite)
7.把精靈加入畫(huà)布(addchild)
8.刷新舞臺(tái)(ticker)
9.游戲結(jié)束,銷(xiāo)毀應(yīng)用(destroy)

1.創(chuàng)建應(yīng)用

let gameApp = new PIXI.Application({
    width: xxxx,
    height: xxxx,
    antialiasing: true, // 抗鋸齒
    transparent: false, // 背景透明
    resolution: 2 // 渲染倍數(shù),避免模糊
});

2.加載資源

let loader = new PIXI.Loader();
loader
    .add('bg', 'img/bg.jpg')
    .....
    .load((loader, resources) => {
      // 加載完畢回調(diào)
      setUp(); //執(zhí)行創(chuàng)建精靈等操作
    });

3/4.創(chuàng)建游戲場(chǎng)景并插入舞臺(tái)

let gameScene = new PIXI.Container();
gameScene.width = xxx;
gameScene.height = xxx;
gameApp.stage.addchild(gameScene);

5.把畫(huà)布插入dom

document.getElementById('xxx').appendChild(gameApp.view);

6.創(chuàng)建精靈并插入場(chǎng)景

首先,為了方便的設(shè)定精靈寬高,聲明兩個(gè)方法

function getWidth (precent) {
  let w = document.body.clientWidth > 720 ? 720 : document.body.clientWidth;
  return (precent / 50) * w / 2;
}
function getHeight (precent) {
  let h = document.body.clientHeight;
  return (precent / 50) * h / 2;
}

1.背景

let bg = new PIXI.Sprite(resources.bg.texture);
bg.width = xxx;
bg.height = xxx;
bg.x = xxx;
bg.y = xxx;
gameScene.addchild(bg)

2.飛機(jī)

let plane = new PIXI.Sprite(resources.plane.texture);
plane.width = xxx;
plane.height = xxx;
plane.x = xxx;
plane.y = xxx;
gameScene.addchild(plane)

給飛機(jī)添加拖動(dòng)事件,讓飛機(jī)跟著手指移動(dòng)。
給飛機(jī)添加射擊事件,在ticker中調(diào)用,使飛機(jī)一直發(fā)射子彈
3.障礙物

let obstacle  = new PIXI.Sprite(resources.obstacle.texture);
obstacle.width = xxx;
obstacle.height = xxx;
obstacle.x = xxx;
obstacle.y = xxx;
gameScene.addchild(obstacle)

這種只是最基礎(chǔ)的做法,如果有稍微多一點(diǎn)的需求,例如,碰撞檢測(cè)的區(qū)域,和紋理圖大小不一樣,就需要
將障礙物紋理、碰撞區(qū)域、爆炸動(dòng)畫(huà),都放入一個(gè)container內(nèi),碰撞區(qū)域push進(jìn)入obstacles數(shù)組,去和子彈飛機(jī)做碰撞檢測(cè)
障礙物的飛行,使用tween.js,初始化時(shí)候,設(shè)置好起點(diǎn)終點(diǎn),在ticker中update就可以像目的地移動(dòng)

    let container = new PIXI.Container();
    // 圖案
    let obstacle = new PIXI.Sprite(texture.obstacle.texture);
    obstacle.name = 'obstacle';
    obstacle.width = getWidth(30);
    obstacle.height = getWidth(30);
    obstacle.x = 0;
    obstacle.y = 0;
    obstacle.anchor.set(0.5, 0.5);
    // 碰撞區(qū)域
    let circle = new PIXI.Sprite();
    circle.width = obstacle.width * 0.5;
    circle.height = circle.width;
    circle.name = 'circle';
    circle.circular = true;
    circle.x = -circle.width*0.5;
    circle.y = -circle.height*0.5;
    container.addChild(circle);
    
    // 文字
    let text = new PIXI.Text('哈哈', {
      fontSize: obstacle.width * 0.13,
      fill: '#fff'
    });
    text.x = - text.width*0.5;
    text.y = - text.height*0.5;
    container.addChild(text);

    // 爆炸效果
    let fireClip = [
    ];
    for (let i = 0; i <= 23; i++) {
      fireClip.push(texture.boom.textures['boom' + i + '.png']);
    }
    let boom = new PIXI.AnimatedSprite(fireClip);
    boom.width = obstacle.width * 2.5;
    boom.height = obstacle.height * 2.5;
    boom.x = -boom.width * 0.5;
    boom.y = -boom.height * 0.5;
    boom.name = 'boom';
    boom.loop = false;
    container.addChild(boom);


    container.addChild(obstacle);
    container.addChild(circle);
    container.x = getWidth(Math.random()*100);
    container.y = -obstacle.height;
   
    // 位移設(shè)定
    let tween = new TWEEN.Tween(container)
      .to(
        {
          x: getWidth(Math.random() * 100),
          y: getHeight(100) + obstacle.height,
        },
        obstacleTime // tween持續(xù)時(shí)間
      )
      .easing(TWEEN.Easing.Linear.None)
      .onComplete(function () {
        // 到底
        container.destroy();
      });
    tween.start();

    // 旋轉(zhuǎn)設(shè)定
    let tween2 = new TWEEN.Tween(obstacle)
      .to(
        {
          rotation: -20
        },
        obstacleTime // tween持續(xù)時(shí)間
      )
      .easing(TWEEN.Easing.Linear.None)
      .onComplete(function () {
      });
    tween2.start();
    // 插入場(chǎng)景
    container.tween = tween;
    obstacles.push(circle);
    tweens.push(tween);
    gameScene.addChild(container);

7.更新舞臺(tái)

創(chuàng)建完游戲內(nèi)所有元素后,開(kāi)啟pixi內(nèi)置定時(shí)器ticker

app.ticker.add(function () {
    return gameLoop();
});

在ticker中更新需要調(diào)用的事件,來(lái)實(shí)現(xiàn)游戲的動(dòng)態(tài)效果

function gameLoop(){
  // 生成子彈
  plane.shut(gameScene, bullets);
  // 生成障礙物
  createobstacle(gameScene, texture, obstacles, TWEEN, tweens);
  // 子彈邏輯處理
  bulletsEvents();
  // 障礙物邏輯處理
  obstaclesEvents();
}

8.子彈飛機(jī)障礙物的碰撞邏輯(重點(diǎn))

function bulletsEvents(){
  for(let i = 0; i < bullets.length;){
    let hit = false;
    for(let o = 0; o < obstacles.length; ) {
        // 子彈與障礙物碰撞檢測(cè)
      if(hitTest(obstacles[o], bullets[i])) {
        hit = true;
        // 移除障礙物
        obstaclesBoom(o)
        continue;
      }else if(hitTest(obstacles[o], plane)){
        // 飛機(jī)與障礙物碰撞檢測(cè)
        let _obstacle = obstacles.splice(o,1)[0];
        _obstacle.destroy();
        gameOver();
        continue;
      }else{
        o++
      }
    }
    // 根據(jù)碰撞狀態(tài)做處理
    if(hit){
      // 如果碰撞了
      // 移除當(dāng)前子彈
      let _bullet = bullets.splice(i,1)[0];
      _bullet.destroy();
      // 加分
      score ++;
      scorePanel.text = '得分:' + score;
    }else{
      // 如果子彈飛出屏幕,則移除;如果沒(méi)有,Y軸位移
      if(bullets[i].y < -bullets[i].height){
        let _bullet = bullets.splice(i,1)[0];
        _bullet.destroy();
      }else{
        bullets[i].y -= 10;
        i++
      }
    }
  }
}

首先遍歷子彈池,內(nèi)部遍歷所有障礙物,通過(guò)hitTest做碰撞檢測(cè)
如果子彈和障礙物碰撞,子彈消失,障礙物消失/爆炸,得分+1;
如果飛機(jī)和障礙物碰撞,障礙物消失/爆炸,游戲結(jié)束
如果都沒(méi)有,檢測(cè)下一個(gè)子彈
如果子彈自下而上,飛出屏幕,則子彈移除,否則影響性能
==============================================================
碰撞檢測(cè)代碼,bump通過(guò)cdn引入
hitTestCircleRectangle只能用于圓形和矩形的碰撞,更多方式查看PIXI官方文檔

// 子彈詞條碰撞
import * as PIXI from 'pixi.js';
export function hitTest (r1, r2) {
  let b = new Bump(PIXI);
  if (b.hitTestCircleRectangle(r1, r2, true) !== false) {
    return true;
  } else {
    return false;
  }
}

9.障礙物爆炸邏輯

碰撞之后,根據(jù)parent屬性,找到container,進(jìn)而找到內(nèi)部的爆炸動(dòng)畫(huà),執(zhí)行play()方法;
爆炸的同時(shí),使紋理隱藏,形成視覺(jué)上的碰撞爆炸效果

部分代碼:

function obstaclesBoom(o){
  let container = obstacles[o].parent;
  let _obstacle = obstacles.splice(o,1)[0];
  _obstacle.destroy();
  container.children[1].play();
  container.children[0].visible = false;
  container.children[2].visible = false;
}

總結(jié)

只是隨便講一下做法的邏輯,具體代碼已上傳github,地址:https://github.com/huangXin1538/pixi-aircrift-wars

demo 效果地址

http://47.104.9.195:8080/pixi-aircraft-wars/
就醬~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容