phaser3之飞机大战(一)

4,171 阅读4分钟

写在前面

该飞机大战素材来源于phaser小站:
www.phaser-china.com/tutorial-de…
原文使用phaser2进行实现,本文用phaser3将飞机大战重构一遍,在实战中学习一下phaser3的api
源码:github.com/YUPENG12138…

1、初始化项目

1.我们使用github上初始化phaser3的webpack工程模板
github.com/photonstorm…
2.将项目中的phaser3版本更新到最新,npm i phaser3 -S
3.将MP3文件的处理引入webpack

// plane/webpack/base.js
{
   test: /\.(gif|png|jpe?g|svg|xml|mp3)$/i,
   use: "file-loader"
}

4.将项目中使用到的素材放到assets文件夹中
5.写个node脚本,生成一下静态资源的对应映射关系。

plane/assets_script.js
const fs = require('fs');;
const path = require('path');

const assetsList = fs.readdirSync(path.resolve(__dirname, 'src/assets/'));

const asssetsMap = {};
assetsList.forEach((item) => {
  const key = item.match(/.\w+/)[0];
  Object.assign(asssetsMap, {
    [key]: `assets/${item}`,
  });
});
fs.writeFileSync(path.resolve(__dirname, 'src/asset_map.json'), JSON.stringify(asssetsMap));

plane\src\asset_map.json

2、初始化配置,加载资源,设置背景

// 引入phaser
import Phaser from 'phaser';

//将资源映射map引进来
const assetsMap = require('./asset_map.json');

/*
* 这里是phaser初始化时的配置项
* api链接:https://photonstorm.github.io/phaser3-docs/Phaser.Types.Core.html#.GameConfig
* type 表示使用哪个渲染器,canvas,还是webgl。AUTO会自动选择,也可以设置
* width,height画布宽高
* scene 项目中的场景,是一个场景还是多个场景,preload create update相当于该场景的生命周期
* /
const config = {
  type: Phaser.AUTO,
  width: 240,
  height: 400,
  scene: {
    preload,
    create,
    update,
  },
};

// 配置完成后使用new Phaser.Game(config)实例化游戏。
// api链接:https://photonstorm.github.io/phaser3-docs/Phaser.Game.html
const game = new Phaser.Game(config);

/*
* 将静态资源使用this.load.image引入到项目中
* 这里有个问题,刚开始做的时候没有考虑到精灵图,普通图片和MP3的引用方式不一致的问题,都按照image的方式引入进来了
* 后面先做了兼容处理,等后续再优化
* api链接:https://photonstorm.github.io/phaser3-docs/Phaser.Loader.LoaderPlugin.html
*/
const asset = {};
function preload() {
  for (const key in assetsMap) {
    if (assetsMap.hasOwnProperty(key)) {
        asset[key] = this.load.image(key, require(`./${assetsMap[key]}`));
    }
  }
}

/*
* 资源加载完成后,在create里将背景图片引入进来
* this.add.image(x, y, imageKey)
* api链接:https://photonstorm.github.io/phaser3-docs/Phaser.GameObjects.GameObjectFactory.html#image__anchor
* phaser3默认位置点为中心点,所以为了从左上角设置位置,我们使用setOrigin(x, y)设置它的起始位置
* api链接:https://photonstorm.github.io/phaser3-docs/Phaser.GameObjects.Components.Origin.html#setOrigin__anchor
*/
function create() {
  const bg = this.add.image(0, 0, 'bg');
  bg.setOrigin(0, 0);
}

function update() {

}

这样游戏的背景就加载好了:

3、设置游戏资源加载进度,加载完成后,从加载场景切换到游戏开始场景

import Phaser from 'phaser';
const assetsMap = require('./asset_map.json');
/*
* 这里我们设置一个gameSenceCenter变量存放各个游戏场景
* 设置一个boot用于加载资源,start为游戏开始场景
*/
const gameSenceCenter = {};

gameSenceCenter.boot = {
  key: 'boot',
  preload() {
    for (const key in assetsMap) {
      if (assetsMap.hasOwnProperty(key)) {
        assetsMap[key] = this.load.image(key, require(`./${assetsMap[key]}`));
      }
    }
    /*
    * 这里我们添加一个文本来显示进度
    * api链接:https://photonstorm.github.io/phaser3-docs/Phaser.GameObjects.GameObjectCreator.html#text__anchor
    */
    const percentText = this.make.text({
      x: this.game.config.width / 2,
      y: this.game.config.height / 2 - 5,
      text: '0%',
      style: {
        font: '18px monospace',
        fill: '#ffffff'
      }
    })
    .setOrigin(0.5, 0.5);

    /*
    * 使用this.load.on监听加载进度和完成状态
    * api链接:https://photonstorm.github.io/phaser3-docs/Phaser.Loader.LoaderPlugin.html#on__anchor
    * 使用setText()设置文本显示
    * api链接:https://photonstorm.github.io/phaser3-docs/Phaser.GameObjects.Text.html#setText__anchor
    */
    this.load.on('progress', function (value) {
      percentText.setText(parseInt(value * 100) + '%');
    });

    this.load.on('complete', function () {
      percentText.destroy();
    });
  },
  create() {
    // 在加载完成后调用this.scene.start(场景key)开始下一个场景
    // api链接:https://photonstorm.github.io/phaser3-docs/Phaser.Scenes.ScenePlugin.html#start__anchor)
    this.scene.start('start');
  },
  update() {}
}

