手摸手教你使用 Pixi.js + Gsap.js 入门2d动画制作--自行车刹车动效
一、效果预览
二、开撸代码
开局我们的代码如下
class BrakeBanner{
constructor(selector){
}
}
1. 创建我们的视图,设置白底背景
constructor() {
this.app = new PIXI.Application({
width: window.innerWidth,
height: window.innerHeight,
backgroundColor: 0xffffff,
resizeTo: window,
});
this.stage = this.app.stage;
const el = document.querySelector(selector);
el.appendChild(this.app.view)
this.loadResource();
}
2. 加载我们需要的图片资源
loadResource() {
this.loader = new PIXI.Loader();
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.add("btn_circle.png", "images/btn_circle.png");
this.loader.add("btn.png", "images/btn.png");
this.loader.load();
this.loader.onComplete.add(() => {
this.show();
})
}
3. 创建按钮和按钮动效
show() {
// 创建按钮
this.createActionButton();
}
createActionButton() {
const btnContainer = new PIXI.Container();
// 创建按钮和按钮外围的圈
const btn = new PIXI.Sprite(this.loader.resources['btn.png'].texture);
const btnCircle = new PIXI.Sprite(this.loader.resources['btn_circle.png'].texture);
const btnCircle2 = new PIXI.Sprite(this.loader.resources['btn_circle.png'].texture);
btnContainer.addChild(btn);
btnContainer.addChild(btnCircle);
btnContainer.addChild(btnCircle2);
// 设置按钮和圆圈的中心点
btn.pivot.x = btn.pivot.y = btn.width / 2;
btnCircle.pivot.x = btnCircle.pivot.y = btnCircle.width / 2;
btnCircle2.pivot.x = btnCircle2.pivot.y = btnCircle2.width / 2;
// 其中一个圆圈要设置一个动效
btnCircle.scale.x = btnCircle.scale.y = 0.8;
gsap.to(btnCircle.scale, { duration: 1, x: 1.2, y: 1.2, repeat: -1 });
gsap.to(btnCircle, { duration: 1, alpha: 0, repeat: -1 });
// 设置按钮手指移动上去时鼠标变为可点击
btnContainer.interactive = true;
btnContainer.buttonMode = true;
this.stage.addChild(btnContainer);
this.btnContainer = btnContainer;
}
这时候就可以在屏幕中间看到一个按钮
4. 加载自行车主体
我们将自行车车体,车把手和刹车手柄都加载进来,并且调整好位置,因为PIXI显示的层级关系是根据添加到stage的顺序有关,我们先加载自行车,再加载按钮,又因为我们的图片切图的原因,我们必须将自行车固定在右下角
show() {
// 创建自行车主体
this.createBicycle();
// 创建按钮
this.createActionButton();
this.fixBibybleToRightBottom();
}
createBicycle() {
const bicycleContainer = new PIXI.Container();
bicycleContainer.scale.x = bicycleContainer.scale.y = 0.3;
// 车身,包含车轮
const brakeBike = new PIXI.Sprite(this.loader.resources['brake_bike.png'].texture);
// 车把手
const brakeHandlerBar = new PIXI.Sprite(this.loader.resources['brake_handlerbar.png'].texture);
// 刹车手柄
const brakeLever = new PIXI.Sprite(this.loader.resources['brake_lever.png'].texture);
bicycleContainer.addChild(brakeBike);
bicycleContainer.addChild(brakeLever);
bicycleContainer.addChild(brakeHandlerBar);
brakeLever.x = 722;
brakeLever.y = 900;
this.brakeLever = brakeLever;
this.bicycleContainer = bicycleContainer;
this.stage.addChild(bicycleContainer);
}
fixBibybleToRightBottom() {
const resize = () => {
this.bicycleContainer.x = window.innerWidth - this.bicycleContainer.width;
this.bicycleContainer.y = window.innerHeight - this.bicycleContainer.height;
this.btnContainer.x = this.bicycleContainer.x + this.bicycleContainer.width / 2;
this.btnContainer.y = this.bicycleContainer.y + this.bicycleContainer.height / 2;
}
window.addEventListener('resize', resize);
resize();
}
5. 给按钮绑定按下和松开的动效
我们给刹车手柄设置旋转中心为图片的右下角,鼠标按下的时候,刹车手柄就旋转,鼠标松开,刹车手柄就旋转回正
show() {
// 创建自行车主体
this.createBicycle();
// 创建按钮
this.createActionButton();
// 绑定事件
this.bindEvent();
}
bindEvent() {
this.brakeLever.pivot.x = 455;
this.brakeLever.pivot.y = 455;
// 给按钮加上事件,按下的时候捏紧刹车,松开则慢慢回正
this.btnContainer.on("mousedown", () => {
gsap.to(this.brakeLever, { duration: 0.5, rotation: Math.PI / 180 * -30 });
});
this.btnContainer.on("mouseup", () => {
gsap.to(this.brakeLever, { duration: 0.5, rotation: 0 });
});
}
6. 模拟自行车骑行
我们想要让自行车有一个动起来的效果,按刹车的时候就停下来,最好的方法就是加个参照物,我们给页面加上一些粒子效果,并且让粒子动起来,我们有几个思路
- 创建一批小圆点,位置随机,将小圆点都放到一个容器里,将容器放到页面,并且旋转一定的角度
- 小圆点有一个加速,一直往容器向下的方向运动,速度越来越快,变运动,粒子慢慢变形变拉长的效果
- 在上诉按下和松开的基础上,新增效果:按下的时候,粒子变回原位,松开粒子又重新动起来
constructor(selector) {
...
this.particleLoop = this.particleLoop.bind(this)
}
show() {
// 创建粒子动效
this.createParticle();
// 创建自行车主体
this.createBicycle();
// 创建按钮
this.createActionButton();
// 绑定事件
this.bindEvent();
// 开始骑行
this.particleStart();
}
createParticle() {
const particleContainer = new PIXI.Container();
particleContainer.rotation = Math.PI / 180 * 35;
particleContainer.pivot.x = window.innerWidth / 2;
particleContainer.pivot.y = window.innerHeight / 2;
particleContainer.x = window.innerWidth / 2;
particleContainer.y = window.innerHeight / 2;
const particles = [];
const colors = [0xf1cf54, 0xb5cea8, 0xf1cf54, 0x818181, 0x000000];
const len = parseInt(Math.random() * 20) + 20;
for (let i = 0; i < len; i++) {
const gr = new PIXI.Graphics();
const idx = Math.floor(Math.random() * colors.length);
gr.beginFill(colors[idx]);
gr.drawCircle(0, 0, 6);
gr.endFill();
const 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);
}
this.stage.addChild(particleContainer);
this.particles = particles;
}
particleStart() {
this.speed = 0;
gsap.ticker.add(this.particleLoop);
}
particlePause() {
gsap.ticker.remove(this.particleLoop);
for (const pItem of this.particles) {
gsap.to(pItem.gr, {
duration: 0.3,
x: pItem.sx,
y: pItem.sy,
ease: 'elastic.out'
});
gsap.to(pItem.gr.scale, {
duration: 0.3,
x: 1,
y: 1,
});
}
}
particleLoop() {
let speed = this.speed;
speed += 0.2;
speed = Math.min(speed, 20);
for (const pItem of this.particles) {
pItem.gr.y += speed;
if (pItem.gr.y >= window.innerHeight) {
pItem.gr.y = 0;
}
pItem.gr.scale.x = Math.max(-0.1 * speed + 1, 0.03);
pItem.gr.scale.y = Math.min(5 * speed + 1, 30);
}
this.speed = speed;
}
bindEvent() {
this.brakeLever.pivot.x = 455;
this.brakeLever.pivot.y = 455;
// 给按钮加上事件,按下的时候捏紧刹车,松开则慢慢回正
this.btnContainer.on("mousedown", () => {
gsap.to(this.brakeLever, { duration: 0.5, rotation: Math.PI / 180 * -30 });
this.particlePause();
});
this.btnContainer.on("mouseup", () => {
gsap.to(this.brakeLever, { duration: 0.5, rotation: 0 });
this.particleStart();
});
}
三、结尾
到此我们的功能就实现了 完整的代码在 github
在公众号里搜 大帅老猿
,在他这里可以学到很多东西