关于前端:如何在react中使用pixi快速的做一个的炫酷的刹车特效全注释附源码

36次阅读

共计 5306 个字符,预计需要花费 14 分钟才能阅读完成。

思考

因为之前跟着视频学了一下 pixi 写自行车刹车的实战案例,只不过是本来的是 html 原生开发。前面本人也想换个环境进行一下尝试。所以就有了在 react 我的项目中进行的重写。

源码地址

进入 github

步骤

  1. 利用 react 脚手架创立我的项目,react 版本为 17.0.2,将多余的代码删除掉。就能够 run 起来了。而后先在 app.js 引入 PIXI,gsap 这两个包

    import * as PIXI from 'pixi.js'
    import {gsap} from 'gsap'

    而后在此文件中创立一个 id 名为 pixiCavas 的 div 盒子。在页面初始化的时候将画布给 append 进去。当前的步骤都是在 app.js 这个文件中进行操作。

     <div id="pixiCavas">
     </div>

    2. 为了让布局看起来更清新,增加两个全局变量 particles(色彩),speed(速度), 之后的代码都是同一级的

     // 全局变量色彩
      let particles = [];
      // 全局的速度
      let speed = 0

    3. 初始化根 pixi 利用

    const app = new PIXI.Application(
     {
       width: window.innerWidth,
       height: window.innerHeight,
       backgroundColor: 0xFFFFFFFF,
       resizeTo: window
     }
      );

    4. 创立加载器实例,一个 app.loader 只能加载一个图片,所以通过 new PIXI.Loader()创立一个实例来实现同时加载

    const loader = new PIXI.Loader()
    // stage:将图片插入到画布中的办法
    const stage = app.stage

    5. 加载图片,这里引入图片利用了 require。尝试过用 import 通过变量的模式来导入,也是可行的。这里应用 require 看起来更娟秀点

     // 加载图片
      loader.add("btn_img", require('./images/btn.png'))
      loader.add("brake_bike", require('./images/brake_bike.png'))
      loader.add("brake_handlerbar", require('./images/brake_handlerbar.png'))
      loader.add("brake_lever", require('./images/brake_lever.png'))
      loader.add("btn_circle", require('./images/btn_circle.png'))
      // 调用加载器
      loader.load()
      // 加载结束的时候调用 show 办法来开始页面
      loader.onComplete.add(() => {show()
      })

    6. 展现,这里是将自行车相干的代码封装起来的,外面还会调用粒子的成果函数

    const show = () => {
     // 创立刹车
     let bikeLeverImage = new PIXI.Sprite(loader.resources.brake_lever.texture);
     //  创立车架
     let bikeContainer = createBikeContainer(bikeLeverImage)
     stage.addChild(bikeContainer)
     // 创立按钮
     let actionButton = creatActionButton();
     actionButton.x = window.innerWidth - 200
     actionButton.y = 500;
     // 将按钮增加到页面
     stage.addChild(actionButton)
     // 使按钮具备和用户交互的能力
     actionButton.interactive = true
     // 小手成果
     actionButton.buttonMode = true
     // 因为是鼠标事件,这里只对 pc 端失效
     // 鼠标按下
     actionButton.on("mousedown", () => {
       bikeLeverImage.rotation = Math.PI / 180 * -30;
       gsap.to(bikeLeverImage, { duration: .6, rotation: Math.PI / 180 * -30})
       // 鼠标按下粒子静止暂停,speed 归 0
       pause()
       speed = 0
     })
     // 鼠标来到
     actionButton.on("mouseup", () => {
       // 旋转刹车
       gsap.to(bikeLeverImage, { duration: .6, rotation: 0})
       // 鼠标来到粒子持续静止
       start()})
    
     // 创立粒子
     creatParticle()
     // 粒子开始静止
     start()}

    7. 创立车架的函数

    const createBikeContainer = (bikeLeverImage) => {const bikeContainer = new PIXI.Container();
    bikeContainer.scale.x = bikeContainer.scale.y = 0.2
    // 留神: 图片放至的程序会影响图片的层级,先放的图片在底层
    // 自行车架
    let bikeImage = new PIXI.Sprite(loader.resources.brake_bike.texture);
    bikeContainer.addChild(bikeImage)
    // 刹车
    // let bikeLeverImage = new PIXI.Sprite(loader.resources.brake_lever.texture);
    bikeContainer.addChild(bikeLeverImage)
    bikeLeverImage.pivot.x = bikeLeverImage.pivot.y = 455;
    bikeLeverImage.x = 722;
    bikeLeverImage.y = 900;
    // 手把
    let bikeHandleBarImage = new PIXI.Sprite(loader.resources.brake_handlerbar.texture);
    bikeContainer.addChild(bikeHandleBarImage)
    // 监听,让自行车始终呈现在画面右下角
    let resize = () => {
      bikeContainer.x = window.innerWidth - bikeContainer.width
      bikeContainer.y = window.innerHeight - bikeContainer.height
    }
    window.addEventListener('resize', resize)
    resize()
    return bikeContainer
     }

    8. 创立行为按钮

    const creatActionButton = () => {let actionButton = new PIXI.Container()
    //  按住按钮以及两个圈
    let btnImg = new PIXI.Sprite(loader.resources.btn_img.texture)
    let btnCircle = new PIXI.Sprite(loader.resources.btn_circle.texture)
    let btnCircle2 = new PIXI.Sprite(loader.resources.btn_circle.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
     }

    9. 创立粒子

    const creatParticle = () => {
    // 创立粒子
    let partialContainer = new PIXI.Container()
    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
    // 粒子多个色彩
    creatParticleColors(partialContainer)
     }

    10. 粒子色彩创立

    const creatParticleColors = (partialContainer) => {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, 10)
      gr.scale.y = 0.4
      gr.scale.x = 0.4
      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)
    }
     }

    11. 小圆点继续挪动,并且在速度大于 20 的时候开始变形,通过扭转粒子的 x,y 的大小来调整为线条和视觉的颗粒感

    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 = 20
        // 颗粒感
        pItem.gr.scale.x = 0.05
      }
      // 超出边界后从画面外面回来继续移动
      if (pItem.gr.y > window.innerHeight) pItem.gr.y = 0
    }
     }

    12. 小圆点挪动的函数

    const start = () => {loop()
    gsap.ticker.add(loop)
     }

    13. 按住鼠标时革除 loop,并且在 onmouseDown 事件时触发让 speed 从新为 0

    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'})
     }
    }

    14. 最重要的一点,将画布 append 到 div 中, 我是这样写的,有小伙伴有其余好办法能够分享哦

      useEffect(() => {
     // 将利用挂载到 app 的 div 上
     document.querySelector("#pixiCavas").appendChild(app.view)
      }, [])

    感悟

    刚开始的时候想着 npm install pixi 的,发现没有这个包 >>PS: 其实是搞错了,应该这么干: npm install pixi.js。而后应用 pixi 时 @inlet/react-pixi 进行的从新,写到一半快不行了。因为没有找到官网文档,也是参考他人的办法来进行书写,感觉也实现不了成果,头发都快薅光了。前面忽然灵感来了,github 这么大的库应该能够搜到材料,所以就间接找到了 pixi 的官网库进行参考 pixi.js. 当初看起来还好,但当真真切切的本人入手时又是另外的感觉了。用将来的眼光看当初如同也不是什么小事。

    番外

    • 最近也在想开始写文章,通过输入来晋升本人的能力

正文完
 0