旋转的无限/重复世界的数学/计算

时间:2011-11-11 13:30:08

标签: math cocos2d-iphone game-physics cclayer

如何创建一个处理旋转的无限/重复世界,就像在这个游戏中一样:

http://bloodfromastone.co.uk/retaliation.html

我通过这样的层次结构编码了我的旋转移动世界:

场景
- mainLayer(CCLayer)
- rotationLayer(CCNode)
- positionLayer(CCNode)

rotationLayer和positionLayer具有相同的大小(目前为4000x4000像素)。

我通过旋转rotationLayer来旋转整个世界,我通过移动positionLayer来移动整个世界,这样玩家总是在设备屏幕上保持居中,这就是移动和旋转的世界。

现在我想做到这一点,如果玩家到达世界的界限(世界被移动,以便世界界限接触到设备屏幕边界),那么世界被“包裹”到相反的界限使世界变得无限。如果世界不旋转那很容易,但现在它确实如此,我不知道如何做到这一点。我在数学和数学思考方面都很傻,所以我需要一些帮助。

现在我认为我不需要任何与cocos2d-iphone相关的帮助。我需要的是一些方法来计算我的球员是否超出了世界范围,然后以某种方式来计算我必须给世界包裹世界的新位置。

我想我必须计算一个圆形的半径,这个圆形将是我在广场世界中的代工厂,无论方形世界处于什么角度,都将确保可见的矩形(屏幕)始终位于世界广场的边界。然后我需要一种方法来计算可见的矩形边界是否在边界圆之外,如果是这样的话,我需要一种方法来计算边界圆中的新相对位置以移动世界。所以说明我添加了5张图片。

可见矩形在旋转的方形世界内的边界内部很好:
Visible rectangle well inside bounds circle inside a rotated square world

可见矩形顶部在旋转的方形世界中击中边界圆圈:
enter image description here

旋转的方形世界移动到相反的垂直位置,以便可见矩形的底部现在在旋转的世界内击中边界:
enter image description here

可见矩形顶部的另一个例子是在旋转的方形世界中击中边界圈以说明不同的场景:
enter image description here

再次旋转的方形世界移动到相反的垂直位置,以便可见矩形的底部现在在旋转的世界内击中边界圈:
And again rotated square world moved to opposite vertical position so that bottom of visible rectangle now hitting bounds circle inside rotated world

在非旋转的情况下移动positionLayer是我弄清楚的数学,正如我所说,只要世界没有旋转,我就可以解决这个问题,但确实如此。移动/定位的world / CCNode(positionLayer)位于旋转的world / CCNode(rotationLayer)内。旋转的rotationLayer的锚点始终位于屏幕的中心,但是当移动的positionLayer位于旋转的rotationLayer内时,它会围绕rotationLayer的锚点旋转。然后我迷路了...当我将positionLayer向下移动到足以使其顶部边框到达屏幕顶部我需要将该positionLayer包装为JohnPS描述但不是那么简单,我需要它根据rotationLayer CCNode的旋转包装在向量中。这个我不知道该怎么做。

谢谢你 索伦

3 个答案:

答案 0 :(得分:7)

像约翰所说,最简单的事情就是建立一个圆环世界。想象一下,你的船是甜甜圈表面上的一个点,它只能在表面上移动。假设您位于两个圆圈(图片中的红色和紫色)​​相交的点:

Circles on a torus

如果您关注这些圈子,您将最终到达您开始的地方。另外,请注意,无论你如何在表面上移动,你都无法达到“边缘”。环面的表面没有这样的东西,这就是为什么它用作无限的2D世界是有用的。它有用的另一个原因是方程非常简单。您可以通过两个角度指定环面上的位置:从紫色圆圈上的“原点”行进的角度,找到红色圆圈以及您在红色圆圈上行进的角度,以找到您感兴趣的点。角度包裹在360度。我们称之为thetaphi两个角度。它们是您船舶在世界上的坐标,以及当您改变速度等时所改变的内容。您基本上将它们用作xy,除非您必须确保始终使用模数你改变了它们(你的世界将在每个方向上只有360度,然后它会环绕)。

