网页游戏以其便携性通常内嵌在各大app中,通过提供沉浸式的游戏体验拉近用户与app之间的距离,最终将用户流量转换为具体的物质价值,这就是网页游戏的价值之一。
本文将带你从零使用Pixi.js打造一款专业级别的网页游戏—消消乐,在线体验网址。通过本文,你会学习到如何使用Pixi及其生态开发一款专业的游戏,充分感受pixi在交互式应用上的魅力。
本文传达的技术或思想不会限制在pixi应用,比如静态资源处理,游戏路由管理器设计理念,缓存池,可暂停可恢复的异步队列管理器等等一系列最佳实战,你都可以直接或举一反三应用到自己的实际项目当中。
游戏主要界面预览
首页
准备状态
消除状态
游戏及结束状态
Pixi简介及其生态
Pixi.js是一款开源的、基于WebGL的2D渲染引擎,被广泛应用于创建交互式的、富有创意的Web应用程序比如游戏,DIY设计等。
在笔者使用pixi期间,个人非常喜欢它的以下特性:
- 灵活的API设计。使它可以方便地与其它库相结合,比如 pixi-react
- 遮罩系统。类似于CSS中的mask-image或PS中的剪切蒙版,我们可以很方便地将图像、容器等限制在其它图形图像的可视区域内。笔者之前写过一个基于Vue3+Pixi.js开发的DIY设计项目,就是得益于pixi灵活的API设计与遮罩系统,使它可以很方便地与Vue3自定义渲染器相结合并实现了可设计区域。
- 较为丰富的生态。
- @pixi/ui:基于pixi的,通用的,可扩展的UI组件库;
- @pixi/layout:简单快捷地在游戏中创建响应式布局。
- @pixi/sound:音频管理。基于WebAudio API。
- AssetPack:静态资源打包器。通过它,我们可以生成manifest.json静态资源清单文件,打包纹理图集(类似于雪碧图),压缩图片,json等,格式转换如ttf转体积更小woff2格式,wav转兼容性更好的MP3格式等。这些功能可帮助我们优化静态资源,以加快加载时间、提高性能和改善用户体验。
- pixi-spine:在pixi中应用spine动画
以上库我们在打造消消乐游戏中都会使用到,当然,还有大名鼎鼎的js动画库gsap以及家喻户晓的现代构建工具 vite。
此外,pixi是基于WebGL的,这使得它能够利用硬件加速来实现高效的渲染,据官方透露,PixiJS V8将会对WebGPU进行更好的支持,届时其渲染性能也会更上一层。pixi社区也提供了丰富的滤镜库以帮助我们实现各种图像效果比如模糊,渐变,色彩调整,马赛克,置换等等。当然,对ts的支持也至关重要,在使用这种多API的库时,我可不希望点一个对象没有任何提示~。
未来pixi还会进一步支持3D渲染,游戏引擎,脚手架等,使游戏开发更轻松,更高效。总之,pixi的潜力很大,在构建数字化内容网站时,限制我们的往往是想象力,而不会是pixi或其它技术本身了。更多详情详见pixi官网,下面我们进入正式的开发当中。
准备工作
在开发前我们需要准备一些开发工具,它们可以帮助我们更好更快地理解pixi。
1.PixiJS Devtools。一款可视化、用于开发调试pixi应用的浏览器扩展插件,在火狐、谷歌扩展商店都有提供下载。通过它我们可以看到画布中元素之间的嵌套关系,重要的是我们可以看到元素支点(pivot或anchor)的位置,这对于元素的布局太有用了!
2.AI工具。先不说pixi目前没有中文文档,即使翻译成中文,其中有一些专有名词在我们没有足够的实战经验下也会难以理解(这一点真的劝退大部分人),比如元素属性tiny,texture,变换矩阵等,这就需要AI工具帮我们快速解读。我为项目编写了大量注释,一方面除了帮助他人理解,另一方面也为AI工具提供了详细的代码上下文,这样,AI会更加理解你的意图以便给出更符合我们预期的答案。目前免费的这里推荐codeGeeX(清华系)、codeium,VSCode扩展中直接搜索下载即可,不过codeium貌似授权需要魔法。如果你已经有心仪的AI工具可以忽略这里。
3.语言翻译工具。在阅读pixi官方文档以及本项目源码注释时,你可能会需要到。笔者使用的是 沉浸式翻译。
当然,还有一款心仪的代码编辑器,以及一颗对游戏或好奇或热爱的心。Let us go.
打包静态资源
首先我们需要使用pnpm init
初始化项目,并且安装相关依赖:
安装生产依赖
这里值得注意的@pixi/ui使用的是0.5版本
pnpm i @pixi/sound @pixi/ui@0.5.0 gsap pixi-spine pixi.js
安装开发依赖
pnpm i vite @assetpack/cli @assetpack/plugin-compress @assetpack/plugin-ffmpeg @assetpack/plugin-json @assetpack/plugin-manifest @assetpack/plugin-texture-packer @assetpack/plugin-webfont -D
- @assetpack/cli:assetpack脚手架。
- @assetpack/plugin-compress:使用 sharp 压缩图像的AssetPack插件。
- @assetpack/plugin-ffmpeg:使用ffmpeg转换音视频文件的AssetPack插件。这里需要在系统上安装ffmpeg,首先在ffmpeg官网下载系统对应的安装包,解压,安装。最后需要配置系统环境变量,以下是mac操作:
# 打开.zshrc,没有就新建
open ~/.zshrc
# 加入以下代码,$PATH后面跟ffmpeg可执行程序所在的文件夹
export PATH=$PATH:/Users/用户名/Downloads
# 使环境变量生效
source ~/.zshrc
最后在终端输入ffmpeg -h
检验一下,系统就会在指定的$PATH中查找对应的可执行程序进行启动。
- @assetpack/plugin-json:用于压缩JSON文件的AssetPack插件。
- @assetpack/plugin-webfont:用于将ttf、otf、woff和svg格式字体转换成体积更小的woff2字体的AssetPack插件。
- @assetpack/plugin-manifest:生成manifest.json资源清单文件,这是pixi V7版本中加载资源清单的最佳实践。
- @assetpack/plugin-texture-packer:使用Texture Packer生成纹理图集(类似雪碧图或者序列帧集合)的AssetPack插件,可用于优化请求次数。
使用assetpack打包资源
新建.assetpack.js
,配置如下:
import {
compressJpg, compressPng } from '@assetpack/plugin-compress';
import {
audio, ffmpeg } from '@assetpack/plugin-ffmpeg';
import {
json } from '@assetpack/plugin-json';
import {
pixiManifest } from '@assetpack/plugin-manifest';
import {
pixiTexturePacker } from '@assetpack/plugin-texture-packer';
import {
webfont } from '@assetpack/plugin-webfont';
export default {
entry: './raw-assets', // 原始资源存放位置
output: './public/assets/', // 打包后存放位置
cache: false, // 不使用缓存
plugins: {
webfont: webfont(), // 字体转woff格式
compressJpg: compressJpg({
// 压缩jpeg
compression: {
quality: 90
}
}),
compressPng: compressPng(), // 压缩png
// audio: audio(), // 快捷配置将wav转mp3,但会同时生成ogg格式
// 因此这里使用ffmpeg进行更详细的配置
ffmpeg: ffmpeg({
inputs: ['.wav'],
outputs: [
{
formats: ['.mp3'],
recompress: true, // 是否重新压缩。比如mp3转mp3也压缩
// options必须提供,可以为空对象
options: {
audioBitrate: 96,
audioChannels: 1,
audioFrequency: 48000,
}
},
]
}),
json: json(), // 压缩json
texture: pixiTexturePacker({
texturePacker: {
removeFileExtension: true, // 移除扩展名
}
}),
// 名称末尾带{m}标识的文件夹或文件都会添加到manifest清单
manifest: pixiManifest({
output: './public/assets/assets-manifest.json'
}),
},
};
在.assetpack.js配置中,由于我们使用到了es6 module,因此需要在package.json中配置type: "module"
。然后在package.json中添加打包的npm script:
{
"assetpack": "assetpack"
}
最后运行一下assetpack命令pnpm run assetpack
即可打包资源。关于assetpack插件用法请自行查阅文档,最后简单看下打包结果(具体可在文末找到项目地址,将其clone到本地运行查看结果)。
- common是游戏欢迎页,游戏页,游戏结果页的共同资源。
- game是游戏页需要的资源。
- home是游戏欢迎页需要的资源。
- preload是加载页需要的资源。
- result是游戏结果页需要的资源。
- assets-manifest.json就是所有资源的清单文件。它的格式大概如下:
{
"bundles": [
{
"name": "preload",
"assets": [
{
"name": [
"preload/cauldron-skeleton.atlas"
],
"srcs": [
"preload/cauldron-skeleton.atlas"
],
}
// ...
]
},
{
"name": "home",
"assets": [
// 一系列资源列表...
]
},
// ...
]
}
纹理图集打包预览
使用vite启动一个最简单的pixi项目
1.新建src/app.ts
创建并导出一个Pixi应用
import {
Application, Text } from "pixi.js";
import {
isDev } from "./utils/is";
Text.defaultResolution = 2;
Text.defaultAutoResolution = false;
export const app = new Application<HTMLCanvasElement>({
backgroundColor: 0xffffff,
backgroundAlpha: 0,
resolution: 2,
})
isDev() && (globalThis.__PIXI_APP__ = app);
- Text.defaultResolution = 2; 表示文字抗锯齿
- isDev() && (globalThis.PIXI_APP = this); 开发环境启用Pixi DevTool
2.新建src/main.ts
引入app并将canvas元素(即app.view)添加到页面上。
import {
app } from "./app";
async function init() {
// add canvas element to body
document.body.append(app.view)
// hide loading
document.body.classList.add('loaded')
}
init()
3.新建index.html
应用入口文件,引入main.ts,并添加值为"module"的type属性,同时添加CSS loading动画。
<!DOCTYPE html>
<html lang="en">
<head>
<meta char