就像John所说的那样,最简单的方法是构建一个环面世界。想象一下,你的飞船是甜甜圈表面上的一个点,它只能在表面上移动。假设你位于两个圆(图片中的红色和紫色)相交的点上:
.
如果你跟着这些圆圈走,最终会回到起点。此外,请注意,无论你在表面上如何移动,都不可能到达“边缘”。环面没有这样的东西,这就是为什么将其用作无限2D世界很有用的原因之一。另一个原因是方程非常简单。通过两个角度指定你在环面上的位置:从紫色圆圈上的“原点”出发找到红色圆圈的旋转角度和在红色圆圈上找到感兴趣点的旋转角度。这两个角度都是360度。我们称这两个角度为
theta
和
phi
。它们是你的飞船在世界中的坐标,并且当你改变速度等时要更改它们。基本上,你将它们用作你的
x
和
y
,但必须确保在更改它们时始终使用模数(你的世界只有每个方向360度,然后会绕回)。
假设您的船坐标为
(theta_ship,phi_ship)
,并且朝向为
gamma_ship
。您想要绘制一个正方形窗口,以船为中心,长度/宽度等于整个世界的某个百分比 n(例如,您只想一次看到四分之一的世界,则将
n=sqrt(1/4)=1/2
,并将窗口的长度和宽度设置为
n*2*pi=pi
)。为此,您需要一个函数,该函数接受在屏幕坐标系中表示的点(
x
和
y
),并输出在世界坐标系中的点(
theta
和
phi
)。例如,如果您问它世界的哪个部分对应于
(0,0)
,则应返回船的坐标
(theta_ship,phi_ship)
。如果船的方向为零(
x
和
y
与
theta
和
phi
对齐),则某个坐标
(x_0,y_0)
将对应于
(theta_ship+k*x_0, phi_ship+k*y_0)
,其中
k
是相关于在屏幕上能够看到多少世界以及
x
和
y
的边界的缩放因子。旋转
gamma_ship
引入了一些三角函数,详见下面的函数。有关量的确切定义,请参见图片。
!
蓝色是屏幕坐标系,红色是世界坐标系和配置变量(描述船在世界中的位置的东西)。在世界坐标系中表示的对象为绿色。
坐标转换函数可能看起来像这样:
# takes a screen coordinate and returns a world coordinate
function screen2world(x,y)
# this is the angle between the (x,y) vector and the center of the screen
alpha = atan2(x,y);
radius = sqrt(x^2 + y^2); # and the distance to the center of the screen
# this takes into account the rotation of the ship with respect to the torus coords
beta = alpha - pi/2 + gamma_ship;
# find the coordinates
theta = theta_ship + n*radius*cos(beta)/(2*pi);
phi = phi_ship + n*radius*sin(beta)/(2*pi));
# return the answer, making sure it is between 0 and 2pi
return (theta
我想这就是全部了。数学只是一些相对简单的三角函数,你应该画一个小图来证明它是正确的。或者你可以使用旋转矩阵及其更大的兄弟刚体变换(特殊欧几里得群SE(2))以较自动化的方式得到相同的答案。对于后者,我建议阅读Murray,Li,Sastry的前几章,它可以在网上免费阅读。
如果您想要做相反的事情(从世界坐标转换为屏幕坐标),则需要做基本相同的事情,但反过来:
beta = atan2(phi-phi_ship, theta-theta_ship);
radius = 2*pi*(theta-theta_ship)/(n*cos(beta));
alpha = beta + pi/2 - gamma_ship;
x = radius*cos(alpha);
y = radius*sin(alpha);