PixiJS 实现娃娃机

1,894 阅读3分钟

起因

2018年俄罗斯世界杯,公司说要和俄罗斯世界杯合作搞一场大型的营销活动,为了增加用户的互动和体现世界杯的元素,经过设计师和运营人员的反复敲定,这个活动就这样诞生了,设计简图如下:

娃娃机

前端游戏引擎

因为之前用 CreateJS 做过一个简单的交互类游戏,它主要是4个主要组件:EaselJS、TweenJS、SoundJS、PreloadJS,它可以进行短期快速简单的开发,但社区活跃度不高、性能等问题让我没有继续用的想法。经过同事推荐,PixiJS 引起了我的注意,而且这两者对于主要对象定义也很类似,有了前者的基础,入手也比较快,代码维护性也高。而对于这种我没用过的库,我都有一种想试一试的冲动,好奇和探究感觉是最有意思的。

正式开始

创建画布和绘制舞台stage

let app = new PIXI.Application({
    width: 667, 
    height: 472,
    transparent: true,
    resolution: 1,
});
document.body.appendChild(app.view);

缓存图片资源

使用canvas绘制图片的时候,需要图片提前加载完成

PIXI.loader.add([
    { name: 'paw', url: '',}
    { name: 'convey', url: '',}
    ...
])
.on("progress", loadProgressHandler) // 监视加载进程
.load(setup);

绘制精灵

function loadProgressHandler (loader, resource) { 
    console.log("loading: " + resource.url);
    console.log("progress: " + loader.progress + "%");
}
funtion setup() {
    let paw = new PIXI.Sprite(PIXI.loader.resources.paw.texture);  // 爪子
    paw.x = 0;   // 精灵的位置(以画布左上角为中心点)
    pax.y = 0;
    let convey = new PIXI.Sprite(PIXI.loader.resources.convey.texture); // 传送带
    elemtScale([paw, convey]); // 精灵缩放比例
    app.stage.addChild(paw, convey); // 把绘制的图片加入舞台
    ...
}
// 精灵缩放比例
elemtScale(arr) {
    const bit = window.innerWidth / 375;  // 750的设计图
    for (let i = 0; i < arr.length; i += 1) {
        arr[i].scale.set(bit, bit);
    }
},

这时候你需要的图片和娃娃机的大概布局已经显示在画布了。

实现动画

PixiJs 的FPS是60帧 提供了ticker方法,就是每一秒刷新舞台60次。

function setup() {
    app.ticker.add(() => gameLoop(delta));
}
let speed = 5;
gameLoop() {
    paw += speed;
}

需求与思考

为了满足运营方的需求,在保证两排娃娃一直在匀速运动的同时,当按下按钮时,要保证爪子能正好抓到娃娃的头而实现娃娃抓住的效果。

我的思路

在基于娃娃匀速移动,爪子向下移动的速度不变的情况下,当按下按钮的那一刻,首先确定要抓起来的是哪个娃娃来倒推计算。爪子到达娃娃顶部所需的时间t1与距离s1,来反算在同样时间娃娃所走过的距离s1,来取大于等于s1距离最近的娃娃为被抓起来的娃娃。而这段时间差,而让爪子延迟下落,实现正好抓住娃娃头的方案。(不知道我说的明白不明白)

这种方案可能会让用户感觉有0.5s左右的延迟,也许不是最优方案,大家有更好的想法可以留言讨论哈。

最后

虽然不是第一次用类似的游戏引擎,但是对于各种定时器、公共方法的封装、实现思路的思路感觉自己还是有所欠缺。其中遇到的精灵层级、偶尔动画晃动的原因还是没有完美解决,希望自己以后可以多总结、思考,才能提高。