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;