各位大佬,请教下nodepool里面的poolHandlerComp该如何使用

各位大佬,本人使用的3.8版本,请教下nodepool里面的poolHandlerComp该如何使用,目前在开发一个射击游戏,需要使用poolHandlerComp对对象池里的子弹复用,官方文档和各论坛好像都没有具体的使用案例,文本中我是想子弹复用的时候回到初始的位置和rotation,nodepool中的poolHandlerComp组建该如何编写。

nodepool 使用有坑的 ,同一帧的节点 进入池里面。。立刻使用是异常,需要等下一帧。。

1赞

这个问题每个版本都有吗?

1赞

子弹 复用的话 直接 new NodePool(); 然后调用 相关的逻辑不就行了么
tileNodePool: cc.NodePool = new cc.NodePool();
getBulletFormPool() {
if (this.tileNodePool.size() <= 10) {
let tile = cc.instantiate(ResManager.inst.getRes(“bullet”, cc.Prefab));
this.tileNodePool.put(tile);
return this.getBulletFormPool();
} else {
this.tileNodePool.get().active = true;
return this.tileNodePool.get();
}
}
putBulletInPool(bullet: cc.Node) {
bullet.active = false;
bullet.setPosition(0, 0);
bullet.setScale(1, 1, 1);
this.tileNodePool.put(bullet);
}
你是想要这种效果?

我是从3.7开始用的 然后加入了一个自己的机制,延迟加入池中 ,确保池中拿出来的node 一定是已经经过一帧延迟的。

看下源码就知道了

import { Component } from '../../cocos/scene-graph/component';
import { Node } from '../../cocos/scene-graph';
import { legacyCC } from '../../cocos/core/global-exports';

type Constructor<T = {}> = new(...args: any[]) => T;

interface IPoolHandlerComponent extends Component {
    unuse (): void;

    reuse (args: any): void;
}

/**
 * @en
 *  `NodePool` is the cache pool designed for node type.<br/>
 *  It can helps you to improve your game performance for objects which need frequent release and recreate operations<br/>
 *
 * It's recommended to create `NodePool` instances by node type, the type corresponds to node type in game design, not the class,
 * for example, a prefab is a specific node type. <br/>
 * When you create a node pool, you can pass a Component which contains `unuse`, `reuse` functions to control the content of node.<br/>
 *
 * Some common use case is :<br/>
 *      1. Bullets in game (die very soon, massive creation and recreation, no side effect on other objects)<br/>
 *      2. Blocks in candy crash (massive creation and recreation)<br/>
 *      etc...
 * @zh
 * `NodePool` 是用于管理节点对象的对象缓存池。<br/>
 * 它可以帮助您提高游戏性能,适用于优化对象的反复创建和销毁<br/>
 * 以前 cocos2d-x 中的 pool 和新的节点事件注册系统不兼容,因此请使用 `NodePool` 来代替。
 *
 * 新的 NodePool 需要实例化之后才能使用,每种不同的节点对象池需要一个不同的对象池实例,这里的种类对应于游戏中的节点设计,一个 prefab 相当于一个种类的节点。<br/>
 * 在创建缓冲池时,可以传入一个包含 unuse, reuse 函数的组件类型用于节点的回收和复用逻辑。<br/>
 *
 * 一些常见的用例是:<br/>
 *      1.在游戏中的子弹(死亡很快,频繁创建,对其他对象无副作用)<br/>
 *      2.糖果粉碎传奇中的木块(频繁创建)。
 *      等等....
 */
export class NodePool {
    /**
     * @en The pool handler component, it could be the class name or the constructor.
     * @zh 缓冲池处理组件,用于节点的回收和复用逻辑,这个属性可以是组件类名或组件的构造函数。
     */
    public poolHandlerComp?: Constructor<IPoolHandlerComponent> | string;
    private _pool: Node[];

