提高基于组件的游戏引擎的效率

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (61)

我正在尝试构建一个基于组件的游戏引擎,我的效率肯定是缺乏的。这个问题在我的碰撞检测中最为明显,因为我将每个GameObject与其他游戏对象进行比较以查看它们是否发生碰撞。这是碰撞检测功能:

void PhysicsSystem::update(float dt) {
std::vector<GameEngine::GameObject> moveObjects = manager->getAllObjectsWithComponent("move");
std::vector<GameEngine::GameObject> physicsObjects = manager->getAllObjectsWithComponent("physics");

for (int i = 0; i < moveObjects.size(); i++) {
    MoveComponent* mComponent = static_cast<MoveComponent*>(manager->getComponentByType("move", moveObjects[i]));
    PhysicsComponent* pComponent = static_cast<PhysicsComponent*>(manager->getComponentByType("physics", moveObjects[i]));
    RenderComponent* rComponent = static_cast<RenderComponent*>(manager->getComponentByType("render", moveObjects[i]));

    if (pComponent == nullptr || mComponent == nullptr || rComponent == nullptr) {
        continue;
    }

    if (!pComponent->isSolid()) {
        continue;
    }

    glm::vec4 coords1 = rComponent->getRenderCoords();


    for (int j = 0; j < physicsObjects.size(); j++) {
        PhysicsComponent* pComponent2 = static_cast<PhysicsComponent*>(manager->getComponentByType("physics", physicsObjects[j]));
        RenderComponent* rComponent2 = static_cast<RenderComponent*>(manager->getComponentByType("render", physicsObjects[j]));
        if (pComponent2 == nullptr || rComponent2 == nullptr) {
            continue;
        }

        if (!pComponent2->isSolid()) {
            continue;
        }


        glm::vec4 coords2 = rComponent2->getRenderCoords();



        int dist = sqrt(pow((coords1.x - coords2.x), 2) + pow((coords1.y - coords2.y), 2));
        if (dist > pComponent->getCollisionRadius()) {
            continue;
        }

        if (GameEngine::Physics::checkCollision(coords1, coords2)) {
            pComponent->addCollision(coords2);
        }
    }
}

我试图通过使用碰撞半径忽略与当前GameObject不相近的GameObject来提高效率,但似乎没有做任何事情,真正导致问题的代码行是

PhysicsComponent* pComponent2 = static_cast<PhysicsComponent*>(manager->getComponentByType("physics", physicsObjects[j]));
RenderComponent* rComponent2 = static_cast<RenderComponent*>(manager->getComponentByType("render", physicsObjects[j]));

这些调用我的GameObjectManager类中的函数。这是该函数的代码:

Component* GameObjectManager::getComponentByType(std::string type, GameObject object) {
    std::unordered_map<std::string, std::unordered_map<GLuint, Component*>>::iterator it = componentsByType.find(type);
    if (it == componentsByType.end()) {
        return nullptr;
    }
    std::unordered_map<GLuint, Component*>::iterator it2 = it->second.find(object.getGameObjectID());
    if (it2 == it->second.end()) {
        return nullptr;
    }

    return it2->second;
}

如果我取出这两行,游戏速度会显着提高。有什么我做错了吗?我认为在unordered_map中找到一个对象是一个恒定的时间操作,所以我不确定如何提高速度。有没有更有效的方法来处理我的组件?非常感谢任何帮助,谢谢!

提问于
用户回答回答于

您可以在内部循环中查询组件的moveObjects.size()时间,这意味着需要进行大量的冗余工作。

你应该在主循环之前放置一个预处理循环,它收集组件:

for (int j = 0; j < physicsObjects.size(); j++) {
    PhysicsComponent* pComponent2 = static_cast<PhysicsComponent*>(manager->getComponentByType("physics", physicsObjects[j]));
    RenderComponent* rComponent2 = static_cast<RenderComponent*>(manager->getComponentByType("render", physicsObjects[j]));
    if (pComponent2 == nullptr || rComponent2 == nullptr) {
        continue;
    }

    if (!pComponent2->isSolid()) {
        continue;
    }

    // add pComponent2 and rComponent2 into an array here
}

然后,在内部循环中,使用收集的数据,而不是从管理器中查询它。

请注意,如果您有很多对象,您可能希望将它们放入一些空间分区数据结构(octree / Kd-tree / BSP-tree)以避免O(n^2)运行时间。

用户回答回答于

这里有很多地方我看到了很小的改进,虽然其中一些可能会带来相对较大的改进。您正在制作许多不需要制作的潜在大数据副本。

  1. moveObjects并且physicsObjects是矢量,并且是原始数据的副本。这些需要复制,还是const &存储在游戏管理器中的载体?
  2. 你有几个检查有pComponentmComponentrComponent。如果任何检查失败,则继续执行下一个对象。获取其中一个值,检查它nullptr,然后获取下一个值。做pComponent第一,并检查是否是实心的,另外两个之前。
  3. jfor循环做同样的事情。pComponent2rComponent2
  4. 检查距离时,不要计算平方根。比较距离的平方而不是。
  5. object参数传递给getComponentByTypeby,const &这样就不会复制它。你只访问它的一个字段。
  6. 使用基于范围的for循环。如果无法做到这一点,可以考虑将向量的大小存储在变量中,而不是调用size每个循环迭代。编译器可以优化冗余调用,但唯一可以确定的方法是检查生成的优化代码。

所属标签

可能回答问题的人

  • 找虫虫

    0 粉丝0 提问6 回答
  • 不吃貓的鱼oo

    5 粉丝466 提问5 回答
  • 优惠活动秘书

    0 粉丝2 提问5 回答
  • 爸爸

    腾讯 · 客户端安全 (已认证)

    4 粉丝4 提问5 回答

扫码关注云+社区

领取腾讯云代金券