你要的红包雨插件来了

你要的红包雨插件来了

先上效果 效果1效果2

效果1效果2

开发背景

双十一公司要做一个往下掉的效果红包雨,双十二又要从下往上喷的效果,安排!经过奋战,我把它封装成了npm包,方便在今后的各个业务中灵活使用。今天笔者就探讨一下往下掉的效果实现过程。

分析

  1. 红包雨频繁的操作数据可以使用canvas的drawImage方法
  2. 红包下掉的效果可以这样算:当前位置=上个位置+这一帧移动的距离,也就是自由落体的计算公式s=s0+1/2*gt^2;
  3. 需要建立3个类,一个全局控制器stage,一个掉落的红包dropBox,一个加一的效果add

上代码


export default class Stage {
 
  constructor(opt: StageOpt) {
   
  }
  /**
   * 事件监听
   * gameOver 游戏结束回调
   * clickBox 点击回调
   * coundownTime 倒计时监听
   * */
  on(name: eventName, fn: Function) {
   
  }
  // 开始游戏
  startGame() {
 
  }

  // 更新ui
  upData() {
   
  }
    
  // 点击
  onClick(e: any) {
   
  }
  // 创建红包
  creatDropBox() {
   
  }
  // 销毁
  destory() {}
   
}




复制代码

stage 中的update方法用于更新ui,做了这几件事:

1.清除画布 this.ctx.clearRect(0, 0, this.width, this.height)

2.创建红包 this.creatDropBox()

3.过滤活跃对象,调用当前对象的updata方法更新数据,调用ctx.drawImage()把当前对象绘制到画布上

4.销毁无用对象


  // 更新ui
  upData() {
    // 清除画布
    if (this.ctx) this.ctx.clearRect(0, 0, this.width, this.height)
    // 创建红包,加入到this.pool
    this.creatDropBox()
    const arr: Array<any> = []
    // 过滤活跃对象
    this.pool.forEach((v: any) => {
      if (!v.isDestory) {
        // 更新每个对象
        v.updata()
        // 绘制图片
        if (this.ctx) {
          this.ctx.drawImage(v.img, v.x, v.y, v.w, v.h)
        }
        arr.push(v)
      }
    })

    // 赋值未回收的对象
    this.pool = [...arr]
    this.timer && window.cancelAnimationFrame(this.timer)
    this.timer = window.requestAnimationFrame(this.upData.bind(this))
  }
复制代码

dropBox和add类,主要负责更新数据,有三个方法

1.updata更新数据

2.getStep 获取当前移动的距离

3.destory 销毁函数

export default class AddScore {
private w: number = 40
private h: number = 40
private x: number
private y: number
private img: any
private id: number
private v: number = 0
private type: string = 'AddScore'
private isDestory: boolean = false

constructor(opt: AddScoreOpt) {
  this.id = idNum += 1
  this.x = opt.x || 20
  this.y = opt.y || 20
  this.img = opt.img
}

// 更新数据
updata() {
  this.y = this.y - this.getStep()
  this.x = this.x + this.getStep()
  this.w -= 1
  this.h -= 1
  this.isDestory = this.v > 8
}

getStep(): number {
  return (this.v += 0.1)
}

destory() {
  this.img = null
}
}
复制代码

stage类中onClick做了这几件事:

1.判断当前点击位置是否在红包上

2.从pool中删除被点击的红包

3.添加加一的效果

 onClick(e: any) {
    e.preventDefault && e.preventDefault()
    // 点击位置
    const pos = {
      x: e.clientX,
      y: e.clientY,
    }
    // 点中对象
    let maxIndex = -1
    let creatTime = 0
    this.pool.forEach((e: any, i: number) => {
      if (this.isIntersect(pos, e)) {
        if (e.creatTime >= creatTime) {
          creatTime = e.creatTime
          maxIndex = i
        }
      }
    })
    // 操作点击对象
    if (maxIndex > -1) {
      const target = { ...this.pool[maxIndex], gameTime: this.gameTime }
      // 回调监听点击事件
      this.events.clickBox.forEach((e: Function) => e(target))
      // 回收box
      this.pool.splice(maxIndex, 1)
      // 添加+1
      this.pool.push(
        new AddScore({ x: target.x, y: target.y, img: this.addIcon })
      )
    }
  }
复制代码

总结

以上就是红包雨的简单实现,代码我放到这里了,但是有些手机体验不好。 经过优化,redpacket-core成功的经历了千万级用户的考验,我把它分享给大家,希望他对你有用。

猜你喜欢

转载自juejin.im/post/7042487729644372004