Home » Tutorials » Grafik und Spiele » Figuren in 3D-Welten einsetzen

Figuren in 3D-Welten einsetzen

Erschaffungsphase?

Und nun müssen wir uns darum kümmern, wie eine Figur in der Welt für uns sichtbar wird. Das erledigt eine Methode mit dem Namen Render.

procedure TFigur.Render (Zeit: DWord);
var Diff: geFloat; XForm: geXForm3D;
begin
  // "Bodenkontrolle"
  CheckGravity;
  // Koordinaten und Winkel ausrichten
  geXForm3D_SetIdentity (@XForm);
  geXForm3D_RotateX (@XForm, TurnVector.x);
  geXForm3D_RotateY (@XForm, TurnVector.y);
  geXForm3D_RotateZ (@XForm, TurnVector.z);
  geXForm3D_Translate
    (@XForm, ViewVector.x, ViewVector.y, ViewVector.z);
  // Wenn Animationen nicht verfügbar, "Standbild" anzeigen
  if Motion = nil then
    geActor_ClearPose(Actor, @XForm)
  else
  begin
    // Animationszeit ermitteln
    geMotion_GetTimeExtents (Motion, @MStart, @MStop);
    Diff := Zeit - MCount; MCount := Zeit;
    MTime := MTime + (MSpeed * Diff / 2000);  // 1000 bis 5000?
    // ggf. Animation "neustarten"
    if MTime > MStop then MTime := MStart;
    // Bewegungsablauf der Figur setzen
    geActor_SetPose (Actor, Motion, MTime, @XForm);
  end;
  // Figur in zufällige Richtungen laufen lassen
  if isMoving then Walk;
end;

Was leistet die Render-Methode? Ganz am Anfang steht die Kontrolle der Schwerkraft, was die Methode CheckGravity übernimmt (die wir uns später genauer anschauen):

CheckGravity;

Diese Methode ist wichtig, damit unsere Figur immer mit den Füßen am Boden bleibt.
Dann kommt die Ausrichtung des Koordinatensystems der Figur (sie entspricht völlig der Ausrichtung der Betrachtermatrix in RunGame ? siehe Hauptunit):

geXForm3D_SetIdentity (@XForm);
geXForm3D_RotateX (@XForm, TurnVector.x);
geXForm3D_RotateY (@XForm, TurnVector.y);
geXForm3D_RotateZ (@XForm, TurnVector.z);
geXForm3D_Translate (@XForm, ViewVector.x, ViewVector.y, ViewVector.z);

Gibt es keinen Motion-Teil, dann wird ein Standbild der Figur angezeigt:

if Motion = nil then geActor_ClearPose(Actor, @XForm);

Gibt es zum Actor einen Motion-Teil, benötigen wir zunächst die Animationszeit, die wir u.a. an die Laufgeschwindigkeit anpassen:

geMotion_GetTimeExtents (Motion, @MStart, @MStop);
Diff   := Zeit - MCount;
MCount := Zeit;
MTime  := MTime + (MSpeed * Diff / 2000);

Die letzte Zahl 2000 ist ein Wert, der auf meinem etwas betagten PC gut funktioniert. Probiert auch mal andere aus ? z.B. zwischen 500 und 5000.
Ist ein Bewegungsablauf vorbei (z.B. jeweils linkes und rechtes Bein bewegen), muss die Animation neu gestartet werden:

if MTime > MStop then MTime := MStart;

Nun wird die Figur „in Pose“ gesetzt:

geActor_SetPose (Actor, Motion, MTime, @XForm);

Dazu brauchen wir eine eigene Matrix (die hier ebenfalls XForm heißen darf, denn sie kann ja nicht mit der XForm in der Hauptunit verwechselt werden).
Steht der „Laufschalter“ auf true, dann können wir die Figur anschließend endlich wandern lassen:

if isMoving then Walk;

Unbewegliche Akteure (wie z.B. Gegenstände) würden dabei einfach durch die Gegend geschoben.
Damit die Figur auch die passende Erscheinung hat, sind eine ganze Reihe von Einstellungen nötig, die wir in den folgenden Set-Methoden zusammenfassen:
procedure TFigur.SetPosition (x,y,z: geFloat);
begin
geVec3d_Set (@ViewVector, x, y, z);
end;
procedure TFigur.SetRotation (x,y,z: geFloat);begin  geVec3d_Set (@TurnVector, x, y, z);end;procedure TFigur.SetScale (x,y,z: geFloat);begin  geVec3d_Set (@ScaleVector, x, y, z);  geActor_SetScale (Actor, x, y, z);end;</delphi>
Mit SetPosition, SetRotation und SetScale werden Position, Laufrichtung und Erscheinungsgröße der Figur gesetzt. Dementsprechend müssen auch die Ausdehnungswerte ? also MinVector und MaxVector ? angepasst werden.

procedure TFigur.SetRange (x0,y0,z0, x1,y1,z1: geFloat);
begin
  geVec3d_Set (@MinVector, x0,y0,z0);
  geVec3d_Set (@MaxVector, x1,y1,z1);
end;

Damit wird ein unsichtbarer Quader um die Figur aufgebaut, dessen Werte für die Kollision maßgeblich sind.
Außerdem sollte es eine Methode geben, mit der man einstellen kann, ob die Figur z.B. stehen, gehen oder gar rennen soll:

procedure TFigur.SetMotion (Speed: geFloat; Bewegung: String;
  Modus: Boolean);
begin
  // Bewegungsablauf einstellen (Stehen/Gehen/Laufen)
  Motion := geActor_GetMotionByName (ActorDef, PChar(Bewegung));
  // Geschwindigkeit, Laufmodus setzen
  MSpeed := Speed; isMoving := Modus;
end;