PIXI简单应用-PIXI&GSAP实现刹车特效 | 猿创营

860 阅读1分钟

前言

近期猿创营在分享一期仿写vanmoof刹车动效的活动, 下面我们来看看整个刹车特效的实现过程, 这个项目使用到了PIXI和GSAP两个库,可以提前了解一下

搭建环境

  1. 当前项目需要加载两个库PIXI 和 GSAP
<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>
  1. 启动一个本地web服务器,我这里使用的serve, 当然大家使用自己熟悉的就行, vscode开发的话推荐使用lib preview

本项目使用到了一些素材,可以在我的github上下载

开发

创建PIXI应用

new PIXI.Application({
  width: window.innerWidth,
  height: window.innerHeight,
  backgroundColor: 0xffffff,
})
document.querySelector(selector).appendChild(this.app.view)

加载图片资源

const loader = new PIXI.Loader()
loader.add('btn.png', 'images/btn.png')
loader.add('brake_bike.png', 'images/brake_bike.png')
loader.add('brake_handlerbar.png', 'images/brake_handlerbar.png')
loader.add('brake_lever.png', 'images/brake_lever.png')
loader.add('btn_circle.png', 'images/btn_circle.png')

loader.load()
loader.onComplete.add(() => {
  setup()
})

创建按钮图片精灵

function loaderButton() {
    const buttonContainer = new PIXI.Container()
    const buttonImg = new PIXI.Sprite(this.loader.resources['btn.png'].texture)
    const buttonCircleImage = new PIXI.Sprite(this.loader.resources['btn_circle.png'].texture)
    const buttonCircleImage2 = new PIXI.Sprite(this.loader.resources['btn_circle.png'].texture)
    buttonContainer.addChild(buttonImg)
    buttonContainer.addChild(buttonCircleImage)
    buttonContainer.addChild(buttonCircleImage2)

    // 设置
    buttonImg.pivot.y = buttonImg.pivot.x = buttonImg.width / 2
    buttonCircleImage.pivot.y = buttonCircleImage.pivot.x = buttonCircleImage.width / 2
    buttonCircleImage2.pivot.y = buttonCircleImage2.pivot.x = buttonCircleImage2.width / 2

    // 设置波纹初始缩放比例
    buttonCircleImage2.scale.x = buttonCircleImage2.scale.y = 0.8
    
    // 添加动画
    gsap.to(buttonCircleImage2.scale, { duration: 1, x: 1.2, y: 1.2, repeat: -1 })
    gsap.to(buttonCircleImage2, { duration: 1, alpha: 0, repeat: -1 })

    // 设置按钮容器大小
    buttonContainer.width = this.buttonConfig.width
    buttonContainer.height = this.buttonConfig.height

    // 默认定位到左上角
    buttonContainer.x = this.buttonConfig.width / 2
    buttonContainer.y = this.buttonConfig.height / 2

    // 添加按钮到舞台
    this.app.stage.addChild(buttonContainer)

    return buttonContainer
  }

设置把手、车身

const brakeHandlerbar = new PIXI.Sprite(this.loader.resources['brake_handlerbar.png'].texture)
    bikeContainer.addChild(brakeHandlerbar)

    const bikeBrakeImage = new PIXI.Sprite(this.loader.resources['brake_bike.png'].texture)
    bikeContainer.addChild(bikeBrakeImage)

    // 把手
    const bikeLeverImage = new PIXI.Sprite(this.loader.resources['brake_lever.png'].texture)
    bikeContainer.addChild(bikeLeverImage)

    bikeLeverImage.pivot.x = 455
    bikeLeverImage.pivot.y = 455
    bikeLeverImage.x = 722
    bikeLeverImage.y = 900

    // bikeLeverImage.rotation = (Math.PI / 180) * -30

    const actionButton = this.createActionButton()
    actionButton.x = actionButton.y = 400
    this.app.stage.addChild(actionButton)

    actionButton.interactive = true
    actionButton.buttonMode = true

    actionButton.on('mousedown', () => {
      // bikeLeverImage.rotation = (Math.PI / 180) * -30
      gsap.to(bikeLeverImage, { duration: 0.6, rotation: (Math.PI / 180) * -30 })
      pause()
    })

    actionButton.on('mouseup', () => {
      // bikeLeverImage.rotation = 0
      gsap.to(bikeLeverImage, { duration: 0.6, rotation: 0 })
      start()
    })

    const resize = () => {
      bikeContainer.x = window.innerWidth - bikeContainer.width
      bikeContainer.y = window.innerHeight - bikeContainer.height
    }
    window.addEventListener('resize', resize)
    resize()

创建雨滴动画

// 创建粒子
    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
    // particleContainer.fill = 0xff0000

    this.app.stage.addChild(particleContainer)
    const particles = []
    const colors = [0xf1cf54, 0xb5cea8, 0xf1cf54, 0xff0000]
    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)
    }
    let speed = 0
    function loop() {
      speed += 0.5
      speed = Math.min(speed, 30)
      for (let i = 0; i < particles.length; i++) {
        let pItem = particles[i]
        pItem.gr.y += speed
        if (speed >= 20) {
          pItem.gr.scale.y = 50
          pItem.gr.scale.x = 0.05
        }

        if (pItem.gr.y > window.innerHeight) {
          pItem.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]
        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' })
      }
    }
    start()

最后

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