在2D空间游戏中伪造等距图形


15

首先,我确切地知道我的绘图问题是什么,并且对于如何解决该问题我有各种想法。我在这里要弄清楚如何调整绘制的帧,以便保持等距的“幻觉”。

我正在编写在太空中进行的2D鸟瞰游戏。我试图在Up是北方的世界中使用等轴测图形,而游戏世界不会像传统的等轴测游戏那样旋转(请记住,游戏是在太空中进行的,没有地形)。这是我尝试使用的一个示例精灵:http : //cell.stat-life.com/images/stories/AsteroidOutpost/Spaceship64.png围绕其自身的垂直轴旋转了64次,视角为35度(又名iso)。图像已生成,因此可以更改。

为了清楚起见,我已指定北(上)为0度,东(右)为90度。

我的问题是,由于所使用的3D平面存在差异,我的精灵并不总是看起来像面对游戏一样。不知道我是否正确使用了术语,但是我的飞船是在一个平面上旋转的,而查看平面期望事物在其自身的平面上旋转。这是问题的描述:

http://cell.stat-life.com/images/stories/AsteroidOutpost/ProjectionIssue.png 左边是侧视图,右边是自顶向下的视图。在顶部,我可以看到太空飞船/精灵表的世界。在底部,我具有将精灵绘制到屏幕上时的外观

右上角是我的飞船如何旋转的简化版本(每帧之间的角度间隔均匀)。右下角是在屏幕上绘制特定角度时,精灵看起来像面对的角度。该问题在45度左右最为明显。这是一张覆盖有“屏幕平面”线的图像,该线指向该船应该面对的方向:http : //cell.stat-life.com/images/stories/AsteroidOutpost/Spaceship64RedLine.png红线应始终指向与船完全相同的方向,但是如您所见,投影问题正在引起问题。我希望我已经很好地描述了这个问题。

编辑: 红线在屏幕平面上旋转,而太空飞船在“船平面”上旋转,因此绘制时船角和屏幕角度之间存在较大差异。 结束编辑

当这艘船向应该向前方射击的一侧偏离目标的位置发射激光束时,看起来很奇怪。

所以...我想出的解决方案是:

  1. 停止尝试伪造等轴测图,变大或回家。已经旋转了我的世界。(PS:这可以解决我的问题,对吗?)
  2. 更改我的Sprite表(以某种方式),使其具有表示模型将被查看的“屏幕角度”的框架。因此,当我要求提供45度的图像时,它实际上看起来像是在屏幕上面对45度。
  3. 更改我的Sprite渲染系统以从Sprite工作表中抓取一个不同的帧(以某种方式),因为知道抓取“正常”帧看起来会很有趣。因此,与其抓取45度的框架,不如抓取33度的框架(只是猜测),使它对用户而言看起来是正确的。
  4. 只需使用3D!真是太容易了

例如:您会推荐哪种解决方案?我倾向于2,即使我知道这是错误的。请记住,我有权使用Sprite生成工具。方法3是我的第二选择。这两种方法都只需要我对角度应用一些数学运算即可得到所需的结果。顺便说一句,我在其中添加了#4作为玩笑,我不想转向3D。

对于两个:使用方法2或方法3,如何调整输入或输出角度?我对3D投影和3D矩阵(更不用说2D矩阵)以及任何其他数学方法可以达到我想要的结果都不太满意。

