简单的效率问题C ++(内存分配)..也许一些碰撞检测有帮助?

时间:2008-12-02 07:53:43

标签: c++ memory performance allocation

我正在用C ++(一个多向2d空间射击游戏)编写一个类似街机的小游戏,我正在完成碰撞检测部分。

以下是我如何组织它(我只是编造它可能是一个糟糕的系统):

每艘船都由圆形组件组成 - 每艘船中的组件数量是任意的(更多的组件,更多的CPU周期)。我有一个maxComponent距离,我在创建船时计算出来的距离基本上是我可以从船的中心到最远部分边缘绘制的最长线。我跟踪屏幕上的内容并使用这个maxComponentDistance来查看它们是否足够接近碰撞。

如果它们距离很近,我会开始检查不同船只的组件是否相交。这就是我的效率问题所在。

我有相对于船舶中心的组件的(x,y)位置,但它没有考虑船舶当前的旋转方式。我保持他们相对,因为我不希望每次船只移动时重新计算组件。所以我有一个小的旋转计算公式,我返回一个2d矢量,对应于相对于船舶中心的旋转考虑位置。

碰撞检测在GameEngine中,它使用2d-vector。我的问题是关于退货类型。我应该在每次调用函数时创建并返回一个二维矢量对象 要么 我应该给该组件对象一个额外的私有2d向量变量,在调用该函数时编辑私有变量,并返回指向该对象的指针吗?

我不确定内存分配的效率与拥有永久可编辑的私有变量。我知道也必须为私有变量分配内存,但不是每次检查冲突时,只有在创建新组件时才需要。组件在我的环境中不是恒定的,因为它们在船被销毁时被删除。

这是我的主要困境。我也很欣赏任何有关我的实际碰撞检测系统设计的指针。这是我第一次给它一个黑客(也许应该读一点)

提前致谢。

5 个答案:

答案 0 :(得分:2)

在每次调用getter-function时,你都应该尽量避免为component-vector做内存分配。相反,尽可能少地进行分配。例如,您可以在船舶的组件构成发生变化时更改,或者甚至更少(通过过度分配)。

您当然也可以调查内存池,预先分配大量此类组件并放入池中,这样您就可以在固定时间内分配新组件。

作为一般人(并且如果太明显而道歉)指出进行这种碰撞检测:将距离平方,而不是计算平方根。 :)

答案 1 :(得分:1)

如果你的2D矢量只是:

 class Vector2D { double x, y; };

然后一定要归还它! E.g:

  Vector2D function( ... );

或通过引用传递:

  void function( Vector2D * theReturnedVector2D, ... );

不惜一切代价避免:

 vector<double> function(...);

Vector类固有的常量堆分配/释放是一个错误!


从计算上讲,复制自己的Vector2D类非常便宜。与Vector&lt;&gt;不同,您自己的Vector2D类可以包含您喜欢的任何方法。

我过去曾使用过这个功能来合并distanceToOtherPointSquared(),scanfFromCommandLineArguments(),printfNicelyFormatted()和operator [](int)等方法。


或者我应该给该组件对象一个额外的私有2d-vector变量,在调用该函数时编辑私有变量,并返回指向该对象的指针?

注意多个函数调用使先前数据无效。这是灾难的秘诀!

答案 2 :(得分:0)

  1. 您可以从返回矢量开始,然后对其进行基准测试。谁知道,它可能足够快。使用分析器,您甚至可以查看运行时间的哪个部分。
  2. 您可以使用Memory Pool重复使用向量并减少复制
  3. 如果它们在整个引擎中重复,您可以尝试使用Flyweight pattern坐标来减少复制和分配。
  4. 保持组件中的数据是减少分配的好方法,但是在设计中引入了一些问题,比如使用向量的人取决于组件的生命周期。内存池可能更好。

答案 3 :(得分:0)

不要使用2D矢量。相反,使用vector point。同样适合您的碰撞检测。在这里使用2D向量只是错误的数据结构。

根据函数的内容,编译器将能够执行NRVO(即named return value optimization),这意味着在最佳情况下,返回向量具有 no 开销,即它永远不会被复制。但是,这只会在您使用函数的返回值初始化新实例时发生,并且当编译器能够跟踪函数内部的执行路径并查看每个返回路径时,将返回相同的对象。考虑以下两点:

vector<int> f(int baz) {
    vector<int> ret;
    if (baz == 42)
        ret.push_back(42);
    return ret;
}

vector<int> g(int baz) {
    if (baz == 42)
        return vector<int>(1, 42);
    else
        return vector<int>();
}

编译器可以对f的呼叫执行NRVO,但不能对g执行。

答案 4 :(得分:0)

在堆上和堆栈上分配内存之间存在很大差异。在堆上分配,例如,使用new / delete或malloc / free是非常慢的。在堆栈上分配真的非常快。对于堆栈,通常缓慢的部分是复制对象。所以注意矢量等,但返回简单的结构可能没问题。