KWEngine, Teil 14: Rotationen relativ zu Objekten

KWEngine bietet verschiedene Arten der Rotation für alle GameObject-Instanzen. Die einfachste Art der Rotation ist die, die die Ausrichtung eines Objekts selbst beschreibt. Diese Rotation wurde bereits in KWEngine, Teil 3: Objekte steuern behandelt. In den folgenden Abschnitten werden zwei weitere Arten der Rotation anhand von Beispielen beschrieben.

1) Rotation um ein anderes Objekt

Um ein Objekt A um ein anderes Objekt B rotieren zu lassen, benötigt man…

  • …die Position von Objekt B,
  • den Abstand, mit dem Objekt A um Objekt B kreist und
  • die Achse, um die rotiert werden soll.
private float _degrees = 0f;

public override void Act(KeyboardState ks, MouseState ms)
{
    // Hier wird testweise um den Ursprung des Koordinatensystems 
    // rotiert, indem der Pivot-Point auf (0|0|0) festgelegt wird:
    Vector3 positionOfObjectB = new Vector3(0f, 0f, 0f);

    // Berechne neue Position des Objekts A, wenn es um diese 
    // Position rotiert:
    Vector3 newPosOfA = 
        HelperVector.CalculateRotationAroundPointOnAxis(
            positionOfObjectB,    // Punkt, um den rotiert wird
            5f,                   // Abstand zum Punkt (Radius)
            _degrees,             // Grad der Rotation (0 bis 359°)
            Plane.Y);             // Achse, um die rotiert wird (z.B. Y)
    
    SetPosition(newPosOfA);       // Setze neue Position für Objekt A

    _degrees++;                   // Erhöhe Rotationsgrad für 
                                  // den nächsten Frame um 1
}

2) Platzierung von Objekten in Abhängigkeit der eigenen Blickrichtung

In KWEngine kann jede GameObject-Instanz erfragen, in welche Richtung es gerade blickt. Diese Richtung wird nicht als Gradzahl, sondern als Vector3 angegeben. Die Engine bezeichnet diesen Vektor als den „Look-At-Vector“ (zu sehen als Pfeil in der unteren Abbildung).

Der Vektor hat immer die Länge 1 (Einheitsvektor) und beschreibt die Bewegungen entlang der drei Achsen, die das Objekt gehen müsste, um genau eine Einheit in Blickrichtung nach vorne zu gehen.

Um also ein neues Objekt (z.B. einen Schuss) direkt eine Einheit vor sich zu erstellen, müsste eine GameObject-Instanz nur folgenden Code in der Act()-Methode ausführen:

public override void Act(KeyboardState ks, MouseState ms)
{
    Vector3 lookAtVector = GetLookAtVector();
    
    Shot s = new Shot();
    s.SetModel("KWSphere");
    s.SetScale(0.5f);

    // Hier wird auf die aktuelle Position der Spielfigur (this.Position)
    // ihr aktueller Look-At-Vektor addiert, so dass die Position für
    // das neue Schussobjekt "s" eine Längeneinheit vor der Spielfigur
    // erscheint.
    // Der Faktor 1.0f kann dabei bestimmen, ob diese Längeneinheit 
    // verkürzt oder verlängert wird (Standard: 1.0f).
    s.SetPosition(this.Position + lookAtVector * 1.0f); 

    s.SetRotation(this.Rotation);
    s.IsCollisionObject = true;
    
    CurrentWorld.AddGameObject(s);
}

Wenn der Schuss jetzt aber nicht direkt vor der Spielfigur erscheinen soll, sondern stattdessen von ihrer rechten Seite aus starten soll, muss der Look-At-Vektor zunächst rotiert werden, bevor er weiterverwendet wird:

public override void Act(KeyboardState ks, MouseState ms)
{
    Vector3 lookAtVector = GetLookAtVector();
    
    // Die Klasse 'HelperRotation' bietet für die Rotation eines Vektors
    // die passende Methode ('RotateVector') an:
    lookAtVector = HelperRotation.RotateVector(
        lookAtVector,    // Vektor, der rotiert werden soll
        -90,             // Grad der Rotation (negativ = im Uhrzeigersinn)
        Plane.Y);        // Achse, um die rotiert werden soll
    
    // Der Rest des Codes bleibt identisch:
    Shot s = new Shot();
    s.SetModel("KWSphere");
    s.SetScale(0.5f);
    s.SetPosition(this.Position + lookAtVector * 1.0f); 
    s.SetRotation(this.Rotation);
    s.IsCollisionObject = true;
    
    CurrentWorld.AddGameObject(s);
}

Der Effekt dieser Rotation ist hier zu sehen:

Schreibe einen Kommentar

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