如何处理2D屏幕坐标和笛卡尔坐标之间的差异


23
  • 大多数2D屏幕/位图坐标系的Y轴正下方(原点位于左上角)。
  • 这与大多数人以正的Y轴指向上方(原点为中心)的几何方式思考相反。

大多数游戏如何管理两个不同的2D坐标系?坐标有两种主要类型(屏幕与笛卡尔坐标),但可能有许多不同的坐标空间:精灵空间,世界空间,视图空间,屏幕空间等。

背景:

我最初使游戏中的世界坐标与2D屏幕坐标约定相匹配。这使得使用图形绘制例程非常自然,但是在使用三角函数(如atan2())时会出现一些细微问题。馈入atan2()2D屏幕坐标的结果非常令人困惑,因为atan2()假定正y轴指向上。

因此,我更改了世界坐标,以遵循经典的笛卡尔坐标系(原点位于屏幕左下方)。使用atan2()进行推理更加简单明了,但是现在很难进行其他类型的推理:

  • 如果我单击此处的屏幕,下面是什么精灵?
  • 我在哪里点击了那个精灵?
  • 如果在错误的位置绘制了子图形,则错误地计算了什么?屏幕坐标还是世界坐标?

我意识到从屏幕坐标到直角坐标的转换只涉及将y值按-1缩放,同时可选地转换两个(x,y)值。我对游戏设计的最佳做法更感兴趣:

  • 大多数游戏是否只​​遵循屏幕坐标约定并改变了他们对atan2()之类的东西的看法?
  • 何时/如何完成坐标系转换?(使用矩阵,OOP抽象等)
  • 子画面位置是否存储为子画面的中心或拐角之一?当我绘制精灵时,精灵的高度/宽度朝“错误”方向移动似乎是一个常见问题。

尽管我的问题主要是关于2D游戏,但OpenGL似乎使用了Y轴指向上方的坐标系。OpenGL必须最终将这些3D坐标投影到2D屏幕坐标系上。也许可以在OpenGL的方法中找到一些指导...

Answers:


8

尝试了所有可能的方法,我发现它是否纯粹是2D游戏,只需使用屏幕绘制系统,它将使您的生活变得更加轻松。Sin,Cos和atan2的使用方式略有不同,但是通过简单地了解向上,向下,顺时针和逆时针的方式可以轻松地弥补这一不便。对于2D游戏,我还建议使用像素而不是米进行计算-考虑屏幕上的距离要容易得多,并且想要更改游戏整体比例的机会几乎为零。

“大多数游戏如何管理两个不同的2D坐标系?”

  • 我已经看过大多数2D游戏使用屏幕系统的来源,但是每个实体都应该知道其世界空间,让您的图形管理器将其转换为屏幕位置。此时,您将进行所需的任何矩阵转换。

“是否将子画面位置存储为子画面的中心或拐角之一?”

  • 如果您从中间开始工作,尽管您也想知道转角,但旋转会更直接向前。

“也许可以在OpenGL的方法中找到一些指导...”

  • 3D引擎是完全不同的情况。由于它们具有真实的摄像头,因此屏幕位置可能与世界位置完全不同。对于自上而下的游戏,您将仅在X和Z轴上工作,而不是在X和Y轴上工作。

1

我可能在这里简化了一些事情,但我的意愿是让任何2D / UI子系统严格按照您所说的“屏幕”坐标进行处理。您将有两个矩阵:ScreenToCartesianTransform和CartesianToScreenTransform。收到鼠标输入事件后,将在使用CartesianToScreenTransform转换鼠标坐标之前将其传递给2D / UI系统的输入管理器。从那里,UI系统将使用屏幕坐标系执行命中测试,并相应地处理(或不处理)事件。如果2D / UI未处理鼠标输入事件,则可以使用原始的未转换坐标将其传递到3D系统(如果存在)。

由于2D / UI系统只能处理“屏幕”坐标,因此在渲染引擎处理之前,需要通过ScreenToCartesianTransform转换其几何形状。


实际上,取决于您使用的是哪个工具包,鼠标输入事件可能已经在屏幕坐标中。在这种情况下,您不会为2D / UI系统进行转换,而会为3D系统(如果存在)进行转换。
Mike Strobel,2010年

0

我更喜欢在Flash中使用显示树。我将有一个根节点(游戏视图),其中包含一个世界(世界节点)的孩子和一个HUD顶部的孩子。在世界节点内部将是游戏世界中对象的节点。

然后,我简单地转换世界节点。除了平移(相机平移)和比例缩放(相机缩放)外,我还应用了另外两个转换:

  • -1 y比例以翻转坐标系。
  • 将世界单位(米)转换为屏幕单位(像素)的缩放比例

然后,我在游戏对象绘图代码中使用y-up / world坐标,在HUD绘图代码中使用y-down / screen坐标,这两种感觉都非常自然。

为了回答诸如“我要单击哪个对象”之类的问题,我使用显示节点方法在坐标系之间转换坐标(例如globalToLocalFlash中的反之)。

顺便说一句,atan当y向下时,实际上并没有什么不同,您只需要考虑所有角度都是顺时针方向而不是逆时针方向。


0

像DirectX一样,OpenGL的X和Z轴沿水平面,Y面朝上。
我从来没有关于屏幕坐标的任何问题,我认为最简单的方法就是简单地对待它:如果某些东西(例如atan2)不喜欢它,则更改输入的参数。

如果您使用相对或局部坐标(例如场景图),那么简单的函数(例如ToGlobalCoords())就很好。实际上,如果您想了解有关空间定位,场景图和localToGlobal的更多信息,那么Game Engine Architecture的免费摘录与此有关。

从左上角或(0,0)原点绘制精灵。原因是由于窗口的左上角原点。

改变窗口坐标系似乎有些愚蠢,并且使输入之类的事情(比起Trig而言,在大多数游戏中扮演更大的角色)要困难得多。这也会使您脱离规范和代码的任何用户。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.