    /**
     * @en
     * Constructor for creating a pool for a specific node template (usually a prefab).
     * You can pass a component (type or name) argument for handling event for reusing and recycling node.
     * @zh
     * 使用构造函数来创建一个节点专用的对象池,您可以传递一个组件类型或名称,用于处理节点回收和复用时的事件逻辑。
     * @param poolHandlerComp @en The constructor or the class name of the component to control the unuse/reuse logic. @zh 处理节点回收和复用事件逻辑的组件类型或名称。
     * @example
     * import { NodePool, Prefab } from 'cc';
     *  properties: {
     *      template: Prefab
     *     },
     *     onLoad () {
     *       // MyTemplateHandler is a component with 'unuse' and 'reuse' to handle events when node is reused or recycled.
     *       this.myPool = new NodePool('MyTemplateHandler');
     *     }
     *  }
     */
    constructor (poolHandlerComp?: Constructor<IPoolHandlerComponent> | string) {
        this.poolHandlerComp = poolHandlerComp;
        this._pool = [];
    }

    /**
     * @en The current available size in the pool
     * @zh 获取当前缓冲池的可用对象数量
     */
    public size (): number {
        return this._pool.length;
    }

    /**
     * @en Destroy all cached nodes in the pool
     * @zh 销毁对象池中缓存的所有节点
     */
    public clear (): void {
        const count = this._pool.length;
        for (let i = 0; i < count; ++i) {
            this._pool[i].destroy();
        }
        this._pool.length = 0;
    }

    /**
     * @en Put a new Node into the pool.
     * It will automatically remove the node from its parent without cleanup.
     * It will also invoke unuse method of the poolHandlerComp if exist.
     * @zh 向缓冲池中存入一个不再需要的节点对象。
     * 这个函数会自动将目标节点从父节点上移除,但是不会进行 cleanup 操作。
     * 这个函数会调用 poolHandlerComp 的 unuse 函数,如果组件和函数都存在的话。
     * @example
     * import { instantiate } from 'cc';
     * const myNode = instantiate(this.template);
     * this.myPool.put(myNode);
     */
    public put (obj: Node): void {
        if (obj && this._pool.indexOf(obj) === -1) {
            // Remove from parent, but don't cleanup
            obj.removeFromParent();

            // Invoke pool handler
            // @ts-ignore
            const handler = this.poolHandlerComp ? obj.getComponent(this.poolHandlerComp) : null;
            if (handler && handler.unuse) {
                handler.unuse();
            }

            this._pool.push(obj);
        }
    }

    /**
     * @en Get a obj from pool, if no available object in pool, null will be returned.
     * This function will invoke the reuse function of poolHandlerComp if exist.
     * @zh 获取对象池中的对象,如果对象池没有可用对象,则返回空。
     * 这个函数会调用 poolHandlerComp 的 reuse 函数,如果组件和函数都存在的话。
     * @param args - 向 poolHandlerComp 中的 'reuse' 函数传递的参数
     * @example
     *   let newNode = this.myPool.get();
     */
    public get (...args: any[]): Node | null {
        const last = this._pool.length - 1;
        if (last < 0) {
            return null;
        } else {
            // Pop the last object in pool
            const obj = this._pool[last];
            this._pool.length = last;

            // Invoke pool handler
            // @ts-ignore
            const handler = this.poolHandlerComp ? obj.getComponent(this.poolHandlerComp) : null;
            if (handler && handler.reuse) {
                handler.reuse(arguments);
            }
            return obj;
        }
    }
}

legacyCC.NodePool = NodePool;

1赞

node 的生命周期 属于cocos自身的问题了,当前帧加入pool 当前帧取出加入其他节点就会出现问题

1赞

你好,是要这种效果,感谢解答

难道不是把子弹的脚本组件名在初始化对象池的时候传过去吗?这样就可以在子弹的脚本组件中的reuse和use函数中写初始化和清理的逻辑。

1赞

我就是这个问题一直搞不清楚,子弹脚本组建里的unuse和reuse如何定位到当前put或者get的node?直接this.nodw吗

1赞

image
image
这有什么看不明白的么???