在这里大声思考:如果我将一个单位矢量面向我要看的船的方向(在屏幕平面上),然后将其投影到船平面上,然后找出那条投影线与飞机平面之间的夹角北方是,我应该具有要显示的船舶图形的角度。对?(#3的解决方案?)伙计...我无法解决。

编辑:

我知道这个问题是很难用静态图像可视化,所以我遵守我的雪碧库Visual测试仪显示的问题:http://cell.stat-life.com/downloads/SpriteLibVisualTest.zip它需要XNA 4.0此应用程序只需旋转精灵,然后从其中心向外以游戏认为船应面对的角度画一条线。

编辑9月8日

继续我的“大声思考”段落:我认为我可以采用朝北的单位矢量(0x,1y,0z),而不是使用投影(因为它看起来很难),而是使用矩阵将其旋转到角度精灵实际上是面向的,然后围绕X轴再次从“查看平面”向外旋转到“精灵平面”,然后……变平?仅使用X和Y(忽略Z),向量(基本上是将其投影)回到视平面上。然后,使用新的扁平化矢量,我可以确定其角度并将其用于...某物。我待会再考虑。

编辑9月8日(2)

我尝试从上面遵循我的想法,并取得了一些成功,是的!所以...为了使一条红线看起来像是从我的飞船中出来(仅出于测试目的),我做了以下工作:

Vector3 vect = new Vector3(0, 1, 0);
vect = Vector3.Transform(vect, Matrix.CreateRotationZ(rotation));
vect = Vector3.Transform(vect, Matrix.CreateRotationY((float)((Math.PI / 2) - MathHelper.ToRadians(AngleFromHorizon))));
Vector2 flattenedVect = new Vector2(vect.X, vect.Y);

float adjustedRotation = (float)(getAngle(flattenedVect.X, flattenedVect.Y));

rotation屏幕角度在哪里,adjustedRotation现在屏幕角度在子平面上看起来是什么。我不知道为什么需要旋转Y而不是X,但这可能与我不知道的3D有关。

因此,现在我有了其他信息,但是如何使用它来选择更合适的框架呢?也许不是从视平面旋转到子平面,然后向后投影,我应该尝试以其他方式进行。这是我的精灵,带有调整后的红线,但我真正想做的是调整模型,而不是调整线:http : //cell.stat-life.com/images/stories/AsteroidOutpost/Spaceship64RedLineCorrected.png

编辑9月9日

哈RAY!它是固定的!我将描述如何解决该问题:

我听从电子商务的建议,并被世界坐标系“压扁”(或拉伸...?)。这基本上是解决方案1,尽管我的印象是我必须相对于屏幕坐标系旋转世界坐标系。不对!Up仍然是+ y,Right仍然是+ x。我修改了WorldToScreen和ScreenToWorld方法以在世界坐标和屏幕坐标之间正确转换。这些方法可能不是最佳方法,但是这是我的代码库中仅有的两个必须更改的方法。

public Vector2 ScreenToWorld(float x, float y)
{
    float deltaX = x - (size.Width / 2f);
    float deltaY = y - (size.Height / 2f);

    deltaX = deltaX * scaleFactor / (float)Math.Sqrt(3);
    deltaY = deltaY * scaleFactor;

    return new Vector2(focusWorldPoint.X + deltaX, focusWorldPoint.Y + deltaY);
}

public Vector2 WorldToScreen(float x, float y)
{
    float deltaX = x - focusWorldPoint.X;
    float deltaY = y - focusWorldPoint.Y;

    deltaX = deltaX / scaleFactor * (float)Math.Sqrt(3);
    deltaY = deltaY / scaleFactor;

    return new Vector2(size.Width / 2f + deltaX, size.Height / 2f + deltaY);
}

就是这样!更改这两种方法会影响其他所有方面:我在看的东西,绘制对象的位置,单击的位置以及所有其他内容。我的太空船现在直接注视着它所要射击的目标,一切都落在了原地。我将尝试正交投影,看看它是否使一切看起来都更加“真实”。


恭喜你 一旦您有可玩的​​东西,别忘了给我戳,我想看看它的去向。
aaaaaaaaaaaaaa

@eBusiness如所承诺的那样:cell.stat-life.com/images/stories/AsteroidOutpost/…cell.stat-life.com/images/stories/AsteroidOutpost/AOOhNoes.png 注意船看起来像在看着那座塔吗?:D谢谢!
约翰·麦克唐纳

@eBusiness,视频youtube.com/watch?v=Q8pR9KDBsCo自您询问以来,还有一个下载链接。
约翰·麦克唐纳

Answers:


4

选择等轴透视图后,您需要校正X轴和Y轴之间的比例。如果给定的距离在屏幕Y轴上投影为1,则相同的距离将在屏幕X轴上投影为sqrt(3)。因此,如果您将内容平放在屏幕上,则会执行以下操作:

draw(object.image, object.x*sqrt(3), object.y)

非回答笔记:

  • 你为什么要弄乱精灵表和东西呢?如果需要,可以让3D渲染器进行等轴测。
  • 由于您使用的是精灵表,为什么不对它们进行抗锯齿处理?
  • 在空间上是等距的,我想我从未见过有这样的游戏用途,由于缺乏清晰的等距视觉参考,我不确定该游戏的效果如何。

1
我认为...这可以解决所有问题。这很容易解决,我可以不做任何处理。我将尽快尝试此方法,并告诉您它的运行情况。回答您的注意事项:1)我正在使用2D,因为这是我所熟悉的,并且我正在根据3D模型生成图纸。2)边缘应该很锋利,但是在坚硬的边缘内,我可以使用alpha通道进行抗锯齿。3)我不打算模拟三维(很多),我主要是希望二维图形不是自上而下的,而是让您看到事物的各个方面。
约翰·麦克唐纳

