好的,所以我有一个遍历并更新的所有实体的大清单。在AS3中,我可以将其存储为数组(动态长度,无类型),向量(类型)或链表(非本地列表)。目前,我正在使用数组,但如果速度更快,我打算更改为Vector或链表。
无论如何,我的问题是,当实体被销毁时,应如何将其从列表中删除?我可以取消其位置,将其剪接或只是在其上设置标记以说“跳过我,我死了”。我正在汇总我的实体,因此已死亡的实体很可能在某个时候再次处于活动状态。对于每种类型的馆藏,我最好的策略是什么,哪种馆藏类型和删除方法的组合最有效?
好的,所以我有一个遍历并更新的所有实体的大清单。在AS3中,我可以将其存储为数组(动态长度,无类型),向量(类型)或链表(非本地列表)。目前,我正在使用数组,但如果速度更快,我打算更改为Vector或链表。
无论如何,我的问题是,当实体被销毁时,应如何将其从列表中删除?我可以取消其位置,将其剪接或只是在其上设置标记以说“跳过我,我死了”。我正在汇总我的实体,因此已死亡的实体很可能在某个时候再次处于活动状态。对于每种类型的馆藏,我最好的策略是什么,哪种馆藏类型和删除方法的组合最有效?
Answers:
Flixel框架使用Dead标志(实际上是确定是否应绘制,更新等的几个标志)。我想说的是,如果您要恢复实体,并且如果性能存在问题,则可以使用Dead标志。以我的经验,实例化新实体是您所描述的用例中最昂贵的操作,并且由于Flash有时需要大量收集垃圾,因此拼接或清空元素可能导致内存膨胀。
dead
真正有助于提高性能。
尽管某些技术本质上比其他技术更有效,但是只有在目标平台上的周期用尽时,这才有意义。使用任何技术可以使您更快地完成游戏。同时,请尽量不要依赖于容器数据结构的特定实现,如果需要,它将帮助您进行后续优化。
只是为了解决这里其他人已经讨论过的一些技术。如果实体的顺序很重要,则死标记可以使您在下一帧的更新循环中进行拼接。例如。非常简单的伪代码:
void updateGame()
{
// updateEntities()
Entity* pSrcEntity = &mEntities[0];
Entity* pDstEntity = &mEntities[0];
newNumEntities = 0;
for (int i = 0; i < numEntities; i++)
{
if (!pSrcEntity->isDead)
{
// could be inline but whatever.
updateEntity(pDstEntity, pSrcEntity);
// if entity just died, don't update the pDstEntity pointer,
// and just let the next entity updated overwrite it.
if (!pDstEntity->isDead)
{
pDstEntity++;
newNumEntities++;
}
}
pSrcEntity++;
}
}
numEntities = newNumEntities;
这些是此方案的特征:
就个人而言,我将使用链接列表。快速遍历喜欢的列表以及添加和删除项目。如果您需要直接访问结构中的项目(例如,访问索引),则使用数组或向量将是一个不错的选择,但这听起来并不是您需要的。
每当您从链接列表中删除项目时,都可以将其添加到对象池中,然后可以对其进行循环以节省内存分配。
我在多个项目中使用了多边形数据结构,并对它们感到非常满意。
编辑:很抱歉,就删除策略而言,我的答案不是很明确:我建议从列表中删除该条目,直到它死了,然后将其直接添加到池结构中(回收)。由于从链接列表中删除项目非常有效,因此我认为没有问题。
next
在删除节点后将其指针链接到该节点。如果您不想自己麻烦做,那么双链表将是您选择的DataStructure。
我在使用的lib上找到的一种干净通用的解决方案是使用可锁定的映射。
你有2个操作lock()
和unlock()
,当你迭代在地图上你lock()
,现在从这个角度每次变更地图不生效运行,它只是被压入一个CommandQueue
一旦你调用运行unlock()
。
因此,删除实体将具有以下伪代码:
void lockableMap::remove(std::string id) {
if(isLocked) {
commandQueue.add(new RemoveCommand(id));
} else {
//remove element from map
}
当你 unlock()
isLocked = false
commandQueue.execute(this);
唯一需要考虑的是,您将仅在循环后删除实体。
编辑:这是西蒙提出的解决方案。
这是我从Liosan得到的答案:https : //gamedev.stackexchange.com/a/46765/24633
我有两种方法。
调用要删除的对象时,它实际上设置了两个标志:
1.告诉容器对象已被删除
2.告诉容器要求删除哪些对象
void object::deleteObject()
{
container->objectHasBeenDeleted = true;
isToDelete = true;
}
一个 使用对象向量
std::vector<object*> objects;
然后在更新功能中,检查是否已删除对象,如果是,则遍历所有对象并删除具有删除标志的对象
void container::update()
{
if (objectHasBeenDeleted)
{
std::vector<object*>::iterator ListIterator;
for(ListIterator=objects.begin(); ListIterator!=objects.end();)
{
if( (*ListIterator)->isToDelete )
{
ListIterator = objects.erase(ListIterator);
delete *ListIterator;
}
else {
++ListIterator;
}
}
objectHasBeenDeleted = false;
}
}
两个 使用(指向a的)对象向量。
std::vector<object*> *objects;
在更新功能中,如果要删除对象,请遍历这些对象,然后将不希望删除的对象添加到新向量中。删除对象向量并将指针设置为新向量
void container::update()
{
if (objectHasBeenDeleted)
{
std::vector<object*> *newVector;
unsigned long i;
for (i = 0; i < objects->size(); i++)
{
if (!objects->at(i)->isToDelete)
{
newVector->push_back(objects->at(i));
}
}
delete objects;
objects = newVector;
objectHasBeenDeleted = false;
}
}