前言
写完业务代码,得空也在想再玩点什么,前不久留意到@大帅老猿的猿创营,激起了我这深度潜水党的兴趣。所以跟着大佬学习,来点缺啥补啥~
下面开始学习过程
准备基础环境
直接clone
大佬仓库,看看都给我们准备了什么github.com/ezshine/YCY…
项目很简单,引入了PIXI
和GSAP
两个库。一个是优秀的webGL2d
渲染引擎,一个是优秀的前端动画引擎。(都没用过,先跟着敲)
<script src="https://pixijs.download/release/pixi.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.10.4/gsap.min.js"></script>
创建PIXI应用
class BrakeBanner {
constructor(selector) {
// 初始化PIXI应用,将舞台设置为1920x1080
this.app = new PIXI.Application({
width: window.innerWidth,
height: window.innerHeight,
backgroundColor: 0xffffff,
resizeTo: window
})
document.querySelector(selector).appendChild(this.app.view);
this.stage = new PIXI.Container();
this.stage.sortableChildren = true
this.app.stage.addChild(this.stage);
}
}
加载图片资源
// 创建资源加载器
this.loader = new PIXI.Loader();
// 向资源加载器添加资源 key,path
this.loader.add('btn.png', 'images/btn.png');
this.loader.add('btn_circle.png', 'images/btn_circle.png');
this.loader.add('brake_bike.png', 'images/brake_bike.png');
this.loader.add('brake_handlerbar.png', 'images/brake_handlerbar.png');
this.loader.add('brake_lever.png', 'images/brake_lever.png');
this.loader.load();
this.loader.onComplete.add(() => {
//资源加载完给舞台添加内容
this.show();
})
添加按钮(简单的先来)
// 创建按钮容器
const btnContainer = new PIXI.Container();
this.stage.addChild(btnContainer);
// 通过图片创建精灵元素
const btnImage = new PIXI.Sprite(this.loader.resources['btn.png'].texture);
btnContainer.addChild(btnImage);
const btnCircleImage = new PIXI.Sprite(this.loader.resources['btn_circle.png'].texture);
btnContainer.addChild(btnCircleImage)
效果如下
设置转换中心点
//设置转换中心点
btnImage.pivot.x = btnImage.pivot.y = btnImage.width / 2;
btnCircleImage.pivot.x = btnCircleImage.pivot.y = btnCircleImage.width / 2;
btnContainer.x = 200;
btnContainer.y = 200;
btnCircleImage.scale.x = btnCircleImage.scale.y = .8;
初尝GSAP动效
gsap.to(btnCircleImage, { duration: 1, alpha: 0, repeat: -1 });
gsap.to(btnCircleImage.scale, { duration: 1, x: 1.1, y: 1.1, repeat: -1 })
把按钮相关代码整合到createActionButton 函数中
按钮效果就完成啦,如下
添加车架和刹车把手
车架
const bikeContainer = new PIXI.Container();
this.stage.addChild(bikeContainer);
// 整体进行一个缩放
bikeContainer.scale.x = bikeContainer.scale.y = .3;
bikeContainer.zIndex = 3
const bikeImage = new PIXI.Sprite(this.loader.resources['brake_bike.png'].texture);
bikeContainer.addChild(bikeImage)
const bikeHanderImage = new PIXI.Sprite(this.loader.resources['brake_handlerbar.png'].texture);
bikeContainer.addChild(bikeHanderImage)
刹车把手
const bikeLeverImage = new PIXI.Sprite(this.loader.resources['brake_lever.png'].texture);
bikeContainer.addChild(bikeLeverImage)
bikeLeverImage.x = 255 + 454;
bikeLeverImage.y = 450 + 462;
bikeLeverImage.pivot.x = 454;
bikeLeverImage.pivot.y = 462;
bikeLeverImage.rotation = 0;
再设置一下按钮容器和自行车容器的层级,把按钮放在顶层
// 设置按钮层级
actionBtn.zIndex = 3
// 设置自行车层级
bikeContainer.zIndex = 2
这样车和按钮就可以啦
添加按钮交互,实现捏刹车/松刹车
actionBtn.on("mousedown",()=>{
bikeLeverImage.rotation = Math.PI/180*-35;
})
actionBtn.on("mouseup",()=>{
bikeLeverImage.rotation = 0;
})
加入GSAP
actionBtn.on("mousedown",()=>{
gsap.to(bikeLeverImage,{duration:.6,rotation : Math.PI/180*-35});
})
actionBtn.on("mouseup",()=>{
gsap.to(bikeLeverImage,{duration:.6,rotation : 0});
})
这会就完成了按钮效果
调整下位置
let resize = () => {
bikeContainer.x = window.innerWidth - bikeContainer.width;
bikeContainer.y = window.innerHeight - bikeContainer.height;
}
window.addEventListener('resize', resize);
resize();
速度粒子效果
先看一下需求
- 首先得要有粒子,也就是小圆点
- 小圆点的颜色有好几种
- 向某一个角度一直移动
- 超出底部边界后回到顶部继续移动
- 按住鼠标停止
- 停止的时候还有一点回弹的效果
- 松开鼠标继续
OK,一条一条来实现
创建粒子容器和对象数组
let particleZoneSize = window.innerWidth;
let particlesContainer = new PIXI.Container();
this.stage.addChild(particlesContainer);
let particles = [];
const colors = [0xf1cf54, 0xb5cea8, 0xf1cf54, 0x818181, 0x000000];
for (let i = 0; i < 10; i++) {
let gr = new PIXI.Graphics();
gr.beginFill(colors[Math.floor(Math.random() * colors.length)]);
gr.drawCircle(0, 0, 6);
gr.endFill();
let parItem = {
sx: Math.random() * particleZoneSize,
sy: Math.random() * particleZoneSize,
}
gr.x = parItem.sx;
gr.y = parItem.sy;
gr.zIndex = 1
particles.push({...parItem,gr})
particlesContainer.addChild(gr);
}
粒子随机颜色
const colors = [0xf1cf54, 0xb5cea8, 0xf1cf54, 0x818181, 0x000000];
for(let i=0;i<10;i++){
//...
gr.beginFill(colors[Math.floor(Math.random() * colors.length)]);
//...
让粒子动起来
首先还是理解需求,想象正在骑自行车。我们速度越来越快直到到达最大速度,接着就是匀速运动。那速度越来越快时,我们观察到的粒子就快产生拖影,它在视觉上是被拉长变细的
let speed = 0
function loop() {
speed += .5;
speed = Math.min(speed, 20);
for (let i = 0; i < particles.length; i++) {
//拿到粒子item和小圆点实例
let pItem = particles[i];
let gr = pItem.gr;
//让粒子走起来
gr.y += speed;
if (speed >= 20) {
gr.scale.y = 40;
gr.scale.x = 0.03
}
//当粒子移动超出范围时回到顶部
if (gr.y > innerWidth) gr.y = 0;
}
}
gsap.ticker.add(loop);
等等,好像角度不太对
particlesContainer.pivot.set(particleZoneSize / 2, particleZoneSize / 2);
particlesContainer.rotation = (35 * Math.PI) / 180;
particlesContainer.x = particleZoneSize / 2;
particlesContainer.y = particleZoneSize / 2;
现在可以了
现在我们要实现开始停止并把它和刹车联系起来
开始粒子运动
function start(){
speed = 0;
gsap.ticker.add(loop);
}
停止粒子运动
function pause() {
//先移除掉requestAnimationFrame的侦听
gsap.ticker.remove(loop);
for (let i = 0; i < particles.length; i++) {
let pItem = particles[i];
let gr = pItem.gr;
//恢复小圆点的拉伸比例
gr.scale.x = gr.scale.y = 1;
//恢复小圆点透明度
gr.alpha = 1;
//让所有的小圆点使用弹性补间动画回到初始坐标
gsap.to(gr, {
duration: 0.6,
x: pItem.sx,
y: pItem.sy,
ease: "elastic.out",
});
}
}
关联按钮
actionBtn.on("mousedown", () => {
bikeLeverImage.rotation = Math.PI / 180 * -35;
gsap.to(bikeLeverImage, { duration: .6, rotation: Math.PI / 180 * -35 });
pause()
})
actionBtn.on("mouseup", () => {
bikeLeverImage.rotation = 0;
gsap.to(bikeLeverImage, { duration: .6, rotation: 0 });
start()
})
这就实现完了
最终效果
写在最后
好多小伙伴都跟着大帅老师实现啦,赶个晚集~
第一篇文章写的水了点,就当补的作业了。
还是比较喜欢猿创营
的形式的,既能学习很多前端知识还能学到真实项目内容。
感谢大帅老师的讲解,在公众号里搜 大帅老猿
,在他这里可以学到很多东西。