KWEngine, Teil 19: 2D-Darstellung

Obwohl die KWEngine primär für 3D-Szenen konzipiert wurde, ist es über Umwege möglich, eine klassische 2D-Darstellung zu erzwingen. Der größte Unterschied liegt hier in der Kameraprojektion:

  • In einer 3D-Szene erscheinen Objekte in der Ferne kleiner (perspektivische Projektion), aber
  • in einer 2D-Szene werden alle Objekte gleicher Größe auch immer gleich groß dargestellt, da die Entfernung der Objekte zueinander keine Rolle spielt (orthografische Projektion).

Die Standardprojektion in der KWEngine ist perspektivisch. Also muss die Projektion zunächst auf „orthografisch“ umgestellt werden.
Außerdem erhält die FOV-Eigenschaft in der orthografischen Projektion eine neue Bedeutung. Ihr Wert muss auf die aktuelle Höhe des Fensters gesetzt werden. Dies bewirkt dass die Breite und Höhe der Welt in die tatsächliche Pixelanzahl des Fensters aufgeteilt werden.

Alle Anpassungen sollten in der Prepare()-Methode Ihrer Welt-Klasse erfolgen:

public override void Prepare()
{
    // Ortografische Projektion setzen:
    KWEngine.Projection = ProjectionType.Orthographic; 

    // Pixelgenaue Projektion:
    FOV = CurrentWindow.Height;   
                     
    // Objekte, die weiter als 10000 Pixel vom Mittelpunkt der Welt entfernt
    // sind, werden automatisch von der Engine entfernt:
    WorldDistance = 10000;     

    // Beispielhafte Konfiguration der Spielfigur:
    Player p = new Player();
    p.SetModel("KWQuad");         // Flache Quadrate statt 3D-Würfel verwenden
    p.IsCollisionObject = true;
    p.SetPosition(0, 128, 0);
    p.SetScale(48, 64, 1);        // Skalierungswerte jetzt in Pixeln
    p.SetTexture(@".\textures\player.png");
    AddGameObject(p);                        

    // Wichtig:
    // Da Quadrate sehr flach sind, muss ihre Hitbox-Tiefe stark vergrößert
    // werden, damit die 3D-Kollisionsberechnungen weiterhin funktionieren.
    p.SetHitboxScale(1, 1, 1000); 
}

Ein sehr wichtiger Faktor ist die Anpassung der Hitbox-Skalierung. Hier ist es wichtig, dass die z-Ebene stark vergrößert wird (z.B. wie im Beispielcode mit Faktor 1000). Andernfalls kann es passieren, dass Objekte aufgrund von Rundungsungenauigkeiten bei der Kollisionsberechnung nicht als kollidierend erkannt werden.

Nicht vergessen: Anpassung der Toleranz für die Kollisionserkennung

Damit nicht jedes Objekt für alle anderen Objekte prüfen muss, ob es mit einem der Objekte kollidiert, wendet die KWEngine vorab für jeden Frame eine Art Filter an. Dieser Filter bestimmt für jedes Objekt eine Liste von den Objekten, mit denen es potenziell kollidieren könnte (z.B. weil es nah genug an ihnen dran ist). Für die 2D-Darstellung werden alle Objektgrößen jedoch jetzt in Pixeln gerechnet, so dass der Filter nicht mehr korrekt eingestellt ist und korrigiert werden muss:
KWEngine.SweepAndPruneToleranceWidth = 64;

Diese Angabe bedeutet, dass der Filter den Bereich um ein Objekt um bis zu 64 Pixel zusätzlich erweitert, damit potenzielle Kollisionskandidaten besser gefunden werden. Der Wert sollte der schnellsten Geschwindigkeit eines Objekts entsprechen. Wenn ein Objekt z.B. 128 Pixel pro Frame zurücklegen kann, dann sollte die Toleranzbreite auf 128 gesetzt werden.
(Der Standardwert für 3D ist 1)


Animierte 2D-Objekte mit Spritesheets

Sollten Sie 2D-Objekte mit verschiedenen Animationsbildern (Spritesheets) verwenden wollen, können Sie mit Hilfe der GameObject-Methoden SetTextureRepeat() und SetTextureOffset() bestimmen, welcher Teil des Spritesheet angezeigt werden soll:

Beispiel für ein Spritesheet mit 3 Zeilen und 10 Spalten
public class Player : GameObject
{
    public override void Act(KeyboardState ks, MouseState ms)
    {
        // Da das Beispiel-Spritesheet 10 Spalten hat, muss die
        // Texturwiederholung in x-Richtung auf 10% gestellt werden.
        // Bei 3 Zeilen muss die y-Richtung dementsprechend auf 1/3
        // der Texturhöhe angezeigt werden.
        // Ohne zusätzlichen Offset (Abstand) würden von der Textur 
        // jetzt 10% von links und 33% von oben angezeigt werden
        // (die Animationsstufe ganz links oben):
        SetTextureRepeat(0.1f, 0.33333333f);

        // Wenn aber stattdessen die Animationsstufe ganz links in 
        // der zweiten Zeile angezeigt werden soll, muss ein ein 
        // vertikaler Offset um 33% erfolgen:
        SetTextureOffset(0f, 0.333333f);
    }
}

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert