Here comes the red envelope rain plug-in you asked for

Effect one, effect two

Development background

Double 11 company to do a down the effect of red envelope rain, double 12 and from the bottom of the effect of spray, arrangement! After some hard work, I packaged it into an NPM package that can be used flexibly in various businesses in the future. Today, the author discusses the effect of falling down the process.

Analysis of the

  1. To manipulate data frequently, you can use canvas’s drawImage method
  2. The effect of red envelope drop can be calculated as follows: current position = previous position + this frame movement distance, that is, the calculation formula of free fall s=s0+1/2*gt^2;
  3. We need to create three classes, a global controller stage, a dropBox for dropping red envelopes, and a add effect

In the code


export default class Stage {
 
  constructor(opt: StageOpt){}/** * Event monitor * gameOver game end callback * clickBox click callback * coundownTime countdown monitor ** /
  on(name: eventName, fn: Function){}// Start the game
  startGame(){}/ / update the UI
  upData(){}/ / click
  onClick(e: any){}// Create a red envelope
  creatDropBox(){}/ / destroy
  destory(){}}Copy the code

The Update method in the stage is used to update the UI and does these things:

1. Clear the canvas this.ctx.clearRect(0, 0, this.width, this.height)

This.creatdropbox ()

3. Filter the active object, call the updata method of the current object to update the data, and call ctx.drawImage() to draw the current object to the canvas

4. Destroy useless objects


  / / update the UI
  upData() {
    // Clear the canvas
    if (this.ctx) this.ctx.clearRect(0.0.this.width, this.height)
    // Create a red envelope and add it to this.pool
    this.creatDropBox()
    const arr: Array<any> = []
    // Filter active objects
    this.pool.forEach((v: any) = > {
      if(! v.isDestory) {// Update each object
        v.updata()
        // Draw a picture
        if (this.ctx) {
          this.ctx.drawImage(v.img, v.x, v.y, v.w, v.h)
        }
        arr.push(v)
      }
    })

    // Assign an uncollected object
    this.pool = [...arr]
    this.timer && window.cancelAnimationFrame(this.timer)
    this.timer = window.requestAnimationFrame(this.upData.bind(this))}Copy the code

The dropBox and Add classes, which are responsible for updating data, have three methods

1. Updata Updates data

2. GetStep Obtains the current move distance

3. Destory destroy function

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
}

// Update data
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}}Copy the code

OnClick in the stage class does these things:

1. Determine whether the current click position is on the red envelope

2. Delete the clicked red packets from the pool

3. Add a plus one effect

 onClick(e: any) {
    e.preventDefault && e.preventDefault()
    // Click the position
    const pos = {
      x: e.clientX,
      y: e.clientY,
    }
    // Click on the middle object
    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
        }
      }
    })
    // Click on the object
    if (maxIndex > -1) {
      consttarget = { ... this.pool[maxIndex],gameTime: this.gameTime }
      // The callback listens for click events
      this.events.clickBox.forEach((e: Function) = > e(target))
      / / recycling box
      this.pool.splice(maxIndex, 1)
      / / add + 1
      this.pool.push(
        new AddScore({ x: target.x, y: target.y, img: this.addIcon })
      )
    }
  }
Copy the code

conclusion

The above is the simple implementation of red envelope rain, the code I put here, but some mobile phone experience is not good. After optimization, Redpacket-core has successfully experienced the test of tens of millions of users. I share it with you and hope it can be useful to you.