首先,我确切地知道我的绘图问题是什么,并且对于如何解决该问题我有各种想法。我在这里要弄清楚如何调整绘制的帧,以便保持等距的“幻觉”。
我正在编写在太空中进行的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红线应始终指向与船完全相同的方向,但是如您所见,投影问题正在引起问题。我希望我已经很好地描述了这个问题。
编辑: 红线在屏幕平面上旋转,而太空飞船在“船平面”上旋转,因此绘制时船角和屏幕角度之间存在较大差异。 结束编辑
当这艘船向应该向前方射击的一侧偏离目标的位置发射激光束时,看起来很奇怪。
所以...我想出的解决方案是:
- 停止尝试伪造等轴测图,变大或回家。已经旋转了我的世界。(PS:这可以解决我的问题,对吗?)
- 更改我的Sprite表(以某种方式),使其具有表示模型将被查看的“屏幕角度”的框架。因此,当我要求提供45度的图像时,它实际上看起来像是在屏幕上面对45度。
- 更改我的Sprite渲染系统以从Sprite工作表中抓取一个不同的帧(以某种方式),因为知道抓取“正常”帧看起来会很有趣。因此,与其抓取45度的框架,不如抓取33度的框架(只是猜测),使它对用户而言看起来是正确的。
- 只需使用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);
}
就是这样!更改这两种方法会影响其他所有方面:我在看的东西,绘制对象的位置,单击的位置以及所有其他内容。我的太空船现在直接注视着它所要射击的目标,一切都落在了原地。我将尝试正交投影,看看它是否使一切看起来都更加“真实”。