前言
作为一枚菜鸟, 一直能喜欢做一些酷炫的动画特效, 但是一直没有机会接触到。直到前段时间,在猿创营中,跟着大帅的直播学习了一把刹车的动画效果后,有了这边文章记录一下自己的学习内容。
参考文档
- PIXI:pixijs.com/
- GSAP:greensock.com/docs/v3/GSA…
- 学习视频:www.bilibili.com/video/BV1q3…
我们看一下动画效果:
从上图的效果上, 我们可以看到要实现的效果:按钮有波纹状的效果和粒子快速滑动的效果,点击按钮有刹车动画,同时,粒子停住。放开按钮后,粒子恢复滑动。
在开始编码前,我们整理一下核心思路:
- 用PIXI创建根实例用来存放动画并挂载到dom上
- 创建主容器并加载到根实例上
- 通过loader加载图片资源
- 资源加载后并显示到页面上
- 开始使用gsap添加动画效果到按钮上并实现刹车效果
- 添加粒子并把它加载到页面上
- 让粒子快速滑动起来
- 点击按钮停止粒子动画
整理出上面的思路后,我们开始编码实现:
首先,我们先创建一个BrakeBanner类。在初始化的时候,创建一个根实例并将它挂载到页面上,这个根实例将用来存放各种需要添加的资源。具体代码如下:
class BrakeBanner{
constructor(selector){
// 创建实例
this.app = new PIXI.Application({
width: window.innerWidth,
height: window.innerHeight,
backgroundColor: 0xffffff,
resizeTo: window
})
// 挂载到dom上
document.querySelector(selector).appendChild(this.app.view)
this.stage = new PIXI.Container() // 容器
this.app.stage.addChild(this.stage) // 将新增容器添加到根容器上
}
}
接着,我们通过loader将图片资源引并显示到页面上,这里看一下具体如下:
addLoader() {
// 资源加载器
const loader = new PIXI.Loader()
// 资源入队
images.forEach(img => {
loader.add(img, `images/${img}`)
})
// 资源加载
loader.load()
// 加载完成后回调
loader.onComplete.add(() => {
this.show()
})
return loader
}
上面我们创建了一个addLoader方法,是用来加载所有的图片,然后我们在constructor中调用该方法:
constructor(selector){
//...省略部分代码...
this.loader = this.addLoader()
}
这样我们就把资源加载进来了。只是加载进来还是不够的,我们现在要把图片显示到页面上,所以这里我们增加一个方法show用来加图片加到页面上:
show() {
// 加载按钮图片并设置中心点
const imgContainer = this.createActionButton()
imgContainer.x = imgContainer.y = 400
const bikeContainer = new PIXI.Container()
this.stage.addChild(bikeContainer)
bikeContainer.scale.x = bikeContainer.scale.y = 0.3
const leverImage = new PIXI.Sprite(this.loader.resources['brake_lever.png'].texture)
bikeContainer.addChild(leverImage)
leverImage.pivot.x = leverImage.pivot.y = 455
leverImage.x = 722
leverImage.y = 900
const bikeImage = new PIXI.Sprite(this.loader.resources['brake_bike.png'].texture)
bikeContainer.addChild(bikeImage)
const handlerImage = new PIXI.Sprite(this.loader.resources['brake_handlerbar.png'].texture)
bikeContainer.addChild(handlerImage)
this.stage.addChild(imgContainer)
}
我们在show中调用了createActionButton方法,同时,通过PIXI.Container创建用来存放车体图片的容器。而12行则设置了刹车的中心点,13和14行则调整了它的坐标位置。那调用createActionButton方法是做了什么?我们先看一下代码:
createActionButton() {
// 加载按钮容器
const imgContainer = new PIXI.Container()
// 将按钮图片纹理加入到容器中
let btnImg = new PIXI.Sprite(this.loader.resources['btn.png'].texture)
imgContainer.addChild(btnImg)
let btnCircle = new PIXI.Sprite(this.loader.resources['btn_circle.png'].texture)
imgContainer.addChild(btnCircle)
let btnCircle2 = new PIXI.Sprite(this.loader.resources['btn_circle.png'].texture)
imgContainer.addChild(btnCircle2)
// 设置中心点
btnImg.pivot.x = btnImg.pivot.y = btnImg.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动画
gsap.to(btnCircle.scale, {
duration: 1,
x: 1.3,
y: 1.3,
repeat: -1
})
gsap.to(btnCircle, {
duration: 1,
alpha: 0,
repeat: -1
})
return imgContainer
}
createActionButton方法实际上是做了两件事情:将按钮的资源加载到容器上和给按钮添加波纹的效果。
3到17行的代码,都是拿到按钮的图片资源并添加到imgContainer的容器中,然后调整图片的中心点和坐标
20行之后的代码,则是通过gsap来实现波纹状的效果。
效果图如下:
**现在,**刹车和按钮都加载了,我们要实现刹车的动画了。在show方法中,我们添加一下鼠标事件,代码如下:
show() {
// ......
imgContainer.interactive = true
imgContainer.buttonMode = true
imgContainer.on('mousedown', () => {
gsap.to(leverImage, {
duration: .6,
rotation: Math.PI/180*-30,
})
})
imgContainer.on('mouseup', () => {
gsap.to(leverImage, {
duration: .6,
rotation: 0,
})
})
}
先给按钮(imgContainer)设置两个属性interactive 和buttonMode ,这样才能有交互效果,给它添加两个事件后,刹车动画就完成了,短短的几行代码就实现了。
效果图如下:
最后,就是把粒子的效果实现了。
还是在show方法,我们先把粒子创建出来:
show() {
//.....
// 创建粒子
let particleZoneSize = window.innerWidth
let particleContainer = new PIXI.Container()
this.stage.addChild(particleContainer)
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() * window.innerHeight,
gr
}
gr.x = parItem.sx
gr.y = parItem.sy
particleContainer.addChild(gr)
particles.push(parItem)
}
let zWidth = particleZoneSize/2
let zHeight = window.innerHeight / 2
particleContainer.pivot.set(zWidth,zWidth)
particleContainer.rotation = (35 * Math.PI) / 180
particleContainer.x = zWidth
particleContainer.y = zHeight
}
这里还是一样先创建一个容器particleContainer ,然后用PIXI.Graphics创建形状,beginFill填充颜色,调用drawCircle绘制粒子,最后用数组将粒子数据存放起来。
**现在,**我们已经创建粒子了,接下来就让他们动起来,代码如下:
show() {
// ....
let speed = 0
function loop() {
speed += .5
speed = Math.min(speed, 20)
for (let i = 0; i < particles.length; i++) {
let pItem = particles[i]
let gr = pItem.gr
gr.y += speed
if (speed >= 20) {
gr.scale.y = 40
gr.scale.x = .03
}
if (gr.y > window.innerHeight) {
gr.y = 0
}
}
}
function start() {
speed = 0
gsap.ticker.add(loop)
}
function pause() {
gsap.ticker.remove(loop)
for (let i = 0; i < particles.length; i++) {
let pItem = particles[i]
let gr = pItem.gr
gr.scale.y = 1
gr.scale.x = 1
gsap.to(gr, {
duration: .6,
x: pItem.sx,
y: pItem.sy,
ease: 'elastic.out'
})
}
}
start()
}
我们添加了start,pause和loop方法。最后调用了start方法,让粒子动起来。
其中,24行的代码里我们将loop添加到gsap的ticker中。
28行的代码里我们将loop移出ticker中。
同时将start和pause分别放到mouseup和mousedown事件中,具体如下:
// ...
imgContainer.on('mousedown', () => {
gsap.to(leverImage, {
duration: .6,
rotation: Math.PI/180*-30,
})
** pause()**
})
imgContainer.on('mouseup', () => {
gsap.to(leverImage, {
duration: .6,
rotation: 0,
})
**start()**
})
// ...
这样我们就实现了点击粒子停止,放开粒子快速滑动的效果。最终的效果就如同我们一进来的动态图一样。
至此,我们就可以用PIXI和gsap来愉快的实现我们的各种酷炫效果了。各种小伙伴快快用起来~~~
打开广告
在公众号里搜 大帅老猿,他做技术外包很靠谱