如何在react中使用pixi快速的做一个的炫酷的刹车特效!(全注释,附源码)

本文记录了一位开发者如何在React项目中使用Pixi.js库和gsap进行交互式动画开发,详细介绍了从项目初始化、资源加载、元素创建到事件监听的整个过程,特别是如何实现自行车刹车时的粒子效果和动画交互。
摘要由CSDN通过智能技术生成

pixi

思考

因为之前跟着视频学了一下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.现在看起来还好,但当真真切切的自己动手时又是另外的感觉了。用未来的眼光看现在好像也不是什么大事。

番外

  • 也是最近在开始写文章,通过输出来提升自己的能力

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只夏宇坤

你的鼓励是我持续创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值