5

如何生成旋转的精灵?这些是旋转3D模型的屏幕截图吗?面对角度可能由于3D建模工具的摄影机视角而偏离。等轴测透视图不能准确表示3D空间。远离“相机”的东西不会变小。

如果您只想快速解决。解决方案2可能很难正确解决。解决方案3似乎很容易,只需将不匹配角度的框架替换为更适合该角度的框架即可。

有时激光仍会关闭。由于您没有进行平滑旋转,而是在特定度数范围内显示了不同的帧。

编辑:

您的问题是生成的屏幕截图不是等轴透视图,而是普通的3D相机视图。

在此处输入图片说明

等轴测图模拟3D空间,但不是精确的表示形式。随着距相机距离的增加,事物变得越来越小。对于等轴测透视图,则不会这样做,因为这会在子画面中造成难看的缩放伪影。

您的太空飞船屏幕截图是使用3D摄像机透视图制作的。这就是为什么激光发射关闭的原因。比较“等距”和“透视”中的红线。

您的子画面生成器应使用Matrix.CreateOrthographic()而不是Matrix.CreatePerspective()作为投影矩阵。


精灵是使用我正在开发的3D到2D工具生成的,因此问题很可能出在该工具上。该工具仅加载3D模型,然后实现Spaceship64.png(如上),将模型旋转(360/64)= 5.625度,将其保存为框架,然后再次旋转相同的量,直到所有64帧。用于渲染模型的代码在这里:code.google.com/p/sprite-maker/source/browse/trunk/XNAWindow / ... 在另一个类中进行旋转。我还以为解决方案2和3是彼此相反的,不是吗?
约翰·麦当劳

编辑了我的答案。往上看。
斯蒂芬

我想我可能需要同时做这两个事情:让我的精灵生成器使用正交投影并像@eBusiness所说的那样改变我的世界坐标系。昨晚我尝试了正交投影,它的确改变了我的船的外观,但仅靠它并不能解决我遇到的角度问题。
约翰·麦克唐纳

刚刚看到您的修改。校正后的精灵看起来像船的中心偏离红线的中心。也许足以使飞船比红线的起点高一到两个像素。船舶离开您的世界原点时,可见误差是否会改变?然后缩放X轴可能会解决此问题。
斯蒂芬

1

我认为您在这里只是等距外观的样子。您是对的,从视觉上看,0deg和10deg之间的差异似乎比90deg和100deg之间的差异更大。。。但这是因为等轴测图本质上会压缩一个轴。如果您不想要那种外观,则不需要等轴测图。

就是说,我认为您遇到的视觉问题归因于没有视觉参考点。您的大脑假设您正在自上而下地看-嘿,这是空间,为什么不呢-并将其解释为标准的自上而下的视图。为了进行测试,请尝试添加一些浮动全息参考点。例如,一个45度角网格或围绕您的航天器的一组范围圆。确保它们正确变形,就像它们在渲染太空船的同一等距平面上一样。我敢打赌,您的大脑会弄清楚视角,然后突然看起来正确。

现在,弄清楚如何将其传达给用户。。。这完全是另一回事。


我是否还需要旋转世界轴来使用这种方法完成幻觉(问题中的方法1)?
约翰·麦当劳

据我所知,该船已经被正确渲染-侧视图以等轴测显示为“正确”的角度显示了它。我想我不确定“旋转世界轴”的意思。
ZorbaTHut 2011年

所谓“旋转世界轴”,是指相对于相机旋转世界45度,以使“北方”以对角线朝向屏幕的右上角或左上角,而不是“北方”直上移到屏幕顶部。
约翰·麦当劳


这可能会有所帮助,但无论如何在太空中都不会产生太大的改变。除非您在世界上覆盖了网格,否则就没关系了。
ZorbaTHut 2011年
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.