PixiJS游戏开发应用实践(一)

3,741 阅读5分钟

背景

最近在做一个城市旅行打卡养成类的活动需求,其中主场景地图模块是采用PixiJs渲染的,由于之前也没有接触过H5游戏的开发,对于PixiJs也是只停留在有所耳闻的阶段,因此这次的开发也是现学现用,前后历时1个月左右的时间,踩了一些坑,也总结了一些个人的开发经验,基于PixiJs做了一些基础的游戏功能API的封装。俗话说得好:“工欲善其事,必先利其器。”,在揭晓这些API的神秘面纱之前,我们一起来学习一下PixiJs的几个简单概念,为我们后续的深入了解打下基础。

PixiJs

官网对于PixiJs的定义:它是一个非常快的2D sprite渲染引擎。渲染引擎就说明它负责关于渲染的一切功能,可以帮助我们显示、动画和管理交互图形。

image.png

几个基本概念

Application

const app = new PIXI.Application({
    width: 256, // default: 800 宽度
    height: 256, // default: 600 高度
    antialias: true, // default: false 反锯齿
    transparent: false, // default: false 透明度
    resolution: 1 // default: 1 分辨率
})
document.body.appendChild(app.view)

pixi通过Application对象创建一个矩形显示区域。它会自动生成一个HTML的canvas元素,所有的绘制都是基于这个canvas画布。Application也会自动选择使用Canvas或者是WebGL来渲染图形,这个取决于浏览器的支持情况。

Container

Container-容器对象,它会在应用中创造一个新的图层。可以类比于我们HTML中的div,作为一个容器,必然是可以装载子元素对象,在实际开发中,我们一般用它来为显示对象做分组。

Sprite

在pixi中,Sprite(精灵)是一种特殊的图像对象,这个应该是游戏开发最常用的对象之一了,实际开发中,一般用它来显示游戏图片资源。

Loader

pixi使用WebGL在GPU上渲染图像,因此图像需要被转换为GPU可以处理的对象,这个对象在pixi中被称为texture(纹理),为了保证存取的高效,pixi使用text cache(纹理缓存)来存储和引用精灵需要的所有纹理。那么如何加载图像文件,将它转化为GPU所需要的纹理呢?那就需要Loader(加载器)对象来出马了,它可以加载任何类型格式的图像。

了解完上面一些基础概念之后,我们就来开始今天第一个API的揭秘。

封装一个图片预加载API

首先我们要明白为什么需要预加载,上面我们提到如果要创建一个Sprite精灵对象,就需要取纹理缓存中存储的纹理对象,而纹理对象是通过Loder加载器加载转化的。也就是我们游戏的loading过程其实就是通过加载器加载图像资源转化为纹理对象的过程。

Loder的基本使用方式

// pixiv5.0.x版本以后Loader挂载在shared属性下
const Loader = PIXI.Loader.shared
// 一、add加载图像列表
Loader.add([
  'assets/fire.png',
  'assets/water.png'
])
.load(callback)
// 二、add加载单个图片,为资源分配名称
Loader.add('fire', 'aasets/fire.png').load(callback)
// 三、单个资源加载成功回调,其中的url可以是本地图片地址,也可以是远程cdn图片资源地址
Loader.add([
   { name: 'fire', url: 'assets/fire.png', onComplete: () => {} }
])
.load(callback)

从上面可以看出loader加载器先add加载图像资源(列表),load为加载完成的回调,所以基于上述loader相关api进行封装:

export default function (resource: Array<any[]>): Promise<unknown> {
  if (!Array.isArray(resource)) {
    console.error(`请传入一个资源列表`)
    return
  }
  let loaderArr = []
  if (Array.isArray(resource[0])) {
    resource.forEach(item => {
      const onComplete = item[2] ? item[2] : null
      const loaderItem = {
        name: item[0], // 资源的别名
        url: item[1], // 资源的地址
        onComplete // 资源完成加载时要调用的函数
      }
      loaderArr.push(loaderItem)
    })
  } else {
    loaderArr = resource
  }
  return new Promise((resolve, reject) => {
    Loader.add(loaderArr)
      .load(resolve)
    Loader.onError.add(reject)
  })
}

使用方式如下:

let count = 0

// 用作计算资源的加载进度
const loadCount = () => {
  count++
  console.log(`加载资源图片第${count}张, 时间${Date.now()}`)
}

// 预加载
Preloader([
  ['fire', 'assets/fire.png', loadCount],
  ['water', 'assets/water.png', loadCount],
  ['json', 'assets/sprite.json', loadCount]
]).then(() => {
  console.log('资源加载成功')
}).catch(() => {
  console.log('资源加载失败')
})

Loder加载器支持加载雪碧图的json文件。那么基于pixi的雪碧图该如何制作呢,接下来我们聊聊这个话题。

关于如何制作PixiJs雪碧图

在游戏开发领域,资源加载效率是游戏性能的一大瓶颈,为了提升游戏的加载性能,对于多张同类型的资源图片,会通过软件合成的方式把他们合成到一张图片上,这张图片就是雪碧图,减少了网络请求次数。而我们通常用来做雪碧图的工具就是TexturePacker,字面上的意思就是纹理打包工具。软件操作界面:

image.png

只需要在右侧设置一览的数据格式中选择PixiJS选项即可,最后生成的文件包含一个.json和一个.png/.jpg文件,前者是每张图片在雪碧图上的位置和图片相关信息,后者是合成之后的大尺寸雪碧图,其中的json文件格式:

image.png

其中的meta/image属性替换成你的cdn图片资源地址即可,而鲜肉月饼则是该图片对应的纹理名称,然后Preloader中的json地址替换成你的cdn上的json地址即可,json上包含的所有的图片对象纹理都会被加载到纹理缓存中。

TexturePacker软件还是很方便的,支持业内几乎全部流行的游戏引擎,包括但不限于CocosUnity白鹭EgretPixiJs等,不过专业版对于一台机器只有7天的试用期,免费版不能使用高级算法,合成出来的雪碧图有瑕疵,这个就比较没办法,除非愿意付费支持,目前还没有其他相关的能代替它的工具,如果有小伙伴知道的,可以评论区分享出来哈~

后记

本次主要分享关于PixiJs的一些基础知识,封装一个简单的资源预加载器,以及TexturePacker软件用于合成雪碧图的一些基础使用步骤。后续会更新关于帧动画播放碰撞检测以及自适应的应用创建等相关API,有问题评论区码字,也欢迎指错勘误!

参考

  1. PixiJs中文网
  2. Texturepacker官网
  3. Loader