起因
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左右的延迟,也许不是最优方案,大家有更好的想法可以留言讨论哈。
最后
虽然不是第一次用类似的游戏引擎,但是对于各种定时器、公共方法的封装、实现思路的思路感觉自己还是有所欠缺。其中遇到的精灵层级、偶尔动画晃动的原因还是没有完美解决,希望自己以后可以多总结、思考,才能提高。