PIXI+GSAP 编写超酷炫自行车刹车特效 | 猿创营
涉及技术
使用 PIXI 用来制作视觉动画,官方文档:pixijs.com/ 使用 GSAP 用来优化动画特效,官方文档:greensock.com/docs/v3/GSA… 使用 vscode 编写代码,推荐安装插件 Live preview,可以本地预览页面,方便调试
项目总览
预览地址:ml1234256.github.io/YCY-Trainin… github:github.com/ml1234256/Y… 动画特效为三个部分:按钮,自行车,背景粒子 项目目录结构如下
加载图片资源
使用 load 加载图片资源
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')
this.loader.load()
制作按钮
创建按钮容器,加载按钮图片,设置动效
const actionButton = 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)
actionButton.addChild(btn, btnCircle)
btn.pivot.x = btn.pivot.y = btn.width / 2
btnCircle.pivot.x = btnCircle.pivot.y = btnCircle.width / 2
btnCircle.scale.x = btnCircle.scale.y = 0.8
// 设置动画
gsap.to(btnCircle.scale, { duration: 1, x: 1.3, y: 1.3, repeat: -1 })
gsap.to(btnCircle, {duration: 1, alpha: 0, repeat: -1})
制作自行车
创建自行车容器,加载自行车各部件图片
const bikeContainer = new PIXI.Container()
bikeContainer.scale.x = bikeContainer.scale.y = 0.2
const brakeBikeImage = new PIXI.Sprite(this.loader.resources['brake_bike.png'].texture)
const brakeLevelImage = new PIXI.Sprite(this.loader.resources['brake_lever.png'].texture)
const brakeHanderbarImage = new PIXI.Sprite(this.loader.resources['brake_handlerbar.png'].texture)
bikeContainer.addChild(brakeBikeImage,brakeLevelImage, brakeHanderbarImage)
this.stage.addChild(bikeContainer, actionButton)
// 设置把手旋转中心,固定把手位置
brakeLevelImage.pivot.x = brakeLevelImage.pivot.y = 455
brakeLevelImage.x = 722
brakeLevelImage.y = 900
添加车把动效
将把手动效促发事件绑定到按钮上,当按下按钮时,把手向下旋转,松开按钮时,把手恢复原位
// 设置把手动画
actionButton.interactive = true
actionButton.buttonMode = true
actionButton.on('mousedown', () => {
gsap.to(brakeLevelImage, {duration:.3, rotation: Math.PI/180*-30})
})
actionButton.on('mouseup', () => {
sap.to(brakeLevelImage, {duration:.3, rotation: 0})
})
添加背景粒子动效
加载粒子:创建粒子容器,创建10个粒子,加入到容器中
const 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 = 35 * Math.PI /180
const 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()
// 粒子运动初始坐标
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)
}
添加动效:设置粒子向下运动,再将容器旋转,使得粒子向左下角运动 优化动效:将粒子在x轴方向上缩小至0.03倍,y轴方向上放大至40倍,设置速度由快倒慢
// 让粒子向下运动
let speed = 0
const 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
if (speed >= 20) {
pItem.gr.scale.x = 0.03
pItem.gr.scale.y = 40
}
f (pItem.gr.y > window.innerHeight) pItem.gr.y = 0
}
}
const start = () => {
speed = 0
gsap.ticker.add(loop)
}
const parse = () => {
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'})
}
}
设置按下按钮粒子停止运动,松开按钮粒子恢复运动
actionButton.on('mousedown', () => {
gsap.to(brakeLevelImage, {duration:.3, rotation: Math.PI/180*-30})
parse()
})
actionButton.on('mouseup', () => {
gsap.to(brakeLevelImage, {duration:.3, rotation: 0})
start()
})
最后
感谢大帅给的这次学习机会,收获很多。在公众号里搜 大帅老猿
,在他这里能学到很多东西。
转载自:https://juejin.cn/post/7126133624029577252