动效分享,用PixiJS和GsapJS制作刹车动效| 猿创营

2,709 阅读3分钟

前言

事情是这样的,最近加入了创业、兼职、学习氛围浓厚的群。看到了很多有趣的案例,跟着大佬学习了一些有意思的东西,所以呢,想着来分享这个使用PIXI+GSAP实现的刹车动效案例。

最终效果

那咋们直接上图看效果

sss.gif

基础环境

准备好两个库,一个就是PixiJS,是一个非常优秀的2d WebGL 渲染引擎,官网链接:pixijs.com/。另一个就是动画引擎库Gsap,官网链接:greensock.com/docs/v3/GSA…。话不多说,接下来开始上代码。

初始化页面,创建PIXI应用

<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/release/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>
//brakebanner.js
class BrakeBanner {
  constructor(selector) {
    this.app = new PIXI.Application({
      width: window.innerWidth,
      height: window.innerHeight,
      backgroundColor: 0xf0f0f0,
      resizeTo: window
    })
    document.querySelector(selector).appendChild(this.app.view)
    //创建舞台
    this.stage = new PIXI.Container();
  }
}

加载静态资源

//创建加载器
this.loader = new PIXI.Loader()
this.loader.add('btn.png', 'images/btn.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.add('btn_circle.png', 'images/btn_circle.png')
this.loader.load()
​
//加载完成
this.loader.onComplete.add(() => {
     this.show()
})

绘画出车架和刹车把手

先把给个部位画出来,这里面有个小小点:谁最后addchild到容器中,谁的层级相对较高。

//创建容器
const bikeContainer = new PIXI.Container()
bikeContainer.scale.x = bikeContainer.scale.y = 0.3
//加载车架资源并且添加进容器中
const bikeImage = new PIXI.Sprite(
  this.loader.resources['brake_bike.png'].texture
)
bikeContainer.addChild(bikeImage)
//加载刹车并且添加进容器中
const bikeLeverBarImage = new PIXI.Sprite(
  this.loader.resources['brake_lever.png'].texture
)
bikeContainer.addChild(bikeLeverBarImage)
​
//修改刹车的中心点和x,y轴的位置
bikeLeverBarImage.pivot.x = 455
bikeLeverBarImage.pivot.y = 455
bikeLeverBarImage.x = 722
bikeLeverBarImage.y = 900
​
//加载车把手并且添加进容器中
const bikeHanderBarImage = new PIXI.Sprite(
  this.loader.resources['brake_handlerbar.png'].texture
)
bikeContainer.addChild(bikeHanderBarImage)
​
//设置容器的位置
const resize = () => {
  bikeContainer.x = window.innerWidth - bikeContainer.width
  bikeContainer.y = window.innerHeight - bikeContainer.height
}
resize()
window.addEventListener('resize', resize)
​
this.stage.addChild(bikeContainer)

实现按钮效果

仔细上面动图,按钮是有一个波纹弹出的效果,并且点击的时候也会触发刹车,接下来我们实现一下。

createActionButton() {
    /** 创建一个按钮容器 */
    let actionButton = new PIXI.Container()
​
    /** 获取到按钮容器里面的元素 */
    let btnImage = new PIXI.Sprite(this.loader.resources['btn.png'].texture)
    let btnCircle = new PIXI.Sprite(
      this.loader.resources['btn_circle.png'].texture
    )
    let btnCircle2 = new PIXI.Sprite(
      this.loader.resources['btn_circle.png'].texture
    )
​
    /** 在按钮容器添加元素 */
    actionButton.addChild(btnImage)
    actionButton.addChild(btnCircle)
    actionButton.addChild(btnCircle2)
​
    /** 按钮容器里面的元素设置位置 */
    btnImage.pivot.x = btnImage.pivot.y = btnImage.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.3, y: 1.3, repeat: -1 })
    gsap.to(btnCircle, { duration: 1, alpha: 1, alpha: 0, repeat: -1 })
​
    this.stage.addChild(actionButton)
    return actionButton
  }
}

给按钮添加事件,加入刹车片的动效,这就有刹车的感觉了

 actionButton.on('mousedown', () => {
    gsap.to(bikeLeverBarImage, {
      duration: 0.1,
      rotation: (Math.PI / 180) * -30
    })
  })
​
  actionButton.on('mouseup', () => {
    gsap.to(bikeLeverBarImage, {
      duration: 0.3,
      rotation: 0
    })
  })

车辆启动的粒子效果

接下来就到了最有意思的环节,先看看上面动图,看看那些线条是如何动的。

  • 粒子 有多个颜色
  • 向某一个角度持续移动
  • 超出边界后回到顶部继续移动
  • 按住鼠标停止的时候会有一点回弹的效果
  • 松开鼠标继续

创建🌰(粒子)容器和对象数组

 //创建粒子容器
let particleContainer = new PIXI.Container()
this.stage.addChild(particleContainer)
​
//对象数组
let particles = []
//粒子颜色
const colors = [0xf1cf54, 0xb5cea8, 0xf1cf54, 0x818181, 0x000000]
//遍历创建多个
for (let i = 0; i < 20; i++) {
  let gr = new PIXI.Graphics()
  //随机🌰颜色
  gr.beginFill(colors[Math.floor(Math.random() * colors.length)])
  gr.drawCircle(0, 0, 6)
  gr.endFill()
​
  //存储到对象数组中
  let pItem = {
    sx: Math.random() * window.innerWidth,
    sy: Math.random() * window.innerHeight,
    gr
  }
  gr.x = pItem.sx
  gr.y = pItem.sy
  particleContainer.addChild(gr)
  particles.push(pItem)
}

让🌰(粒子)动起来

我们只需要旋转粒子的容器,控制粒子y轴向下移动就可以了。

//设置容器
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

容器的位置和角度调好了,接下来就是想办法让粒子一直动,根本停不来的那种~。设置一个速度初始值,这样就能感受到由快到慢的感觉了。还有大家发现没,粒子刚开始是圆体慢慢的变成线条,是怎么实现的,其实非常简单,我们只需要球体的y轴拉长,x轴变扁就实现了。

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
    if (speed >= 20) {
      //y轴拉长,x轴变扁
      pItem.gr.scale.y = 20
      pItem.gr.scale.x = 0.05
    }
    //超出屏幕,回到顶部,继续动
    if (pItem.gr.y > window.innerHeight) pItem.gr.y = 0
  }
}
​
function start() {
  speed = 0
  gsap.ticker.add(loop)
}
​
gsap.ticker.add(loop)

让🌰(粒子)暂停

让粒子暂停,回到圆体状态,并且有回弹效果

function pause() {
  gsap.ticker.remove(loop)
​
  for (let i = 0; i < particles.length; i++) {
    let pItem = particles[i]
    //回到圆体状态
    pItem.gr.scale.y = 1
    pItem.gr.scale.x = 1
    //回弹效果
    gsap.to(pItem.gr, {
      duration: 0.6,
      x: pItem.sx,
      y: pItem.sy,
      ease: 'elastic.out'
    })
  }
}

🌰(粒子)效果加入按钮事件中

actionButton.on('mousedown', () => {
  pause()
})
​
actionButton.on('mouseup', () => {
  start()
})

好了,这样就完成了,是不是发现很简单也很有意思。

demo地址:github.com/qwerlp/YCY-…

公众号里搜 大帅老猿,在他这里可以学到很多东西