Figuren in 3D-Welten einsetzen
Neue Unit, neue Klasse
Um eine Figur ins Spiel zu bringen, sind eine Menge Aktionen nötig. Deshalb ist es sinnvoll, alle Methoden in einer neuen Unit zusammenzufassen, die ich G4DFigur nennen möchte. Die Methoden, die eine solche Figur mindestens braucht, sind allesamt in der Klasse TFigur vereinbart.
(Statt von einer Figur könnte man auch von Akteur, Bot, Kreatur, Gegner oder wie auch immer sprechen. Daher steht es Euch natürlich frei die Unit bzw. Klasse beispielsweise in G4DBot bzw. TBot umzubenennen. Allerdings kann unsere Figur hier einem echten Bot noch lange nicht das Wasser reichen.)
Verschaffen wir uns einen Überblick über die Genesis-Units, die in die Hauptunit eingebunden werden müssen:
G4D_Genesis, G4D_BaseType, G4D_XForm3D, G4D_geTypes, G4D_Vec3D, G4D_Vfile, G4DDriver, G4DFigur;
Neu gegenüber dem letzten Projekt ist lediglich die Unit G4DFigur, die es aber in sich hat. Denn unsere Figur lernt damit nicht nur (scheinbar) selbständig zu laufen, sondern sie kann auch mit Kollisionen umgehen, Treppen und die Schwerkraft sind für sie kein Problem. Dazu bedarf es einer Reihe weiterer Methoden, von denen viele jedoch für Voreinstellungen zuständig sind.
Auch hier zuerst die Uses-Liste:
uses Windows, Classes, Dialogs, G4D_Genesis, G4D_BaseType, G4D_XForm3D, G4D_geTypes, G4D_Vec3D, G4D_Vfile, G4D_Motion, G4D_Actor;
Als nächstes folgt die Vereinbarung der Klasse TFigur. Dabei habe ich eine ganze Reihe Vektoren aus der Hauptunit übernommen. So trifft man von ViewVector bis MaxVector nur gute Bekannte. Lediglich mit ScaleVector gibt es einen weiteren Vektor für die Größenverhältnisse, in denen die Figur im Spiel erscheinen soll. (Es leuchtet sicher ein, dass ich mich später für Bewegung und Kollisionskontrolle der Figur ebenfalls kräftig bei den Methoden aus TForm1 bediene.)
type TFigur = class private Actor : pgeActor; // Figurtyp ActorFile : pgeVFile; // Figurdatei ActorDef : pgeActor_Def; // Definitionsdaten ViewVector : geVec3D; // aktuelle Position LookVector : geVec3D; // neue Position TurnVector : geVec3D; // Drehwinkel ScaleVector: geVec3D; // Skalierungswerte MinVector : geVec3D; // min. Kollisionsgrenze MaxVector : geVec3D; // max. Kollisionsgrenze Motion : pgeMotion; // Animationphasen MCount : geFloat; // Animationszähler MStart : geFloat; // Startzeitpunkt MTime : geFloat; // Animationsdauer MStop : geFloat; // Endzeitpunkt MSpeed : geFloat; // Laufgeschwindigkeit isMoving : Boolean; // in Bewegung? public World: pgeWorld; constructor Create (Welt: pgeWorld; DateiName: String); procedure SetPosition (x,y,z: geFloat); procedure SetRotation (x,y,z: geFloat); procedure SetScale (x,y,z: geFloat); procedure SetRange (x0,y0,z0, x1,y1,z1: geFloat); procedure SetMotion (Speed: geFloat; Bewegung: String; Modus: Boolean); function Collision: Boolean; virtual; procedure CheckGravity; virtual; procedure Walk; virtual; procedure Render (Zeit: DWord); virtual; destructor Destroy; override; end;
Nun zu den einzelnen Methoden. Zuerst geht es um die Erschaffung der Figur. Dabei beginnt die Create-Methode damit, allen Vektoren einen (vorläufigen) Startwert zuzuteilen:
constructor TFigur.Create (Welt: pgeWorld; DateiName: String); begin inherited Create; // Startaufstellung/ausrichtung "nullen" geVec3d_Set (@Motion, 0.0, 0.0, 0.0); geVec3d_Set (@ViewVector, 0.0, 0.0, 0.0); geVec3d_Set (@LookVector, 0.0, 0.0, 0.0); geVec3d_Set (@TurnVector, 0.0, 0.0, 0.0); // Normale Größe geVec3d_Set (@ScaleVector, 1.0, 1.0, 1.0); // Begrenzungen geVec3d_Set (@MinVector,-20.0,-0.0,-20.0); geVec3d_Set (@MaxVector, 20.0, 0.0, 20.0); // ACT-Datei laden ActorFile := geVFile_OpenNewSystem (nil, GE_VFILE_TYPE_DOS, PChar(DateiName), nil, GE_VFILE_OPEN_READONLY); if ActorFile = nil then ExitError ('ACT-Datei lässt sich nicht öffnen!'); // Definitionsdaten der Figur "auspacken" ActorDef := geActor_DefCreateFromFile (ActorFile); if ActorDef = nil then ExitError ('Figurdaten lassen sich nicht auslesen!'); // Die Figur "zusammenbauen" Actor := geActor_Create (ActorDef); if Actor = nil then ExitError ('Figur lässt sich nicht erzeugen!'); // Die Figur in die Welt einfügen InitOK := Boolean(geWorld_AddActor (Welt, Actor, GE_ACTOR_RENDER_NORMAL, $fffffff)); if not InitOK then ExitError ('Figur lässt sich nicht in Welt einfügen!'); // Welt "übernehmen" World := Welt; // Startdaten für Animation setzen Motion := nil; MCount := GetTickCount; // 0.0; MSpeed := 0.0; isMoving := false; end;
Dann wird die Datei geladen, die sämtliche Daten für unsere Figur enthält:
ActorFile := geVFile_OpenNewSystem (nil, GE_VFILE_TYPE_DOS, PChar(DateiName), nil, GE_VFILE_OPEN_READONLY);
Während die Weltdaten als BSP-Datei gespeichert sind, sind die Daten einer Figur in einer Datei untergebracht, die für Genesis3D die Kennung ACT hat. Das ist ein Kürzel für „Actor“, zu Deutsch soviel wie „Schauspieler, Darsteller“. In Genesis3D sind damit nicht nur Akteure gemeint, also Figuren, die sich bewegen und auch etwas tun (können). Als Actor gilt aber ebenso z.B. ein Baum oder eine Figur, die unbeweglich einen Eingang bewacht. Viele Gegenstände in einem Spiel können also vom Typ Actor sein.
Um eine Figur zu erstellen, wird ein 3D-Grafikprogramm benötigt. Eine sehr preisgünstige Möglichkeit ist das Shareware-Programm MilkShape 3D (mit dem sich Figuren nicht nur für Genesis-Games, sondern auch für zahlreiche andere Spiele wie z.B. Quake, Half-Life, Unreal oder Max Payne erstellen lassen). Nun müssen wir zuerst die Daten auspacken, die die Figur beschreiben. Anschließend kann damit die Figur selbst zusammengebaut werden:
ActorDef := geActor_DefCreateFromFile (ActorFile); Actor := geActor_Create (ActorDef);
Die fertige Figur wird in die Welt eingefügt und diese kann dann mit der Eigenschaft World von TFigur verknüpft werden:
geWorld_AddActor (Welt, Actor, GE_ACTOR_RENDER_NORMAL, $fffffff)); World := Welt;
Zuletzt setzen wir die Ausgangswerte für eine mögliche Animation der Figur. Dabei sorgen wir jetzt dafür, dass sie erst einmal ihre Ruhe hat und stellen alles auf „regungslos“:
Motion := nil; MCount := GetTickCount; MSpeed := 0.0; isMoving := false;