所以,我有一个3d平台游戏。我希望有一个按钮,如果你拿着它,它会让你回到过去"。值得庆幸的是,游戏相当简单,只有一个实体,所以每个帧唯一需要保存的是。
struct Coord {
float x;
float y;
float z;
}
structure Bool6 {
bool front;
bool back;
bool left;
bool right;
bool top;
bool bottom;
}
struct Player {
Coord Pos;
Coord Vel;
Bool6 Col;
}
但是我担心这是很多数据,特别是因为我的游戏理论上运行在大约60fps左右,所以保存5秒左右(300帧)的数据可以在滚动支持时访问。我认为每个框架都做这样的事情
Player Data[300];
for (int i = 299; i > 0; i--)
{
Data[i] = Data[(i-1)];
}
Data[0] = "THIS FRAMES DATA";
然而,这听起来意味着在存储每一帧时只会产生大量的处理能力。
它们是一种更有效的方式来存储这些数据,使所有数据按顺序排列吗?
也是他们可以告诉阵列插槽它没有任何东西的方式吗?如果播放器在所有阵列插槽填满之前或回滚之后尝试回滚,那么它们不会出现问题?我相信C#我会把它设置为等于NULL ......但这并不适用于c ++,可能是因为我使用的是结构。
非常感谢!
答案 0 :(得分:2)
然而,这听起来像是一种令人难以置信的处理能力
在做出这样的陈述之前,做数学是很有用的。您所关注的数据似乎约为40个字节,因此40 * 300 = 12 kB。这很容易适应内存,远远不是一个令人难以置信的处理能力。在现代计算机上。
它们是一种更有效的方式来存储这些数据,使所有数据按顺序排列吗?
是。如果你的游戏是确定性的,你需要存储的只是玩家的输入和5秒前的一个游戏状态。回滚时,重置游戏状态并重播用户输入以重新计算每个帧数据。
有关如何在gamedev stackexchange上设计自己的重播系统的详细讨论,请参阅this question。
答案 1 :(得分:1)
我认为300个相对较小的元素阵列根本不会让你失望,你尝试过它吗?
那就是说你可以将它存储在一个向量中并将迭代器保存到“当前”并更新它。
答案 2 :(得分:0)
如果您认为存储300很多,则存储较少,例如您可以存储1/5帧:
....|....|....|....|..*
* is your position, `/` the frames you will store and `....` other frames
并且你不必每次都复制所有保存的数据...只需删除第一个并在最后添加一个,你可以使用std :: list,你不会有复制任何数据
在每5帧中,您会将myList.pop_front();
称为最早的帧,myList.push_back();
称为最新的
答案 3 :(得分:0)
我认为存储要求并不严格 - 即使有300帧,这个小物体也会占用比普通纹理少得多的内存。
我建议你避免使用原始数组并查看使用std :: vector几乎同样有效,并且会自动调整大小,因为你需要更多的缓冲空间(如果你突然需要8秒或者fps上升到100你不会突然耗尽缓冲空间)。这也解决了您使用未填充“插槽”的难度,因为矢量具有您可以有效访问的已知大小。
我也可能会建议您不需要存储每一帧 - 像波斯王子这样的游戏,如果你仔细观察它们就会不那么顺利,当时间倒退时表明他们可能只存储每一帧或者像每一帧一样,每秒两次。
答案 4 :(得分:0)
除非你在MCU上运行,否则数据大小(鉴于你提供的结构)与游戏的其余部分相比可以忽略不计(~10K,如果我正确计算它,对于现代个人电脑)。
以CPU为单位,以你指定的方式和每一帧移动数据,可能是次优的(它将每秒移动10K大约60次,或者每秒600K,这可能 - 尽管可能不会 - 明显的)。如果它成为一个问题,我会去一个循环缓冲区(例如,在boost :: circular_buffer中),或者std :: deque或std :: list(deque可能是我的第一选择);所有这些都有O(1)插入/删除时间,插入/删除是大多数时候你需要的。从理论上讲,还有一个选项可以使用memmove()来加快速度而不会改变很多东西,但它很容易出错,并且仍然具有O(N)复杂性,所以我宁愿不去做。
答案 5 :(得分:-2)
实际上,您可以每帧执行更少的操作来存储状态。
您可以使用std::vector
。然后,在每一帧,push_back()
新状态和if(vector.size() > 300)
,然后执行pop_front()
。
如果您认为这还不够,请尽量少保存(每半秒一次)。回滚信息时,可以在值之间进行插值。
你该死的奥斯曼,矢量没有pop_front,所以你可以使用vector.erase(vector.begin()):)所以你不必使用链表。