PixiJS实现白色相簿2游戏

2,547 阅读4分钟

我即使是死了,钉在棺材里了,也要在墓里,用这腐朽的声带喊出:████

原文地址

体验游戏

1. 扫码开始游戏,建议佩戴耳机。

2. 进入游戏首页,点一下你要选的女主即可进入不同分支。(默认冬马线)

项目源码:pixi-whitealbum

注意:PixiJS的基础知识,在前文已经介绍过了,所以不再累赘。

粒子背景

由于Pixi只是一个轻量级的渲染库,所以并没有提供给开发者一个内置的粒子特效库。因此,如果希望实现下面这个雪花背景,需要开发者自己编写代码。

作为一个代码粘贴复制搬运工,自己写当然是不可能的。在codepen上已经有了大量的canvas雪花特效,我们可以直接拿来参考。

不过codepen的示例基本都是原生Canvas API,如果改写成Pixi实现,依旧不能无脑copy。

原生API实现雪花的关键是:

function draw (obj) {
  // obj就是每一个雪花对象
  ctx.beginPath();
  ctx.strokeStyle = "transparent";
  ctx.fillStyle = "rgba(255,255,255,"+((0.5*Math.random())+0.5)+")";

  // 通过setInterval或者requestAnimationFrame方法不断改变obj.x obj.y来实现雪花飘落
  ctx.arc(obj.x,obj.y,obj.dia,0,2*Math.PI);
  ctx.closePath();
  ctx.stroke();
  ctx.fill();
}

而在Pixi中,我们可以在tick方法里不断改变图层的xy偏移量即可

let circle = new Graphics();
circle.beginFill(0xFFFFFF, obj.alpha);
// 0 0 位置写死即可
circle.drawCircle(0, 0, obj.dia);
circle.endFill();

// 通过tick方法不断改变circle的position来实现雪花飘落
circle.x = obj.x;
circle.y = obj.y;
parent.addChild(circle);

详情见源码

Pixi还特别提供了一个ParticleContainer类,如果发现粒子效果性能很差时,可以把大量的粒子或精灵放在这个父类里,而不是普通的Container类。

场景过度

场景切换就是很普通的透明度改变,可以使用TweenMax动画库

// 前一个场景淡出
TweenMax.to(preContainer, 0.5, { 
  alpha: 0,
  visible: false 
});
// 后一个场景淡入
TweenMax.to(currentContainer, 0.8, { alpha: 1 });

需要特别注意的是:透明度为0的图层一定要把visible设成false,否则该图层仍可以点击

音频播放

使用了pixi-sound,一个非常强大的音频库。

import { Loader } from 'pixi.js';
import sound from 'pixi-sound';

const loader = Loader.shared;

loader
  .add('bgm', 'https://pixijs.io/pixi-sound/examples/resources/boing.mp3')
  .load(() => {
    // 预加载完成后,自动播放
    sound.play('bgm', { loop: true });
  });

不过由于IOS和Chrome的安全限制,使用JS自动播放音频是被禁止的,必须通过用户触发事件,才能调用音频播放。

pixi-sound考虑到了这个场景,所以在源码中可以看到,它会对用户的第一次点击事件进行监听,通过播放一个空音频,确保加载的音频可以被正常播放。

布局

页面缩放,基于750px标准

const rootContainer = new Container();
app.stage.addChild(rootContainer);

// 相对于设计稿750px进行缩放(竖屏状态)
const screenScaleRito = window.innerWidth / 750;
rootContainer.scale.set(screenScaleRito);

// 由于宽度进行了缩放,所以实际的渲染高度
const finalHeight = window.innerHeight / screenScaleRito;

由于canvas布局不像css布局那样方便,所以居中布局,需要自己手动计算偏移量

// 渲染宽度
const renderWidth = 750;
const screenScaleRito = window.innerWidth / renderWidth;
// 渲染高度
const renderHeight = window.innerHeight / screenScaleRito;

const sprite = new Sprite(spriteTextures['touma.png']);
sprite.x = (renderWidth - sprite.width) / 2;
sprite.y = (renderHeight - sprite.height) / 2;

其他事项

图片精灵 可以使用Texture Packer软件,把多张图片合并成一张图片,方便管理。

图片分层

抠图以及去水印(别问抠图为啥用AE。。。)

Parcel的一些坑

因为用的是Parcel打包工具,所以基本0配置开发。不过Parcel.cache缓存经常出bug。如果你的代码出现了莫名的问题,可以试试删除该文件夹。

特意加了一个clean命令

"scripts": {
  "dev": "npm run clean && parcel public/index.html",
  "build": "npm run clean && parcel build public/index.html",
  "clean": "rimraf ./dist ./.cache",
  "prebuild": "echo ❄️❄️❄️又到了白色相簿的季节❄️❄️❄️",
  "postbuild": "echo ❄️❄️❄️你为什么那么熟练啊❄️❄️❄️",
}

还有就是Parcel开发时,经常报WebSocket is not open: readyState 2 (CLOSING)错误。

通常出现这种错误的情况是:你有大段的代码发生了改变。

瑕不掩疵,总的来说,Parcel还是不错的一款打包工具,虽然基本只会用在个人项目上,公司项目还是老老实实用webpack吧。

参考