我正在尝试构建一个基于组件的游戏引擎,但是我的效率肯定不足。该问题在碰撞检测中最明显,因为我将每个GameObject与另一个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中找到对象是恒定时间的操作,因此我不确定如何提高速度。有没有更有效的方式来处理我的组件?任何帮助将不胜感激,谢谢!
答案 0 :(得分:0)
在许多地方,我看到一些小的改进,尽管其中一些可能会带来相对较大的改进。您正在制作大量不需要的潜在大数据副本。
moveObjects
和physicsObjects
是向量,并且是原始数据的副本。这些是否需要复制,或者它们可以const &
是游戏管理器中存储的向量?pComponent
,mComponent
和rComponent
的几张支票。如果任何检查失败,则继续下一个对象。获取这些值之一,检查其是否为nullptr
,然后获取下一个。首先进行pComponent
,然后再检查其是否牢固。j
和pComponent2
的{{1}}循环执行相同的操作。rComponent2
将object
参数传递到getComponentByType
,这样就不会复制它。您只访问它的一个字段。const &
。编译器可以优化冗余调用,但是唯一可以确定的方法是检查生成的优化代码。答案 1 :(得分:0)
您在内部循环中查询组件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
}
然后,在内部循环中,使用收集的数据,而不是从管理器中查询它。
请注意,如果您有很多对象,则可能希望将它们放入某些空间分区数据结构(八叉树/ Kd-树/ BSP-树)中,以避免运行O(n^2)
。