给DOM开发者的游戏开发指南-11.FlppyBird-对象池

431 阅读1分钟

仓库地址:github.com/haiyoucuv/W…

引入概念:对象池

上节我们完成了障碍的动态创建

但是运行一段时间发现,dom节点树上有n个障碍,卡得一批

这些移出屏幕的障碍,不仅占了大量内存,而且他们其实完全不需要更新和渲染

11_1.png

对象池

使用对象池,回收对象,保存在池中,需要的时候不必再重新创建,只需要从池中获取就可以

对象移除显示列表的时候,放回池中就可以了

  • 创建ObjectPool
  • 用一个静态变量来保存对象
  • 实现静态方法put接口,传入name来区分保存对象的类型,这样可以保存不同的类型的对象
  • 实现静态方法get接口,传入name来获取相应的类型的对象
/**
 * 一个简单的通用对象池
 */
class ObjectPool {

	static objs = {};

	static put(name, obj) {
		const pool = ObjectPool.objs[name] || (ObjectPool.objs[name] = []);

		pool.push(obj);
	}

	static get(name) {
		const pool = ObjectPool.objs[name] || (ObjectPool.objs[name] = []);

		if (pool.length <= 0) {
			return null;
		}

		return pool.shift();
	}
}

改造PieMgr

  • 创建Pie时先从对象池中获取,如果没有,则新创建
  • Pie移出屏幕后,从托管列表中移除,从子节点移除,并且放回对象池
class PieMgr extends GameObject {

	/* ... */

	/**
	 * 创建Pie
	 */
	createPie() {
		// 使用对象池 如果对象池中取不到,说明对象池空了,需要新创建
		const pie = ObjectPool.get("pie") || new Pie();
		this.addChild(pie);
		this.pieArr.push(pie);  // 加入列表统一管理
		pie.top = Math.random() * -150; // 高度随机
		pie.left = winSize.width;   // 从屏幕左边出现
	}

	update() {
		super.update();

		// 所有的Pie同时向左移动
		const { speed, pieArr } = this;
		pieArr.forEach((pie) => {
			pie.left -= speed;
			if (pie.left <= -pie.size.width) {  // 如果移出屏幕
				this.pieArr.splice(this.pieArr.indexOf(pie), 1);    // 从托管列表里移除
				this.removeChild(pie);                              // 从子节点移除
				ObjectPool.put("pie", pie);                         // 加入对象池
			}
		});
	}
}

运行案例,挂机10分钟,一点也不卡,显示列表最多也只有两个Pie同时存在

挂机一天也不卡,牛逼