微信小游戏 demo 飞机大战 代码分析 (二)(databus.js)

微信小游戏 demo 飞机大战 代码分析(二)(databus.js)

微信小游戏 demo 飞机大战 代码分析(一)(main.js)

微信小游戏 demo 飞机大战 代码分析(三)(spirit.js, animation.js)

微信小游戏 demo 飞机大战 代码分析(四)(enemy.js, bullet.js, index.js)

本博客将使用逐行代码分析的方式讲解该demo,本文适用于对其他高级语言熟悉,对js还未深入了解的同学,博主会尽可能将所有遇到的不明白的部分标注清楚,若有不正确或不清楚的地方,欢迎在评论中指正

本文的代码均由微信小游戏自动生成的demo飞机大战中获取

databus.js

代码:

import Pool from './base/pool'

let instance

/**
 * 全局状态管理器
 */
export default class DataBus {
  constructor() {
    if ( instance )
      return instance

    instance = this

    this.pool = new Pool()

    this.reset()
  }

  reset() {
    this.frame      = 0
    this.score      = 0
    this.bullets    = []
    this.enemys     = []
    this.animations = []
    this.gameOver   = false
  }

  /**
   * 回收敌人,进入对象池
   * 此后不进入帧循环
   */
  removeEnemey(enemy) {
    let temp = this.enemys.shift()

    temp.visible = false

    this.pool.recover('enemy', enemy)
  }

  /**
   * 回收子弹,进入对象池
   * 此后不进入帧循环
   */
  removeBullets(bullet) {
    let temp = this.bullets.shift()

    temp.visible = false

    this.pool.recover('bullet', bullet)
  }
}

instance

  • 该对象用于承载该文件中惟一的databus类,实现单例模式
  • 单例模式是一种设计模式,保证全局仅有一个该类的对象,这样能在该demo中保证全局数据的一致性

constructor

构造器

  • 如果instance不为空已经存在,那么就返回instance
    • 这是实现单例模式,保证不管多少次new都只能产生一个对象
  • 如果不为空,将instance设置为自身,并进行下列初始化操作
    • 创建一个对象池pool
      • 对象池技术是通过将生成的对象暂时保存于池中,需要对象时先在池中查看是否有多余对象,若不足再生成对象,而在销毁对象时不进行真正销毁,而是加入对象池中
    • 重置所有内容,设置为空

removeEnemey(enemy)

移除某个敌方对象(敌机)

  • 从enemys数组中获取第一个元素
    • shift方法是js中移除第一个元素并返回的方法
  • 设置其不可见
  • 移入名为enemy的池中

removeBullet(bullet)

移除某一个子弹

操作方式同上一个函数相同

pool.js

一个用于实现对象池的函数

代码:

const __ = {
  poolDic: Symbol('poolDic')
}

/**
 * 简易的对象池实现
 * 用于对象的存贮和重复使用
 * 可以有效减少对象创建开销和避免频繁的垃圾回收
 * 提高游戏性能
 */
export default class Pool {
  constructor() {
    this[__.poolDic] = {}
  }

  /**
   * 根据对象标识符
   * 获取对应的对象池
   */
  getPoolBySign(name) {
    return this[__.poolDic][name] || ( this[__.poolDic][name] = [] )
  }

  /**
   * 根据传入的对象标识符,查询对象池
   * 对象池为空创建新的类,否则从对象池中取
   */
  getItemByClass(name, className) {
    let pool = this.getPoolBySign(name)

    let result = (  pool.length
                  ? pool.shift()
                  : new className()  )

    return result
  }

  /**
   * 将对象回收到对象池
   * 方便后续继续使用
   */
  recover(name, instance) {
    this.getPoolBySign(name).push(instance)
  }
}

const __

用于防止魔术字符串出现的常量列表

  • Symbol
    • 在js中反复用于获取某些值或者对象的字符串称为魔术字符串,如果字符串过多,正常使用可以,但是若需要修改,则需要同时修改多个字符串,非常不利于维护
    • 为了解决这个问题,ES6引入了一个新的数据类型Symbol,用于存储这些字符串类型,而之后需要用到该字符串仅需要用该常量取得
    • symbol类型为类似于字符串的类型,不能使用new命令,也不能添加属性
  • 在这里声明了一个对象名称为poolDic,用于保存多个对象池的一个字典

constructor()

  • 创建一个空的poolDic

getPoolBySign(name)

  • 根据传入的名称获取相应的对象池,若不存在则生成一个新的,以一个数组来作为对象池

getItemByClass(name, className)

获取对象

  • 获取相应对象池
  • 判断对象池是否为空,若不为空,返回第一个元素,并从对象池中移除
  • 若不为空,则用传入的类名生成新的一个对象

recover(name, instance)

回收对象

  • 获取对象池并向其中推入元素
    • push是js数组中的操作,用于将元素打入数组当中
posted @ 2019-05-30 18:17  Phoenix_Xie  阅读(2564)  评论(0编辑  收藏  举报