gameSenceCenter.start = {
  key: 'start',
  create() {
    this.add.image(0,0,'bg').setOrigin(0);
  },
  update() {},
}

const config = {
  type: Phaser.AUTO,
  width: 240,
  height: 400,
  scene: [gameSenceCenter.boot, gameSenceCenter.start],
};
const game = new Phaser.Game(config);

4、手机屏幕适配

// plane/index.html
<!--设置一下通用样式-->
<style>
    * {
      margin: 0;
      padding: 0;
    }
</style>

// plane/src/index.js
/*
* 在boot preload中设置适配兼容,desktop表示是否是桌面端
* api链接:https://photonstorm.github.io/phaser3-docs/Phaser.Game.html#device__anchor
* Phaser.Scale.FIT 表示保持比例将界面充满,还有其他的属性可以看文档去尝试一下
* api链接:https://photonstorm.github.io/phaser3-docs/Phaser.Scale.ScaleManager.html#scaleMode__anchor
* 设置后需要刷新一下
* api链接:https://photonstorm.github.io/phaser3-docs/Phaser.Scale.ScaleManager.html#refresh__anchor
*/
if (!this.game.device.os.desktop) {
  this.scale.scaleMode = Phaser.Scale.FIT;
  this.scale.refresh();
}

这样就充满手机屏幕了

5、为开始场景添加元素

1、这里我们要修改一下boot.preload函数里的加载逻辑,做下前面说的精灵图加载兼容,精灵图和正常图片的加载方式是不一样的
这里我们先用到了飞机和开始按钮,就先处理这两个

/*
* 加载精灵图的方法是this.load.spritesheet(图片key, 图片路径, { 每帧宽度, 每帧高度 });
* api链接:https://photonstorm.github.io/phaser3-docs/Phaser.Loader.LoaderPlugin.html#spritesheet__anchor
*/
preload() {
    for (const key in assetsMap) {
      if (assetsMap.hasOwnProperty(key)) {
        if (key === 'myplane') {
          this.load.spritesheet(key, require(`./${assetsMap[key]}`), {
            frameWidth: 40,
            frameHeight: 40,
          });
          continue;
        }
        if (key === 'startbutton') {
          this.load.spritesheet(key, require(`./${assetsMap[key]}`), {
            frameWidth: 100,
            frameHeight: 40,
          });
          continue;
        } 
        assetsMap[key] = this.load.image(key, require(`./${assetsMap[key]}`));
      }
    }
    ...
}

2、我们开始为start场景加元素

/*
* 在start.create中我们添加元素逻辑
* 1.在start场景中我们添加游戏背景
*
* 2.添加copyright标识
*
* 3.添加飞机精灵
* this.add.sprite(x, y, 图片key),因为引入时候我们是用spritesheet引入的,所以会显示第一帧
* api链接:https://photonstorm.github.io/phaser3-docs/Phaser.GameObjects.GameObjectFactory.html#sprite__anchor
*
* 4.创建飞机帧动画
* this.animas.create({动画的名字, 序列帧, 帧速率, 重复状态})
* api链接:https://photonstorm.github.io/phaser3-docs/Phaser.Types.Animations.html#.Animation
* this.anims.generateFrameNumbers() 生成一个Phaser.Types.Animations.AnimationFrame对象数组
* api链接:https://photonstorm.github.io/phaser3-docs/Phaser.Animations.AnimationManager.html#generateFrameNames__anchor
*
* 5.plane.anims.play('fly');让精灵调用帧动画进行播放
* api链接:https://photonstorm.github.io/phaser3-docs/Phaser.GameObjects.Components.Animation.html#play__anchor
*
* 6.添加开始按钮
* 这里涉及到了this.add.sprite的第4个参数,表示要加载精灵图里的第几帧,从0开始
* setInteractive()是将精灵变成可点击的状态
* https://photonstorm.github.io/phaser3-docs/Phaser.GameObjects.Sprite.html#setInteractive__anchor
*
* 7.为开始按钮添加按下和抬起事件
* api链接:https://photonstorm.github.io/phaser3-docs/Phaser.GameObjects.Sprite.html#on__anchor
* 在按下抬起是使用setFrame去切换帧
* api链接:https://photonstorm.github.io/phaser3-docs/Phaser.GameObjects.Sprite.html#setFrame__anchor
*/
// 添加背景
const bg = this.add.image(0, 0, 'bg').setOrigin(0);

// 添加游戏copyright标识
this.add.image(this.game.config.width / 2, this.game.config.height - 16, 'copyright');

// 引入飞机精灵
const plane = this.add.sprite(this.game.config.width / 2, 100, 'myplane');

// 创建飞行帧动画
this.anims.create({
  key: 'fly',
  frames: this.anims.generateFrameNumbers('myplane', { start: 0, end: 3 }),
  frameRate: 10,
  repeat: -1
});

// 飞机调用飞行动画
plane.anims.play('fly');

// 添加开始按钮
const startButton =  this.add.sprite(this.game.config.width / 2, 200, 'startbutton', 1).setInteractive();
startButton.on('pointerdown', () => {
  startButton.setFrame(0);
})
startButton.on('pointerup', () => {
  startButton.setFrame(1);
  console.log('start game');
})

本篇就先到这里,下周会更新游戏场景的部分逻辑,包含飞机拖拽,边界检测,发射子弹,敌机碰撞检测。