使用PIXI,GSAP制作刹车视觉动效实践与感悟 | 猿创营

280 阅读3分钟

思考

一般开场白就是介绍一下自己😳,那我也介绍一下自己吧。hellow,我是沐阳,刚开始在掘金上水文。作为一位初级前端,开发经验往往只停留在了后台管理系统,或者一些简单的h5页面。大多数的时候因为技术水平有限,所以很少有时间去学习了解很多的东西。想过自己利用周末时间去学习。但是每次都有各种理由放弃。有一句话说的好,方向不对,努力白费。所以我选择和一些志同道合的小伙伴一起学习。下面是利用周末时间结合B站教学视频点对点敲的动效😊。

图片效果展示

2022-07-09 12.51.54.gif

前置类容

源码地址

github

  • 如果想直接看效果,可以pull下来,利用vscode插件Live Preview,右键html文件选择Live PreView:Show Preview命令进行查看
  • 如果嫌麻烦,就在这里把代码贴上了

代码块

1,在html页面中进行开发:引入下面的脚本

 <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>

2,html页面设置一个id,用于后面的选择器进行插入选择

<body>
    <div id="brakebanner"></div>
 </body>

3,创建js文件目录,建立brakebanner.js

  • 创建BrakeBanner类
class BrakeBanner{
	constructor(selector){
            // 创建总盒子Application
            this.app = new PIXI.Application({
            width: window.innerWidth,
                     height: window.innerHeight,
                     backgroundColor: 0xFFFFFFFF,
                     resizeTo: window
            })
            // 将实例化Application插入body页面中
            document.querySelector(selector).appendChild(this.app.view)
            // this.app.stage赋值简写
            this.stage = this.app.stage
            // 创建加载器
            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()
            })
	}
 }
  • show函数调用
show(){
    let actionButton = this.creatActionButton();
    actionButton.x = actionButton.y = 300;

    const bikeContainer = new PIXI.Container();
    this.stage.addChild(bikeContainer)

    bikeContainer.scale.x = bikeContainer.scale.y = 0.2
    let bikeImage = new    PIXI.Sprite(this.loader.resources['brake_bike.png'].texture);
    bikeContainer.addChild(bikeImage)
    // 注意: 图片放至的顺序会影响图片的层级,先放的图片在底层
    // 刹车
    let bikeLeverImage = new PIXI.Sprite(this.loader.resources['brake_lever.png'].texture);
    bikeContainer.addChild(bikeLeverImage)
    bikeLeverImage.pivot.x = bikeLeverImage.pivot.y = 455;
    bikeLeverImage.x = 722;
    bikeLeverImage.y = 900;
    // 手把
    let bikeHandleBarImage = new PIXI.Sprite(this.loader.resources['brake_handlerbar.png'].texture);
    bikeContainer.addChild(bikeHandleBarImage)
    // 创建按钮
    this.stage.addChild(actionButton)
    // 具备和用户交互的能力
    actionButton.interactive = true
    // 小手效果
    actionButton.buttonMode = true
    actionButton.on("mousedown",()=>{
        // 旋转刹车,未添加动小时侯效果
        // bikeLeverImage.rotation = Math.PI/180*-30;
        gsap.to(bikeLeverImage,{duration:.6, rotation: Math.PI/180*-30})
        pause()
    })
    actionButton.on("mouseup",()=>{
        // 旋转刹车
        // bikeLeverImage.rotation = 0;
        gsap.to(bikeLeverImage,{duration:.6, rotation: 0})
        start()
    })
    // 监听,让自行车一直出现在画面右下角
    let resize = ()=> {
       bikeContainer.x = window.innerWidth - bikeContainer.width
       bikeContainer.y = window.innerHeight - bikeContainer.height
    }
    window.addEventListener('resize',resize)
    resize()

    // 创建粒子
    let partialContainer = new PIXI.Container()
    this.stage.addChild(partialContainer)
    // 将粒子盒子旋转35度
    partialContainer.rotation = 35*Math.PI/180
    // 设置盒子的中心点
    partialContainer.pivot.x = window.innerWidth/2
    partialContainer.pivot.y = window.innerHeight/2
    partialContainer.x = window.innerWidth/2
    partialContainer.y = window.innerHeight/2


    let particles = [];
    // 粒子多个颜色
    let colors = [0xf1cf54,0xb5cea8,0xf1cf54,0x8182f]
    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.scale.y = 0.3
     gr.scale.x = 0.3
     gr.endFill()
     let pItem = {
         sx: Math.random()*window.innerWidth,
         sy: Math.random()*window.innerHeight,
         gr: gr
     }
     gr.x = pItem.sx
     gr.y = pItem.sy
     partialContainer.addChild(gr)
     particles.push(pItem)
    }
    let speed = 0
    // 持续移动
    const loop = ()=>{
        speed += .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.y = 40
            // 颗粒感
            pItem.gr.scale.x = 0.03
        }
        // 超出边界后从画面里面回来继续移动
        if(pItem.gr.y> window.innerHeight) pItem.gr.y=0
          }
    }

    const start = ()=>{
        speed = 0
        gsap.ticker.add(loop)
    }
    // 按住鼠标停止
    const pause = () => {
    gsap.ticker.remove(loop)
    for (let i=0; i<particles.length; i++) {
        let pItem = particles[i]
        pItem.gr.scale.y = .3
        pItem.gr.scale.x = .3
        // ease: 'elastic.out'回弹效果
        gsap.to(pItem.gr,{duration:.6,x:pItem.sx,y:pItem.sy,ease: 'elastic.out'})
        }
       }
    start()
}
  • 调用creatActionButton
creatActionButton(){
    let actionButton = new PIXI.Container()

    let btnImg = 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(btnImg)
    actionButton.addChild(btnCircle)
    actionButton.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 actionButton
}

总结

虽然代码不多。但主观上让我进行开发,却是一件很难的事情。尤其是粒子倾斜加速的这里,怎么将圆圈变为线,并且进行非匀速倾斜运动。如果用算法去实现,有些麻烦。所以这种将所以原点统一放在一个容器里面,然后对每个小圆点进行y轴移动,到达临界点的时候重新开始计算,然后转换容器中心点的位置进行倾斜实现。这样的思路很不错。

  • 小伙伴们也可以看视频教程,感觉理念讲解的很好,可以自己动手练一练。

公众号里搜 大帅老猿,他做技术外包很靠谱