在交互及其频繁的游戏场景中,会产生大量的节点创建与销毁,其操作是非常耗费性能的,那么对象池则可以极大减少了重复节点的创建。
对象池就是一组可回收的节点对象,我们通过创建 cc.NodePool 的实例来初始化一种节点的对象池。通常当我们有多个 prefab 需要实例化时,应该为每个 prefab 创建一个 cc.NodePool 实例。当我们需要创建节点时,向对象池申请一个节点,如果对象池里有空闲的可用节点,就会把节点返回给用户,用户通过 node.addChild 将这个新节点加入到场景节点树中。
创建节点管理类
export class PoolManager{
private poolDic: Dictionary<ObjectPool> = new Dictionary<ObjectPool>();
public CreatePool(poolName: string, go: Node | Prefab) {
if (!go || !go.isValid) return warn(" prefab not available ", poolName);
if (this.poolDic.containsKey(poolName)) return warn(" pool already exists ", poolName);
let pool = new ObjectPool(go);
this.poolDic.add(poolName, pool);
}
public Get(poolName: string) {
let pool: ObjectPool = this.poolDic.getValue(poolName);
if (pool) return pool.Get();
warn(" pool does not exist , unable to get ");
return null;
}
public Save(poolName: string, go: Node, delay: number = 0, callback?) {
let pool: ObjectPool = this.poolDic.getValue(poolName);
if (pool) return pool.Save(go, delay, callback);
warn(" pool does not exist , unable to save ");
}
public SaveAll(poolName: string) {
let pool: ObjectPool = this.poolDic.getValue(poolName);
if (pool) return pool.SaveAll();
}
public Clean(poolName: string) {
let pool: ObjectPool = this.poolDic.getValue(poolName);
if (pool) {
pool.Clean();
this.poolDic.remove(poolName);
}
}
public CleanAll() {
this.poolDic.clear();
}
}
-
poolDic: 池子承载对象(子弹道具池子、炮弹道具池子等等......)
-
CreatePool:创建某个节点池子,根据poolName区分
-
Get:获取某个节点池子中未活跃的节点,并将状态更新为活跃
-
Save: 将指定某节点的状态更新为不活跃
-
SaveAll:将整个节点池子所有节点变为不活跃
-
Clean:清空某节点池子
-
CleanAll:清空所有节点池子
创建执行节点活跃状态的类
export class ObjectPool {
private prefab: Node | Prefab;
private pool: Array<Node> = [];
constructor(prefab: Node | Prefab) {
this.prefab = prefab;
}
public Get() {
if (this.pool.length > 0 && this.checkIsIdleGo(this.pool)) {
let go: Node = this.getIdleGo(this.pool);
go.active = true;
go.setPosition(Vec3.ZERO);
return go;
} else {
// LogManager.log("池子内预制不够,创建元素");
let go: any = instantiate(this.prefab);
go.active = true;
this.pool.push(go);
return go;
}
}
public Save(go: Node, delay: number = 0, callback?) {
if (delay == 0) {
this.runSaveVoid(go, callback);
} else {
let set1 = setTimeout(() => {
clearTimeout(set1);
this.runSaveVoid(go, callback);
}, delay);
}
}
public SaveAll() {
for (let i = this.pool.length - 1; i >= 0; i--) {
this.pool[i].active = false;
this.pool[i].parent = null;
}
}
public Clean() {
this.pool = [];
}
private runSaveVoid(go, callback) {
go.getComponent(Animation) && go.getComponent(Animation).stop();
go.active = false;
go.parent = null;
callback && callback();
}
private checkIsIdleGo(pool) {
for (let i = 0; i < pool.length; i++) {
if (!pool[i].active) {
return true;
}
}
return false;
}
private getIdleGo(pool) {
let index = pool.findIndex((item) => {
return !item.active;
});
if (index != -1) {
return pool[index];
}
}
}
ObjectPool中的方法是跟PoolManager一一对应,其作用是对节点的状态执行更新
创建池对象数据结果的类
Dictionary 是一个泛型类,主要用于实现键值对存储的数据结构,类似于 Map。
export class Dictionary<T> {
dataStore = {};
add(key: string, value: T) {
this.dataStore[key] = value;
}
remove(key: string) {
if (this.dataStore[key]) delete this.dataStore[key];
}
getValue(key: string) {
if (this.dataStore[key]) {
return this.dataStore[key];
} else {
// warn("key Not Found", key);
return null;
}
}
containsKey(key: string) {
if (this.dataStore.hasOwnProperty(key)) return true;
return false;
}
showAll() {
for (const key in this.dataStore) {
if (this.dataStore.hasOwnProperty(key)) {
log(key, "-->", this.dataStore[key]);
}
}
}
clear() {
this.dataStore = {};
}
count() {
let num = 0;
for (const key in this.dataStore) {
num++;
}
return num;
}
}
对象池使用
PoolManager.CreatePool("pool", Node); // 创建对象池
let item = PoolManager.Get("pool"); // 拿出来一个节点使用
item.setParent(parentNode); // 挂载到目标父节点下
PoolManager.Save("pool", item); // 将节点状态变成不活跃