Zuallererst weiß ich genau, was mein Zeichenproblem ist, und ich habe verschiedene Ideen, wie ich es lösen kann. Ich bin hier, um herauszufinden, wie man den Rahmen so einstellt, dass die isometrische "Illusion" erhalten bleibt.
Ich schreibe ein 2D-Spiel aus der Vogelperspektive, das im Weltraum stattfindet. Ich versuche, isometrische Grafiken in einer Welt zu verwenden, in der Up Nord ist, kein Drehen der Spielwelt wie in traditionellen isometrischen Spielen (denken Sie daran, das Spiel findet im Weltraum statt, kein Gelände). Hier ist ein Beispiel-Sprite, das ich verwenden möchte : http://cell.stat-life.com/images/stories/AsteroidOutpost/Spaceship64.png 64-mal um die eigene vertikale Achse gedreht, mit einem Betrachtungswinkel von 35 Grad (aka, iso). Das Bild wurde erzeugt, so dass dies kann geändert werden.
Aus Gründen der Klarheit habe ich festgelegt, dass Nord (Oben) 0 Grad und Ost (Rechts) 90 Grad beträgt.
Mein Problem ist, dass mein Sprite nicht immer so aussieht, als würde es dort ausgerichtet sein, wo das Spiel denkt, dass es auf einen Unterschied in den verwendeten 3D-Ebenen zurückzuführen ist. Ich bin nicht sicher, ob ich die Terminologie richtig verwende, aber mein Raumschiff wurde in einer Ebene gedreht, und die Ansichtsebene erwartet, dass die Dinge in ihrer eigenen Ebene gedreht werden. Hier ist eine Darstellung des Problems:
http://cell.stat-life.com/images/stories/AsteroidOutpost/ProjectionIssue.png Links habe ich Seitenansichten, rechts habe ich Ansichten von oben nach unten. Oben habe ich die Raumschiff- / Sprite-Ansicht der Welt. Unten sehe ich, wie das Sprite aussieht, wenn es auf dem Bildschirm angezeigt wird.
Oben rechts ist eine vereinfachte Version davon zu sehen, wie mein Raumschiff gedreht wurde (gleichmäßige Gradtrennungen zwischen den einzelnen Frames). In der rechten unteren Ecke ist der Winkel, die Sprite aussehen wie es mit Blick auf, wenn ein bestimmte Winkel auf dem Bildschirm gezeichnet wird. Das Problem tritt am deutlichsten bei etwa 45 Grad auf. Hier ist ein Bild, das mit einer "Bildschirmebenen" -Linie überlagert ist, die in die Richtung zeigt, in die das Schiff ausgerichtet sein soll: http://cell.stat-life.com/images/stories/AsteroidOutpost/Spaceship64RedLine.png Die rote Linie sollte immer genau in die gleiche Richtung zeigen wie das Schiff, aber wie Sie sehen können, verursacht das Projektionsproblem ein Problem. Ich hoffe, ich beschreibe das Problem gut genug.
BEARBEITEN: Die rote Linie wird in der Bildschirmebene gedreht, während das Raumschiff in der "Schiffsebene" gedreht wird, daher der große Unterschied zwischen dem Schiffswinkel und dem Bildschirmwinkel, wenn es gezeichnet wird. ENDE BEARBEITEN
Es sieht ziemlich seltsam aus, wenn dieses Schiff einen Laserstrahl auf ein seitlich entferntes Ziel schießt, wenn es geradeaus schießen soll.
Also ... die Lösungen, die ich gefunden habe, sind:
- Hören Sie auf, eine isometrische Ansicht zu fälschen, gehen Sie groß oder gehen Sie nach Hause. Drehe meine Welt schon. (PS: das wird mein Problem beheben, oder?)
- Ändere mein Sprite Sheet (irgendwie) so, dass es Frames enthält, die den "Bildschirmwinkel" darstellen, unter dem das Modell angezeigt wird. Wenn ich also nach einem 45-Grad-Bild frage, sieht es tatsächlich so aus, als würde es 45 Grad auf dem Bildschirm anzeigen.
- Ändern Sie mein Sprite-Rendering-System, um (irgendwie) einen anderen Frame aus dem Sprite-Sheet zu ziehen, da Sie wissen, dass das Ziehen des "normalen" Frames lustig aussehen wird. Anstatt also den 45-Grad-Rahmen zu greifen, greift er den ... 33-Grad-Rahmen (nur raten), damit er für den Benutzer korrekt aussieht .
- Benutze einfach 3D! Es ist so viel einfacher, Mann
Zum einen: Welche Lösung würden Sie empfehlen? Ich neige zu 2, obwohl ich weiß, dass es falsch ist. Denken Sie daran, dass ich vollen Zugriff auf das Sprite-Generierungs-Tool habe. Methode 3 wäre meine zweite Wahl. Bei beiden Methoden muss ich lediglich einige Berechnungen auf die Winkel anwenden, um das gewünschte Ergebnis zu erzielen. Übrigens habe ich als Scherz # 4 hinzugefügt, ich möchte nicht zu 3D wechseln.
Zu zweit: Wie würde ich mit den Methoden 2 oder 3 den Ein- oder Ausgabewinkel anpassen? Ich kann mit 3D-Projektionen und 3D-Matrizen (geschweige denn 2D-Matrizen) nicht allzu gut umgehen, und mit welcher anderen Mathematik auch immer kann ich das gewünschte Ergebnis erzielen.
Hier laut denken: Wenn ich einen Einheitsvektor nehme, der in die Richtung zeigt, in die das Schiff schauen soll (auf der Bildschirmebene), dann projiziere diesen auf die Schiffsebene und finde dann heraus, wie der Winkel zwischen dieser projizierten Linie und der Ebene ist Norden ist, sollte ich den Winkel der Schiffsgrafik haben, die ich anzeigen möchte. Richtig? (Lösung für # 3?) Mann ... das kann ich nicht herausfinden.
BEARBEITEN:
Ich weiß, dass das Problem mit statischen Bildern nur schwer zu visualisieren ist. Daher habe ich meinen Sprite Library Visual Tester befolgt, um das Problem anzuzeigen: http://cell.stat-life.com/downloads/SpriteLibVisualTest.zip Für diese Anwendung ist XNA 4.0 erforderlich Drehe einfach das Sprite und ziehe eine Linie von seinem Mittelpunkt nach außen in dem Winkel, in dem das Spiel glaubt, dass das Schiff ausgerichtet sein sollte.
EDIT 8. September
Fortsetzung von meinem Abschnitt "Lautes Denken": Anstatt eine Projektion zu verwenden (weil es schwierig aussieht), denke ich, ich könnte einen nach Norden gerichteten Einheitsvektor (0x, 1y, 0z) verwenden, um ihn in den Winkel zu drehen Das Sprite ist tatsächlich ausgerichtet. Drehen Sie es dann erneut von der "Ansichtsebene" nach außen in die "Spriteebene" um die X-Achse. Dann ... Abflachen? Der Vektor wird (im Wesentlichen) zurück auf die Betrachtungsebene projiziert, indem nur X und Y verwendet werden (Z wird ignoriert). Mit diesem neuen abgeflachten Vektor könnte ich dann seinen Winkel bestimmen und damit ... etwas tun. Ich werde später mehr darüber nachdenken.
EDIT 8. September (2)
Ich habe versucht meine Idee von oben mit einigem Erfolg zu verfolgen, yay! Um eine rote Linie zu erhalten, die aussieht, als würde sie direkt aus meinem Raumschiff kommen (nur zu Testzwecken), habe ich Folgendes getan:
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));
Wo rotation
ist der Bildschirmwinkel und adjustedRotation
jetzt sieht dieser Bildschirmwinkel auf der Sprite-Ebene aus. Ich weiß nicht, warum ich Y anstelle von X drehen musste, aber es hat wahrscheinlich etwas mit 3D zu tun, von dem ich nichts weiß.
Nun habe ich also eine zusätzliche Information, aber wie verwende ich diese, um einen passenderen Rahmen auszuwählen? Vielleicht sollte ich versuchen, es andersherum zu machen, anstatt mich von der Ansichtsebene in die Sprite-Ebene zu drehen und dann nach hinten zu projizieren. Hier ist mein Sprite mit einer angepassten roten Linie, aber ich möchte wirklich das Modell und nicht die Linie anpassen: http://cell.stat-life.com/images/stories/AsteroidOutpost/Spaceship64RedLineCorrected.png
EDIT 9. September
HORAY! Es ist repariert! Ich werde beschreiben, was ich getan habe, um es zu beheben:
Ich folgte dem Rat von eBusiness und "quetschte" mich nach dem Weltkoordinatensystem (oder dehnte mich aus ...?). Dies ist im Wesentlichen Lösung Nr. 1, obwohl ich den Eindruck hatte, dass ich mein Weltkoordinatensystem in Bezug auf das Bildschirmkoordinatensystem drehen müsste. Nicht wahr! Oben ist immer noch + y und rechts ist immer noch + x. Ich habe meine WorldToScreen- und ScreenToWorld-Methoden so geändert, dass sie korrekt zwischen den Welt- und Bildschirmkoordinaten konvertieren. Diese Methoden sind möglicherweise nicht optimal, aber hier sind die einzigen zwei Methoden in meiner Codebasis, die geändert werden mussten.
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);
}
Das war's! Das Ändern dieser beiden Methoden wirkte sich auf alles andere aus: was ich sah, wo die Objekte gezeichnet wurden, wo ich klickte, alles. Mein Raumschiff schaut jetzt direkt auf das Ziel, auf das es schießt, und alles passt zusammen. Ich werde mit der orthografischen Projektion experimentieren, um zu sehen, ob dadurch alles „realer“ erscheint.