各位大佬,本人使用的3.8版本,请教下nodepool里面的poolHandlerComp该如何使用,目前在开发一个射击游戏,需要使用poolHandlerComp对对象池里的子弹复用,官方文档和各论坛好像都没有具体的使用案例,文本中我是想子弹复用的时候回到初始的位置和rotation,nodepool中的poolHandlerComp组建该如何编写。
nodepool 使用有坑的 ,同一帧的节点 进入池里面。。立刻使用是异常,需要等下一帧。。
这个问题每个版本都有吗?
子弹 复用的话 直接 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;
node 的生命周期 属于cocos自身的问题了,当前帧加入pool 当前帧取出加入其他节点就会出现问题
你好,是要这种效果,感谢解答
难道不是把子弹的脚本组件名在初始化对象池的时候传过去吗?这样就可以在子弹的脚本组件中的reuse和use函数中写初始化和清理的逻辑。
我就是这个问题一直搞不清楚,子弹脚本组建里的unuse和reuse如何定位到当前put或者get的node?直接this.nodw吗


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