C++ 中的 3D 运动场
Posted
技术标签:
【中文标题】C++ 中的 3D 运动场【英文标题】:3D playing field in C++ 【发布时间】:2020-03-15 21:44:07 【问题描述】:我对 C++ 非常陌生,并且很难创建 3D 游戏板。 棋盘的大小可以在整个游戏过程中增加。
我的第一个想法是使用嵌套向量。
vector<vector<vector<int>>> board
想法是,它很容易访问 (board[z][y][x]
),而且动态分配不会有问题。但是我听说嵌套向量不是一个好主意,因为它破坏了“缓存友好性”。相反,我应该使用一维向量和使用数学的“假”维度。
我认为这意味着创建大小为 (x * y * z) 的向量。在这种情况下,当我想“转到”nested_vector_board[0][1][0] 时,我使用 board[x]。如果我想去nested_vector_board[1][1][0],我使用board[x * y + x]。
我的理解正确吗?板子大小调整时我该怎么办?例如,如果我想让板子更宽,似乎我需要手动移动所有数据。 更重要的是,有没有更好、更简单的方法呢?
我会欢迎任何建议,并在此先感谢您!
【问题讨论】:
'但是我听说嵌套向量不是一个好主意,因为它破坏了“缓存友好性”。'在您的程序正常运行之前,不要担心这样的微优化。 @JosephSible-ReinstateMonica 使用适当的数据结构不是微优化。 在几乎所有时间都在等待用户输入的程序中,不必担心 CPU 性能。 所有答案都暗示了一些东西。我的建议是确保无论您使用什么,都应该将细节隐藏在接口后面,这意味着当您交换板如何实现的细节时,您不需要更改程序其余部分的任何内容。最终,您将拥有一个工作程序,并希望了解板如何存储在内存中,并且您不想更改整个程序来执行此操作。您可能想要使用它的原因是 a) 访问速度、重新分配速度、每个分配的最大大小 【参考方案1】:如果您不知道您的访问模式是什么,您就无法选择最佳解决方案。此外,如果您没有可行的解决方案,您将无法衡量您的表现,只能猜测最佳解决方案,您可能会猜错。
我建议用清晰的界面实现您自己的 3D Board 类,并检查您的简单解决方案是否足够好。如果速度太慢,您可以将实现换成更合适的实现。
这里有一个例子,你可以如何实现你的板子:
#include <iostream>
#include <unordered_map>
#include <map>
template <class ValueType>
class board_3d
public:
using key_t = std::tuple<size_t, size_t, size_t>;
using value_t = ValueType;
ValueType& operator[](key_t key)
return m_data[key];
const ValueType& operator[](key_t key) const
return m_data[key];
private:
std::map<key_t, ValueType> m_data;
;
int main()
board_3d<int> my_board;
my_board[0,0,0] = 5;
return 0;
std::map
最终可能不是你想要的。访问是 O(log n)。要进行优化,您可以使用具有 O(1) 访问权限的 std::unordered_map
或使用向量的任何实现。您还可以添加一个调整大小的函数,该函数负责将数据从旧存储复制到新存储。
【讨论】:
【参考方案2】:我认为你可以使用稀疏表示:
std::map<int, std::map<int, std::map<int, int> > > board;
您可以使用方括号来引用此映射中的值:
board[x][y][z] = 13;
但是,这种结构可能混乱且效率低下,因此您可以将 x、y 和 z 打包成一个复合键并在 std::unordered_map 中使用它。
struct XYZ_Key
int32_t x;
int32_t y;
int32_t z;
bool operator==(const XYZ_Key& o) const
return (x == o.x) && (y == o.y) && (z == o.z);
size_t hashCode() const
return ((((11 + x) * 7) + y) * 5) + z) * 3;
;
std::unordered_map<XYZ_Key, int, decltype(std::mem_fn(&XYZ_Key::hashCode)) > board;
【讨论】:
【参考方案3】:为了避免嵌套向量,如何在堆栈上构建一个 2D 指针网格,大小固定(设置为电路板大小的上限),单个向量保存所有数据?像这样的东西(这里用智能指针实现):
#include <iostream>
#include <vector>
#include <memory>
int main()
const int MAXSIZE = 512
int width = 5;
int height = 5;
int depth = 5;
std::unique_ptr<std::vector<int>> grid[MAXSIZE][MAXSIZE];
for (int i = 0; i < width; ++i)
for (int j = 0; j < height; ++j)
grid[i][j] = std::make_unique<std::vector<int>>();
for (int k = 0; k < depth; ++k)
grid[i][j]->push_back(k);
//To iterate over all the contents:
for (int i = 0; i < width; ++i)
for (int j = 0; j < height; ++j)
for (int k = 0; k < depth; ++k)
std::cout << grid[i][j]->at(k) << " ";
std::cout << " // ";
std::cout << std::endl;
return 0;
您可能需要使用std::shared_ptr
,具体取决于游戏的运行方式。我的理解是这种结构允许比嵌套向量方法更有效的内存访问;也许缺点是必须一次分配更大的网格?
【讨论】:
以上是关于C++ 中的 3D 运动场的主要内容,如果未能解决你的问题,请参考以下文章
在 C++ 中的 OpenGL 中将坐标从 3D 透视投影映射到 2D 正交投影