Pixi.js游戏开发

如何使用pixi.js制作'打飞机'小游戏

2019-06-03  本文已影响0人  希染丶

什么是pixi.js

Pixi.js使用WebGL,是一个超快的HTML5 2D渲染引擎。作为一个Javascript的2D渲染器,Pixi.js的目标是提供一个快速的、轻量级而且是兼任所有设备的2D库。提供无缝 Canvas 回退,支持主流浏览器,包括桌面和移动。 Pixi渲染器可以开发者享受到硬件加速,但并不需要了解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>

创建pixi实例完整流程

1.创建一个应用(application)(包含舞台stage)
2.加载资源(loader)
3.创建游戏场景
4.将场景插入舞台(addchild)
5.把画布插入dom(append)
6.创建精灵(sprite)
7.把精灵加入画布(addchild)
8.刷新舞台(ticker)
9.游戏结束,销毁应用(destroy)

1.创建应用

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

2.加载资源

let loader = new PIXI.Loader();
loader
    .add('bg', 'img/bg.jpg')
    .....
    .load((loader, resources) => {
      // 加载完毕回调
      setUp(); //执行创建精灵等操作
    });

3/4.创建游戏场景并插入舞台

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

5.把画布插入dom

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

6.创建精灵并插入场景

首先,为了方便的设定精灵宽高,声明两个方法

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.飞机

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

给飞机添加拖动事件,让飞机跟着手指移动。
给飞机添加射击事件,在ticker中调用,使飞机一直发射子弹
3.障碍物

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

这种只是最基础的做法,如果有稍微多一点的需求,例如,碰撞检测的区域,和纹理图大小不一样,就需要
将障碍物纹理、碰撞区域、爆炸动画,都放入一个container内,碰撞区域push进入obstacles数组,去和子弹飞机做碰撞检测
障碍物的飞行,使用tween.js,初始化时候,设置好起点终点,在ticker中update就可以像目的地移动

    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);
    // 碰撞区域
    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;
   
    // 位移设定
    let tween = new TWEEN.Tween(container)
      .to(
        {
          x: getWidth(Math.random() * 100),
          y: getHeight(100) + obstacle.height,
        },
        obstacleTime // tween持续时间
      )
      .easing(TWEEN.Easing.Linear.None)
      .onComplete(function () {
        // 到底
        container.destroy();
      });
    tween.start();

    // 旋转设定
    let tween2 = new TWEEN.Tween(obstacle)
      .to(
        {
          rotation: -20
        },
        obstacleTime // tween持续时间
      )
      .easing(TWEEN.Easing.Linear.None)
      .onComplete(function () {
      });
    tween2.start();
    // 插入场景
    container.tween = tween;
    obstacles.push(circle);
    tweens.push(tween);
    gameScene.addChild(container);

7.更新舞台

创建完游戏内所有元素后,开启pixi内置定时器ticker

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

在ticker中更新需要调用的事件,来实现游戏的动态效果

function gameLoop(){
  // 生成子弹
  plane.shut(gameScene, bullets);
  // 生成障碍物
  createobstacle(gameScene, texture, obstacles, TWEEN, tweens);
  // 子弹逻辑处理
  bulletsEvents();
  // 障碍物逻辑处理
  obstaclesEvents();
}

8.子弹飞机障碍物的碰撞逻辑(重点)

function bulletsEvents(){
  for(let i = 0; i < bullets.length;){
    let hit = false;
    for(let o = 0; o < obstacles.length; ) {
        // 子弹与障碍物碰撞检测
      if(hitTest(obstacles[o], bullets[i])) {
        hit = true;
        // 移除障碍物
        obstaclesBoom(o)
        continue;
      }else if(hitTest(obstacles[o], plane)){
        // 飞机与障碍物碰撞检测
        let _obstacle = obstacles.splice(o,1)[0];
        _obstacle.destroy();
        gameOver();
        continue;
      }else{
        o++
      }
    }
    // 根据碰撞状态做处理
    if(hit){
      // 如果碰撞了
      // 移除当前子弹
      let _bullet = bullets.splice(i,1)[0];
      _bullet.destroy();
      // 加分
      score ++;
      scorePanel.text = '得分:' + score;
    }else{
      // 如果子弹飞出屏幕,则移除;如果没有,Y轴位移
      if(bullets[i].y < -bullets[i].height){
        let _bullet = bullets.splice(i,1)[0];
        _bullet.destroy();
      }else{
        bullets[i].y -= 10;
        i++
      }
    }
  }
}

首先遍历子弹池,内部遍历所有障碍物,通过hitTest做碰撞检测
如果子弹和障碍物碰撞,子弹消失,障碍物消失/爆炸,得分+1;
如果飞机和障碍物碰撞,障碍物消失/爆炸,游戏结束
如果都没有,检测下一个子弹
如果子弹自下而上,飞出屏幕,则子弹移除,否则影响性能
==============================================================
碰撞检测代码,bump通过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.障碍物爆炸逻辑

碰撞之后,根据parent属性,找到container,进而找到内部的爆炸动画,执行play()方法;
爆炸的同时,使纹理隐藏,形成视觉上的碰撞爆炸效果

部分代码:

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;
}

总结

只是随便讲一下做法的逻辑,具体代码已上传github,地址:https://github.com/huangXin1538/pixi-aircrift-wars

demo 效果地址

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

上一篇 下一篇

猜你喜欢

热点阅读