0

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

这是我组织它的方式(我只是编造它,所以它可能是一个糟糕的系统):

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

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

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

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

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

这是我的主要困境。我也很感激任何关于我的实际碰撞检测系统设计的指针。这是我第一次破解它(也许应该读一下)

提前致谢。

4

5 回答 5

2

您绝对应该尽量避免在每次调用 getter 函数时为您的组件向量分配内存。相反,尽可能少地进行分配。例如,您可以在船舶的组件组成发生变化时执行此操作,或者更不用说(通过过度分配)。

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

作为进行这种碰撞检测时的一般(如果太明显,请道歉)点:对距离进行平方,而不是计算平方根。:)

于 2008-12-02T07:57:44.067 回答
1

如果您的 2D 矢量只是:

 class Vector2D { double x, y; };

然后一定要退货!例如:

  Vector2D function( ... );

或通过引用传递:

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

不惜一切代价避免:

 vector<double> function(...);

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


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

我过去曾使用此功能来合并诸如 distanceToOtherPointSquared()、scanfFromCommandLineArguments()、printfNicelyFormatted() 和 operator[](int) 等方法。


或者我应该给那个组件对象一个额外的私有二维向量变量,在调用函数时编辑私有变量,然后返回一个指向该对象的指针?

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

于 2008-12-03T01:17:54.233 回答
0
  1. 您可以从返回一个向量开始,然后对其进行基准测试。谁知道,它可能已经足够快了。使用分析器,您甚至可以查看哪些部分占用了运行时间。
  2. 您可以使用内存池来重用向量并减少复制
  3. 如果它们在整个引擎中重复,您可以尝试使用享元模式的坐标来减少复制和分配。
  4. 将数据保留在组件中是减少分配的好方法,但会在您的设计中引入一些陷阱,例如使用向量的人取决于组件的生命周期。内存池可能更好。
于 2008-12-02T08:02:11.390 回答
0

不要使用 2D 矢量。而是使用 a vectorof points。同样适用于您的碰撞检测。在这里使用二维向量只是错误的数据结构。

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

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>();
}

编译器可以对 的调用执行 NRVO f,但不能对g.

于 2008-12-02T08:24:56.180 回答
0

在堆上分配内存和在栈上分配内存有很大的不同。在堆上分配,例如,使用 new/delete 或 malloc/free 非常慢。在堆栈上分配确实非常快。使用堆栈,通常较慢的部分是复制您的对象。所以要注意向量等,但返回简单的结构可能是可以的。

于 2008-12-03T03:20:38.523 回答