现在假设您的船位于坐标(theta_ship,phi_ship)并且方向为gamma_ship。你想绘制一个方形窗口,船的中心和长度/宽度等于整个世界的某个百分比n(假设你只希望一次看到世界的四分之一,那么你设置{{1并将窗口的长度和宽度设置为n = sqrt(1/4) = 1/2)。要执行此操作,您需要一个函数,该函数采用屏幕坐标(n*2*pi = pix)中显示的点,并在世界坐标(ytheta中吐出一个点)。例如,如果您问它世界的哪个部分对应phi,它应该返回船(0,0)的坐标。如果船舶的方向为零((theta_ship,phi_ship)x将与ytheta对齐),则某些坐标phi将对应{{1其中(x_0,y_0)是一个缩放因子,与人们在屏幕中可以看到的世界的多少以及(theta_ship+k*x_0, phi_ship+k*y_0)k上的边界有关。 x的旋转引入了一点触发,详见下面的函数。有关数量的确切定义,请参见图片。 !Blue is the screen coordinate system, red is the world coordinate system and the configuration variables (the things that describe where in the world the ship is). The object represented in world coordinates is green.

坐标转换函数可能如下所示:

y
我认为,这就是它。数学只是一些相对简单的触发器,你应该做一点绘画来说服自己这是正确的。或者,您可以通过使用rotations matrices及其更大的兄弟,刚体变换(特殊欧几里得群体SE(2))以更自动化的方式获得相同的答案。对于后者,我建议阅读免费在线Murray, Li, Sastry的前几章。

如果你想做相反的事情(从世界坐标到屏幕坐标),你必须或多或少做同样的事情,但相反:

gamma_ship

答案 1 :(得分:2)

你需要定义你想要的“对立边界”。有关二维示例,请参阅Fundamental polygon。有四种方法可以将正方形的两侧映射到另一侧,然后得到一个球体,真实投影平面,克莱因瓶或环面。经典的街机游戏Asteroids实际上有一个环面游戏。

这个想法是你需要将每个边界点粘合到一些有意义且一致的边界点上。

如果你的世界真的是三维的(不仅仅是二维表面地图上的三维),那么我认为你的任务变得更加难以确定你想要如何将边缘粘合在一起 - 你的边缘是现在表面嵌入了三维世界。

修改

假设您有一张二维地图,并希望像小行星一样环绕。

如果地图为1000x1000单位,则x=0为地图的左边框,x=999为右边框,您向右看并查看20单位提前。然后在x=995,您要查看1015,但这不在地图的右侧,因此1015应该变为15

如果您位于x=5并向左看20个单元,那么您会看到x=-15您真正想要的985

要查看地图边框时,要获取这些数字(始终在0到999之间),您需要使用modulo operator

new_x = x % 1000; // in many programming languages

x为负时,每种编程语言都会以不同的方式处理x % 1000的结果。它甚至可以实现定义。即它不会总是积极的(在0999之间),所以使用它会更安全:

new_x = (x + 1000) % 1000; // result 0 to 999, when x >= -1000

因此,每次移动或更改视图时,都需要重新计算视图中位置和坐标的坐标。您应用此操作来获取地图上xy坐标的坐标。

答案 2 :(得分:0)

我是Cocos2d的新手,但我想我可以尝试帮助你解决几何计算问题,因为正如你所说,这不是一个框架问题。

我首先要设置你在视觉中心使用的每一层的锚点。

然后让我们同意这样的假设:触及边缘的第一部分将始终是一个角落。

如果您只是想检查它是否在圆圈内,只需检查所有四条边是否在圆圈内。

如果您想知道哪个边缘接触圆的圆周,只需检查距离点x = 0 y = 0最远的边,因为锚将位于中心。

如果你有理由不把锚放在中间,你可以使用相同的逻辑,只要你在每件物品上都包含每个物体宽度的一半。