[英]Organizational system for moving tiles in grid-based level
conceptual problem here. 这里的概念性问题。
I have an array which will be rendered to display tiles in a grid. 我有一个数组,将其呈现为在网格中显示图块。 Now, I want these tiles to be able to move - but not just around in the grid. 现在,我希望这些图块能够移动-但不仅仅是在网格中移动。 Per-pixel. 每像素。 It does need to be a grid, because I need to shift whole rows of tiles, and be able to access tiles by their position, but it also needs to have per-pixel adjustment, while still keeping the "grid" up to date. 它确实需要是一个网格,因为我需要移动整行图块,并能够按其位置访问图块,但是它还需要进行逐像素调整,同时仍保持“网格”最新。 Picture a platforming game with moving tiles. 想象一下带有移动瓷砖的平台游戏。
There are a few organizational systems with which I could do this, and I'll outline a few I thought of as well as their pros and cons (XY-style) in case it helps you understand what I'm saying. 我可以使用一些组织系统来完成此工作,并且我将概述一些我认为的方法以及它们的优缺点(XY风格),以防它有助于您理解我的意思。 I'm asking if you think one of these is best, or think of a better way. 我想问的是,您是否认为其中之一是最好的,还是想一种更好的方法。
One way would be to place objects in the array with the properties xOffset
and yOffset
. 一种方法是将对象放置在具有属性xOffset
和yOffset
的数组中。 I would then render them in their tile position plus their offset. 然后,我将它们渲染在其图块位置加上其偏移量。 ( x * tileWidth + tile.xOffset
). ( x * tileWidth + tile.xOffset
)。 Pros: maintains vanilla grid-system. 优点:保持香草网格系统。 Cons: Then I would have to adjust each tile to its actual grid location once it moved. 缺点:一旦移动,我将不得不将每个图块调整到其实际网格位置。 Also, the "grid" position would become a bit confused as tiles are moving. 另外,随着瓷砖的移动,“网格”位置会变得有些混乱。 (Side note: If you think this is a good way, how would I handle collisions? It wouldn't be as simple as player.x / tileWidth
anymore.) (旁注:如果您认为这是一种好方法,那么我将如何处理冲突?它不再像player.x / tileWidth
那样简单。)
Another would be to place lots of objects with x
s and y
s and render them all. 另一个方法是放置许多带有x
s和y
s的对象并将它们全部渲染。 Pros: Simple. 优点:简单。 Cons: Then I would have to check each one to see if it's in the row I want to shift before doing so. 缺点:然后,在执行此操作之前,我将必须检查每个对象是否都在我要移动的行中。 Also, collisions could not simply check the one tile a player is on, they would have to check all entities. 而且,碰撞不能简单地检查玩家所在的那张图块,而是必须检查所有实体。
Another I thought of would be a sort of combination of the two. 我想到的另一个是两者的结合。 Tiles would be in the original array and get render as x * tileWidth
normal tiles. Tiles将位于原始数组中,并以x * tileWidth
普通瓦片的形式呈现。 Then, when they move, they are deleted from the grid and placed in a separate array for moving tiles, where their x
and y
are stored. 然后,当它们移动时,将它们从网格中删除,并放置在用于移动图块的单独数组中,并在其中存储它们的x
和y
。 Then the collisions would check the grid the fast way and the moving tiles the slow way. 然后,碰撞将以快速方式检查网格,而以慢速方式检查移动瓷砖。
Thanks! 谢谢!
PS: I'm using JavaScript, but it shouldn't be relevant. PS:我使用的是JavaScript,但应该无关紧要。
PPS: Forgive me if it's not Stack Overflow material. PPS:原谅我不是Stack Overflow的内容。 This was the best fit, I thought. 我认为这是最合适的。 It's not exactly code review, but it's not specific to GameDev. 这不是完全的代码审查,但不是特定于GameDev。 Also I needed a tag, so I picked one somewhat relevant. 另外,我需要一个标签,所以我选择了一个相关标签。 If you guys recommend something else I'll be happy to switch it right over and delete this one. 如果你们推荐其他东西,我很乐意将其切换并删除。
PPPS: Sorry if repost, I have no idea how to google this question. PPPS:对不起,如果转贴,我不知道如何用Google搜索这个问题。 I tried to no avail. 我无济于事。
(Side note on handling collisions: Your obstacles are moving. Therefore, comparing the player's position to grid is no longer ever sufficient. Furthermore, you will always have to draw based on the object's current position. Both of these are unavoidable, but also not very expensive.) (有关处理碰撞的注释:您的障碍物正在移动。因此,将玩家的位置与网格进行比较已不再足够。此外,您始终必须根据对象的当前位置进行绘制。这都是不可避免的,但也并非如此非常贵。)
You want the objects to be easy to look up, while still being able to draw them efficiently and, more importantly, quickly checking for collisions. 您希望对象易于查找,同时仍然能够有效地绘制它们,更重要的是,可以快速检查碰撞。 This is easy to do: store the objects in the array, and for the X and Y positions keep indexes which allow for 1) efficiently querying ranges and 2) efficiently moving elements left and right (as their x and y positions change). 这很容易做到:将对象存储在数组中,并且对于X和Y位置保留索引,这些索引允许1)有效查询范围和2)有效向左和向右移动元素(随着它们的x和y位置改变)。
If your objects are going to be moving fairly slowly (that is, on any one timestep, it is unlikely for an object to pass very many other objects), your indexes can be arrays! 如果您的对象移动得相当慢(也就是说,在任何一个时间步上,一个对象都不太可能传递很多其他对象),则索引可以是数组! When an object moves past another object (in X, for instance), you just need to check its neighbor in the X index array to see if they should swap places. 当一个对象经过另一个对象(例如,在X中)时,您只需要检查X索引数组中的它的邻居,看看它们是否应该交换位置。 Keep doing this until it does not need to swap. 继续执行此操作,直到不需要交换为止。 If they're moving slowly, the amortized cost of this will be very close to O(1). 如果他们行动缓慢,则其摊销成本将非常接近O(1)。 Querying ranges is very easy in an array; 在数组中查询范围非常容易。 binary search for the first greater element, and also for the last smaller element. 二进制搜索第一个较大的元素,以及最后一个较小的元素。
Summary/Implementation: (Fiddle at https://jsfiddle.net/LsfuLo9p/3/ ) 摘要/实现:(在https://jsfiddle.net/LsfuLo9p/3/上显示小提琴)
Initialize (O(n) time): 初始化(O(n)时间):
Objs.
创建名为Objs.
的对象数组Objs.
Objs
) pairs, sorted in X, called Xs.
制作(x位置,参考Objs
)对的数组,以X排序,称为Xs.
Objs
) pairs, sorted in Y, called Ys.
创建一个数组(y位置,引用Objs
)对,以Y排序,称为Ys.
Xs
and Ys
, tell the object in Objs
its index in those arrays (so that Xs
has indexes to Objs,
and Objs
has indexes to Xs.
) 对于Xs
和Ys
每个元素,在Objs
告诉对象在这些数组中的索引(这样Xs
拥有Objs,
索引Objs,
而Objs
拥有Xs.
索引Xs.
) When an object moves up in Y (O(1) expected time per moving object, given that they're moving slowly): 当一个对象以Y向上移动时(假设每个移动对象移动缓慢,则期望时间为O(1)):
Objs
, find its index in Ys.
使用Objs
,在Ys.
找到其索引Ys.
Ys.
将其与Ys.
的下一个最大值进行比较Ys.
If it's greater, swap them in Ys
(and update their Y indices in Objs
). 如果更大,则在Ys
交换它们(并在Objs
更新其Y索引)。 (It's easy to apply this to the other three directions.) (将其应用于其他三个方向很容易。)
When the player moves (O(log n + k 2 ) time, where k is the maximum number of items that can fit in a row or column): 玩家移动时(O(log n + k 2 )时间,其中k是可容纳在一行或一列中的最大项目数):
Xs
for small,
the smallest X above Player.X,
and large,
the largest X+width below Player.X.
看在Xs
为small,
上面最小的X Player.X,
和large,
下面的最大X +宽度Player.X.
If large
≤ small
, return the range [large, small].
如果large
≤ small
,则返回范围[large, small].
Ys
for small,
the smallest Y above Player.Y,
and large,
the largest Y+height below Player.Y.
看在Ys
为small,
最小的ÿ上述Player.Y,
和large,
最大的Y +高度低于Player.Y.
If large
≤ small
, return the range [large, small].
如果large
≤ small
,则返回范围[large, small].
(You can improve the time of this to O(log n + k) by using a hashmap to check for set intersections.) (您可以通过使用哈希图检查设置的交集,将时间缩短为O(log n + k)。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.