std :: map访问速度太慢了?

时间:2013-07-29 09:06:36

标签: c++ map entity std

我最近为我的游戏引擎实现了一个实体组件系统。每个实体都会保留一个这样的组件映射:

Component.h

enum COMPONENT_INFO {
    COMPONENT_POSITION = 0, 
    COMPONENT_PHYSICS,
    COMPONENT_RENDERABLE
 };

Entity.h

class Entity {
public:
    std::bitset<NUM_COMPONENTS> componentBits;
    std::map<COMPONENT_INFO, Component*> components;
    ..
    ..

    Component *getComponent(COMPONENT_INFO inf) {
        return components[inf];
    }
 };

我的System类每帧更新每个实体:

void update(Entity *e, float delta) { 
        PositionComponent *cmp=(PositionComponent*)e->getComponent(COMPONENT_INFO::COMPONENT_PHYSICS);
        //x += 1.0f;
        cmp->x += 1.0f;
    }

一切都按预期工作,但我在访问地图时遇到了巨大的性能问题。当我创建10000个实体并迭代它们(系统实际迭代)时,我得到80 FPS蓝色空白系统(没有视觉效果,只有普通屏幕)。但是当我注释掉访问部分并且仅使用x += 1.0f;时,FPS可以递增地增加到1000.就像那样:

void update(Entity *e, float delta) { 
        x += 1.0f; //btw the system has a local x value.
    }

所以问题只是通过地图访问组件。我还能在这样的系统上使用什么?或者我在访问地图时做错了什么?

重要编辑:这只是一个试驾,我的意思是每个实体可能有很多组件,而不仅仅是3.我只是为了测试目的而编写这些组件。

3 个答案:

答案 0 :(得分:2)

首先,你的方法getComponent正在使用operator [],它不仅检索具有给定键的实例,而且如果不存在,则插入一个元素。

http://www.cplusplus.com/reference/map/map/operator%5B%5D/

在给定的实现中,您将自己限制为实体中每种类型的一个组件,这可能不是最佳选择。例如,您可能希望为一个实体提供一些可渲染组件,以执行各种操作,如粒子,网格渲染等。

Map不保证对象按顺序放置在内存中,这可能会导致逐个处理时出现缓存未命中。例如,使用std :: vector会更有效,并将COMPONENT_INFO保留在组件对象本身中。

另一种解决方案是向系统类添加可创建特定类型组件的方法,同时对每个组件实例进行一些操作。然后,系统可以保留每种组件类型的向量,并对这些组件进行批处理。

希望这会有所帮助。

编辑:

这个想法是当你添加/创建新的Collision组件时,组件本身会在系统中注册,提供类型和指向自身的指针。对于可渲染对象等也是如此。您可以为系统中的每种组件类型提供向量映射。当您需要解析collsion时,您只需检索所有可碰撞物(引用向量)。你进行一次log(n)查找,然后迭代所有可碰撞物(由于在向量中的指针在内存中按顺序排列,使其更加缓存友好)。

您是否也在发布版本中测试性能?

答案 1 :(得分:2)

由于每个实体的组件数量似乎是固定的,我会抛弃地图并使用Entity中的成员变量来保存每个组件以及一个getter。这也将避免更新功能中的强制转换:

class Entity {
private:
    PositionComponent* m_positionComponent;
    PhysicsComponent* m_physicsComponent;
    RenderableComponent* m_renderableComponent;
public:
    // initialize the components in the constructor
    PositionComponent* getPositionComponent() {
        return m_positionComponent;
    }

    // more getters for the other components
}

或者,如果您想拥有更多组件类型并希望保持设计灵活,您可能希望将它们存储在向量中,使用枚举值对其进行索引。这将完全避免地图查找,并为您提供更好的性能。

答案 2 :(得分:2)

由于COMPONENT_INFO的最高数量已得到修复,您可以使用array<Component*>(或vector<>并使用例如myArray[COMPONENT_INFO::COMPONENT_PHYSICS]进行寻址。您可能需要检查nullptr,虽然。