PIXI、GSAP初阶碰撞之刹车动感 | 猿创营

1,295 阅读3分钟

效果比对

第一张为模仿效果

前言

最近来自菜鸟派的Rock修炼了PIXI以及GSAP大法,显的有些膨胀;在掘场发起了自嗨模式,先听首歌再继续

修炼过程

Rock直接从磁盘里拿出一堆乱七八糟的材料,一点也不慌乱;悠闲的让PIXI创建个熔炉,材料一次加载到加载器中

constructor(selector) {
    this.speed = 0
    this.btns = {}
    this.particles = []
    this.app = this.initPixi()
    document.querySelector(selector).appendChild(this.app.view)
    this.loader = new PIXI.Loader()
    this.loaderResources()
    this.loader.load()
    this.loader.onComplete.add(() => {
       this.show()
    })
}

initPixi() {
    return new PIXI.Application({
      width: window.innerWidth,
      height: window.innerHeight,
      backgroundColor: 0xffffff,
      resizeTo: window
    })
}

为了让模式更灵动,首先展示了操作按钮;PIXI默认的给按钮材料生成了专属容器,并将已经加载的按钮材料添加到容器,进行相关熔炼,但材料显的有些僵硬;这时候GSAP看不过去了,主动承担了动画效果,并给了一定的过度时间

createdBtnContainer() {
    const actions = [BTN, BTN_CIRCLE]
    const actionContainer = new PIXI.Container()
    actions.forEach(key => {
        this.btns[key] = this.getSprite(key)
        actionContainer.addChild(this.btns[key]) // 像容器中添加按钮资源
    })
    this.btns['statict'] = this.getSprite(BTN_CIRCLE) //多一次静态圈
    this.setOrigin([...actions, 'statict']) //设置资源的原点
    const btnCircle = this.btns[BTN_CIRCLE]
    actionContainer.addChild(this.btns['statict'])
    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: 0, repeat: -1 }) //逐渐消失效果
    return actionContainer
}

随着动作越来越熟练,瞬间就完成车架的搭建显示,并调整了刹车把的位置

createBrakeContainer() {
    const brakes = [BRAKE_BIKE, BRAKE_LEVER, BRAKE_HANDLERBAR,]
    const brakeContainer = new PIXI.Container();
    brakes.forEach(key => {
        this.btns[key] = this.getSprite(key)
        brakeContainer.addChild(this.btns[key])
    })
    brakeContainer.scale.x = brakeContainer.scale.y = 0.3
    this.btns[BRAKE_LEVER].pivot.x = 455
    this.btns[BRAKE_LEVER].pivot.y = 455
    this.btns[BRAKE_LEVER].x = 722
    this.btns[BRAKE_LEVER].y = 900
    return brakeContainer
}

然后就是粒子滚动的登场。大手一挥随机分布各种颜色的原点;让其在y轴运动,并将容器旋转

createParticles() {
    const particleContainer = new PIXI.Container()
    this.app.stage.addChild(particleContainer)
    particleContainer.x = particleContainer.pivot.x = window.innerWidth / 2
    particleContainer.y = particleContainer.pivot.y = window.innerHeight / 2
    particleContainer.rotation = 35 * Math.PI / 180
    const colors = [0x235dc8, 0xf05c5c, 0xf1b375, 0x137cbd4d]
    for (let i = 0; i < 10; i++) {
        const gr = new PIXI.Graphics()
        gr.beginFill(colors[Math.floor(Math.random() * colors.length)])
        gr.drawCircle(0, 0, 6)
        gr.endFill()
        const grItem = {
            sx: Math.random() * window.innerWidth,
            sy: Math.random() * window.innerHeight,
            gr
        }
        gr.x = grItem.sx
        gr.y = grItem.sy
        particleContainer.addChild(gr)
        this.particles.push(grItem)
    }

}

最后气运丹田,逐步的将各个容器进行汇集,进行显示和事件绑定

show() {
    // 创建按钮容器
    const actionContainer = this.createdBtnContainer()
    actionContainer.interactive = true
    actionContainer.buttonMode = true
    // 创建车架容器
    const brakeContainer = this.createBrakeContainer()
    actionContainer.x = window.innerWidth - brakeContainer.width
    actionContainer.y = window.innerHeight - brakeContainer.height
    this.app.stage.addChild(brakeContainer)
    this.app.stage.addChild(actionContainer)
    // 创建粒子数据
    this.createParticles()
    const loop = this.getParticleLoop()
    this.startLoop(loop)
    // 设置事件和交互
    this.setEvent(brakeContainer, actionContainer, loop)
}

setEvent(brakeContainer, actionContainer, loop) {
    const x = window.innerWidth - brakeContainer.width
    const y = window.innerHeight - brakeContainer.height
    const resize = () => {
        brakeContainer.x = x
        brakeContainer.y = y
    }
    window.addEventListener('resize', resize)
    resize()
    actionContainer.on('mousedown', () => {
        const rotation = this.btns[BRAKE_LEVER].rotation = Math.PI / 180 * -30
        gsap.to(this.btns[BRAKE_LEVER], { duration: .6, rotation }) //刹车动效
        this.pauseLoop(loop) //停止粒子滑动和样式、位置还原
        gsap.to(brakeContainer, { duration: .6, x: x - 3, y: y + 3, ease: 'elastic.out' }) //刹车减震动效
    })

    actionContainer.on('mouseup', () => {
        gsap.to(this.btns[BRAKE_LEVER], { duration: .6, rotation: 0 })
        this.startLoop(loop)
        gsap.to(brakeContainer, { duration: .6, x, y, ease: 'elastic.out' })
    })
}

就这样一场华丽的功法到了收功的时间

功法资源

心法

PIXI是一个非常快的2D sprite渲染引擎

  • Application:创建场景
  • Loader: 加载资源,通过add添加,其load方法加载
  • Sprite:特殊的图像对象,可以控制它们的位置、大小、旋转和其他属性
  • container:容器,储存资源对象,方便对象统一控制大小,缩放,位置和旋转操作
  • stage:根容器对象,显示场景中的事物
  • Graphics:绘制基本图像到渲染器,本场景中的粒子运动就是它绘制的圆点进行拉伸和运动

GSAP是制作动画的成熟的JavaScript库

  • to:将资源对象从当前位置向目标位置移动,它还支持了几乎所有的css属性

总结:初次绘制动画,简单实用,内功就交给时间好了;具体代码可查阅git地址;摸金校尉等你一起碰撞各种不同的前端

ps路线:在公众号里搜 大帅老猿,他做技术外包很靠谱