最近加入了大帅老师带领的猿创营
学习,在看完大帅在哔哩哔哩的直播后,自己也动手实现了该动效。尝试写一下软文记录自己的收获与成长(第一次在掘金(网上)发表文章,其实心里慌得一批)。
准备工作
- 到大帅老师的github仓库把工程克隆到本地。
- 修改 src/index.html 下的 pixi.js 引用路径。(因为 pixi 更新了方法有所改变,换回旧版就可以了)
- 在 vscode 安装微软的 Live Preview 插件,该插件可以在编辑器里面实时的预览代码的执行结果。
初始化页面
// index.html
<html>
<head>
<title>猿创营</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,minimum-scale=1.0,user-scalable=no">
<style type="text/css">
html,
body {
margin: 0;
padding: 0;
}
div {
width: 100%;
}
</style>
<script src="https://pixijs.download/v6.5.8/pixi.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.10.4/gsap.min.js"></script>
<script src="./js/brakebanner.js"></script>
<script>
window.onload = init;
function init() {
let banner = new BrakeBanner("#brakebanner");
}
</script>
</head>
<body>
<div id="brakebanner"></div>
</body>
</html>
创建PIXI应用
// brakebanner.js
class BrakeBanner {
constructor(selector) {
this.app = new PIXI.Application({
width: window.innerWidth,
height: window.innerHeight,
backgroundColor: 0xff0000,
resizeTo: window,
});
document.querySelector(selector).appendChild(this.app.view);
}
}
效果如下
引入素材
// brakebanner.js
class BrakeBanner {
constructor(selector) {
...省略未改动代码
backgroundColor: 0xffffff, // 背景改为白色
});
...省略未改动代码
this.stage = this.app.stage;
this.loader = new PIXI.Loader();
// 添加素材
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");
// 执行 load 方法加载素材
this.loader.load();
// 添加回调函数,待加载完素材后显示素材
this.loader.onComplete.add(() => {
this.show(); // 执行 show 方法显示素材
});
}
}
添加 show 方法
// brakebanner.js
class BrakeBanner {
...省略未改动代码
show(){
// 创建 bike
let bikeContainer = this.createBikeContainer();
// 调整 bike 大小
bikeContainer.scale.x = bikeContainer.scale.y = 0.3;
// 把 bike 添加到场景
this.stage.addChild(bikeContainer);
// 创建按钮
let actionButton = this.createActionButton();
// 调整按钮位置
actionButton.x = actionButton.y = 300;
// 把按钮添加到场景
this.stage.addChild(actionButton);
// 添加按钮互动效果
actionButton.interactive = true;
actionButton.buttonMode = true;
// 调整 bike 位置
// 添加 resize 方法
let resize = () => {
bikeContainer.x = window.innerWidth - bikeContainer.width;
bikeContainer.y = window.innerHeight - bikeContainer.height;
};
// 添加 resize 监听事件
window.addEventListener("resize", resize);
// 执行 resize 方法
resize();
}
}
添加 createBikeContainer 方法
// brakebanner.js
class BrakeBanner {
...省略未改动代码
createBikeContainer() {
// 创建容器
let bikeContainer = new PIXI.Container();
// 创建精灵
let bikeImage = new PIXI.Sprite(
this.loader.resources["brake_bike.png"].texture
);
let bikeHandlerbarImage = new PIXI.Sprite(
this.loader.resources["brake_handlerbar.png"].texture
);
let bikeLeverImage = new PIXI.Sprite(
this.loader.resources["brake_lever.png"].texture
);
// 把精灵添加到容器
bikeContainer.addChild(bikeImage);
bikeContainer.addChild(bikeLeverImage);
bikeContainer.addChild(bikeHandlerbarImage);
// 调整把手轴心
bikeLeverImage.pivot.x = bikeLeverImage.pivot.y = 455;
// 调整把手位置
bikeLeverImage.x = 722;
bikeLeverImage.y = 900;
return bikeContainer;
}
}
添加 createActionButton 方法
// brakebanner.js
class BrakeBanner {
...省略未改动代码
createActionButton() {
// 创建容器
let actionButton = new PIXI.Container();
// 创建精灵
let btnImage = new PIXI.Sprite(this.loader.resources["btn.png"].texture);
let btnCircleImage = new PIXI.Sprite(
this.loader.resources["btn_circle.png"].texture
);
let btnCircleImage2 = new PIXI.Sprite(
this.loader.resources["btn_circle.png"].texture
);
// 把精灵添加到容器
actionButton.addChild(btnImage);
actionButton.addChild(btnCircleImage);
actionButton.addChild(btnCircleImage2);
// 调整精灵轴心
btnImage.pivot.x = btnImage.pivot.y = btnImage.width / 2;
btnCircleImage.pivot.x = btnCircleImage.pivot.y = btnCircleImage.width / 2;
btnCircleImage2.pivot.x = btnCircleImage2.pivot.y = btnCircleImage2.width / 2;
// 缩小 btnCircleImage
btnCircleImage.scale.x = btnCircleImage.scale.y = 0.8;
return actionButton;
}
}
效果如下
添加按钮动效
修改 createActionButton 方法
createActionButton() {
...省略未改动代码
// 添加 gsap 动效
gsap.to(btnCircleImage.scale, {
duration: 1, // 动效时长
x: 1.3, // x 缩放比例
y: 1.3, // y 缩放比例
repeat: -1, // 无限循环
});
gsap.to(btnCircleImage, {
duration: 1, // 动效时长
alpha: 0, // 透明度
repeat: -1, // 无限循环
});
...省略未改动代码
}
效果如下
添加把手互动
修改 show 方法
show() {
...省略未改动代码
// 添加鼠标按下事件
actionButton.on("mousedown", () => {
// 添加动效---把手逆时针旋转30°
gsap.to(bikeContainer.children[1], {
duration: 0.6,
rotation: (Math.PI / 180) * -30,
});
});
// 添加鼠标抬起事件
actionButton.on("mouseup", () => {
// 添加动效---把手复原
gsap.to(bikeContainer.children[1], {
duration: 0.4,
rotation: 0,
});
});
...省略未改动代码
}
效果如下
添加速度线动效
创建粒子
show() {
...省略未改动代码
// 创建粒子容器
let particleContainer = new PIXI.Container();
// 把粒子容器添加到场景
this.stage.addChild(particleContainer);
// 调整容器轴心
particleContainer.pivot.x = window.innerWidth / 2;
particleContainer.pivot.y = window.innerHeight / 2;
// 调整容器位置
particleContainer.x = window.innerWidth / 2;
particleContainer.y = window.innerHeight / 2;
// 旋转容器
particleContainer.rotation = (Math.PI / 180) * 35;
// 粒子数组
let particles = [];
// 粒子颜色
let colors = [0xf1cf54, 0xb5cea8, 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, 4);
gr.endFill();
// 粒子初始信息
let pItem = {
sx: Math.random() * window.innerWidth,
sy: Math.random() * window.innerHeight,
gr: gr,
};
// 调整粒子位置
gr.x = pItem.sx;
gr.y = pItem.sy;
// 添加到容器
particleContainer.addChild(gr);
// 添加到数组
particles.push(pItem);
}
}
添加粒子动效
show() {
...省略未改动代码
// 设置初始速度
let speed = 0;
// 添加动效方法
function loop() {
speed += 0.5;
// 设置速度最大值
speed = Math.min(speed, 20);
for (let i = 0; i < particles.length; i++) {
let pItem = particles[i];
// 让粒子动起来
pItem.gr.y += speed;
// 粒子移动速度大于等于20时形状变化
if (speed >= 20) {
pItem.gr.scale.y = 40; // y 拉长至 40
pItem.gr.scale.x = 0.06; // x 压缩至 0.06
}
// 粒子超出屏幕高度返回最高点
if (pItem.gr.y > window.innerHeight) pItem.gr.y = 0;
}
}
// 添加 start 方法
function start() {
// 初始化速度
speed = 0;
// 添加 gsap 动效
gsap.ticker.add(loop);
}
// 执行 start 方法
start();
}
添加按钮互动
show() {
...省略未改动代码
// 修改鼠标按下事件
actionButton.on("mousedown", () => {
...省略未改动代码
pause();
});
// 修改鼠标抬起事件
actionButton.on("mouseup", () => {
...省略未改动代码
start();
});
// 添加 pause 方法
function pause() {
// 移除粒子动效
gsap.ticker.remove(loop);
for (let i = 0; i < particles.length; i++) {
let pItem = particles[i];
// 复原粒子
pItem.gr.scale.x = 1;
pItem.gr.scale.y = 1;
// 添加粒子停止回弹动效
gsap.to(pItem.gr, {
duration: 0.6,
x: pItem.sx,
y: pItem.sy,
ease: "elastic.out",
});
}
}
...省略未改动代码
}
最终效果
总结
- 通过学习大帅老师的刹车动效项目后,我对pixi.js、gsap.js有了初步的认识。
- 填补了我对 canvas 或 css 动画这类技术的不足。
- 要多了解一些国外比较优秀的技术。
- 在公众号里搜
大帅老猿
,在他这里可以学到很多东西!