First Person View
In ihrer aktuellen Welt muss das Objekt explizit als First-Person-Objekt gekennzeichnet werden:
public class GameWorld : World { public override void Prepare() { Player p1 = new Player(); AddGameObject(p1) // Verbinde die Kamera mit dem Objekt und // verschiebe sie um 2 Einheiten nach oben: SetCameraToFirstPersonGameObject(p1, 2f); // Mausempfindlichkeit einstellen (negativ für invertierte Y-Achse): KWEngine.MouseSensitivity = 0.05f; // Deaktiviert den Mauszeiger und sorgt dafür, dass sich // der Cursor nicht außerhalb des Programmfensters bewegen kann: MouseCursorGrab(); } }
Anschließend muss noch in der Player
-Klasse auf die Tastatur- und Mauseingaben reagiert werden:
public class Player : GameObject { public override void Act() { // Initialisiere zwei Variablen: // forward == +1 -> Indikator für 'vorwärts' // forward == -1 -> Indikator für 'rückwärts' // strafe == +1 -> Indikator für 'strafe rechts' // strafe == -1 -> Indikator für 'strafe links' int forward = 0; int strafe = 0; if (Keyboard.IsKeyDown(Keys.A)) strafe -= 1; if (Keyboard.IsKeyDown(Keys.D)) strafe += 1; if (Keyboard.IsKeyDown(Keys.W)) forward += 1; if (Keyboard.IsKeyDown(Keys.S)) forward -= 1; // Nutze die Informationen im Mouse-Objekt, // um die Kamera dementsprechend rotieren zu lassen: CurrentWorld.AddCameraRotationFromMouseDelta(); // Bewege das Objekt entlang der aktuellen Blickrichtung // mit Hilfe der Variablenwerte in 'forward' und 'strafe'. // Der dritte Parameter ist die Geschwindigkeit. MoveAndStrafeAlongCameraXZ(forward, strafe, 0.01f); // Aktualisiere die Kameraposition: // (Erneut wird die Kamera um 2 Einheiten weiter oben platziert) CurrentWorld.UpdateCameraPositionForFirstPersonView(Center, 2f); // Optional: Drehe das (unsichtbare) Player-Objekt mit der Kamera: TurnTowardsXZ(CurrentWorld.CameraPosition + CurrentWorld.CameraLookAtVector); } } }
Waffenmodell anzeigen
Um im First-Person-Modus zusätzlich ein Waffenmodell anzuzeigen, das von der Spielfigur gehalten wird, importiert man zunächst das dafür nötige 3D-Modell auf gewohntem Weg.
Das First-Person-Waffenmodell wird immer über allen anderen Gegenständen gezeichnet, damit es nicht in einer Wand verschwindet, wenn die Spielfigur zu nahe davor steht. Die dafür verwendete Klasse lautet ViewSpaceGameObject
, und Sie müssen eine eigene Unterklasse dieses Typs erstellen. Die Bezeichnung „view space“ kommt daher, weil sich dieses immer an der Kamera orientiert und in dessen Blickfeld („view space“) liegt.
public class MyFirstPersonWeapon : ViewSpaceGameObject { public override void Act() { // Passe das Objekt der ggf. geänderten // Kameraposition an: UpdatePosition(); } }
In der Prepare()
-Methode der Welt-Klasse führt folgender Code zur Einblendung eines Waffenmodells:
public override void Prepare() { KWEngine.LoadModel("Gun", "./modelfolder/gun.fbx"); MyFirstPersonWeapon fpw = new MyFirstPersonWeapon(); fpw.SetModel("Gun"); fpw.SetOffset(0.0f, -0.1f, 0.1f); // Verschiebung relativ zur Kamera fpw.SetScale(1.0f); // Skaliere das Objekt entsprechend SetViewSpaceGameObject(fpw); }
Wichtig:
Dieses Objekt ist nur dann sinnvoll, wenn die Kamera wie im First-Person-Modus gesteuert wird.
Third Person View
Um die Kamera stets in der Nähe des Spielerobjekts zu behalten, ist kein besonderer Modus einzustellen. Stattdessen sind ein paar einzelne Methodenaufrufe und Berechnungen nötig:
GameWorld
-Klasse:
public class GameWorld : World { public override void Prepare() { Player p1 = new Player(); p1.SetRotation(0, 180, 0); // Spielfigur soll sich um 180° drehen, um der Kamera den Rücken zuzudrehen AddGameObject(p1); // Deaktiviert den Mauszeiger und sorgt dafür, dass sich // der Cursor nicht außerhalb des Programmfensters bewegen kann: MouseCursorGrab(); } }
Player
-Klasse:
public class Player : GameObject { private Vector2 _currentCameraRotation = new Vector2(0, 0); private float _limitYUp = 5; private float _limitYDown = -75; public override void Act() { // Optional: // Wenn sich die Spielfigur mitdrehen soll, muss hier // die Mausbewegung auch zur Player-Rotation addiert werden! AddRotationY(-MouseMovement.X * KWEngine.MouseSensitivity); // Diese Methode berechnet die neue Kameraposition: UpdateCameraPosition(MouseMovement * KWEngine.MouseSensitivity); // Hier folgen anschließend die Tastaturabfragen für WSAD // oder andere Richtungstasten. Für Bewegungen auf der XZ-Achse // (Standard) könnte es wie folgt gelöst werden: // Initialisiere zwei Variablen: // forward == +1 -> Indikator für 'vorwärts' // forward == -1 -> Indikator für 'rückwärts' // strafe == +1 -> Indikator für 'strafe rechts' // strafe == -1 -> Indikator für 'strafe links' int forward = 0; int strafe = 0; if (Keyboard.IsKeyDown(Keys.A)) strafe -= 1; if (Keyboard.IsKeyDown(Keys.D)) strafe += 1; if (Keyboard.IsKeyDown(Keys.W)) forward += 1; if (Keyboard.IsKeyDown(Keys.S)) forward -= 1; // Bewege das Objekt entlang der aktuellen Blickrichtung // mit Hilfe der Variablenwerte in 'forward' und 'strafe'. // Der dritte Parameter ist die Bewegungsgeschwindigkeit. MoveAndStrafeAlongCameraXZ(forward, strafe, 0.01f); } private void UpdateCameraPosition(Vector2 msMovement) { // Berechne anhand der Mausbewegung, um wieviel Grad die Kamera // sich drehen müsste: _currentCameraRotation.X += msMovement.X; _currentCameraRotation.Y += msMovement.Y; // Damit die Kamera nicht "über Kopf" geht, wird die Rotation nach // oben und unten begrenzt: if (_currentCameraRotation.Y < _limitYDown) { _currentCameraRotation.Y = _limitYDown; } if (_currentCameraRotation.Y > _limitYUp) { _currentCameraRotation.Y = _limitYUp; } // Erfrage aktuelle Position der Spielfigur: Vector3 playerPosition = Center; // Berechne die neue Kameraposition anhand der gesammelten Infos: Vector3 newCamPos = HelperRotation.CalculateRotationForArcBallCamera( playerPosition, // Drehpunkt 10f, // Distanz zum Drehpunkt _currentCameraRotation.X, // Drehung links/rechts _currentCameraRotation.Y, // Drehung oben/unten false, // invertiere links/rechts? false // invertiere oben/unten? ); // Setze die neue Kameraposition und das Kameraziel: CurrentWorld.SetCameraPosition(newCamPos); CurrentWorld.SetCameraTarget(playerPosition); } }
Falls die Kamera nicht direkt hinter der Spielfigur positioniert werden soll, benötigen Kameraposition und -ziel eine leichte Verschiebung (ein sogenannter Offset). Dann gilt folgende Alternative für die UpdateCameraPosition()
-Methode:
public class Player : GameObject { // ... private void UpdateCameraPosition(Vector2 msMovement) { // Berechne anhand der Mausbewegung, um wieviel Grad die Kamera // sich drehen müsste: _currentCameraRotation.X += msMovement.X * _rotationScaleFactor; _currentCameraRotation.Y += msMovement.Y * _rotationScaleFactor; // Damit die Kamera nicht "über Kopf" geht, wird die Rotation nach // oben und unten begrenzt: if (_currentCameraRotation.Y < _limitYDown) { _currentCameraRotation.Y = _limitYDown; } if (_currentCameraRotation.Y > _limitYUp) { _currentCameraRotation.Y = _limitYUp; } // Erfrage aktuelle Blickrichtung und Position der Spielfigur: Vector3 lookAtVector = LookAtVector; Vector3 playerPosition = Center; // Berechne für Kameraposition und -ziel einen individuellen Offset-Wert: float lav_factor = (0.00012f * (_currentCameraRotation.Y * _currentCameraRotation.Y) + 0.02099f * _currentCameraRotation.Y + 0.89190f); float lav_factor2 = _currentCameraRotation.Y >= -15 ? (_currentCameraRotation.Y + 15) / 20f : 0f; Vector3 offsetCamPos = HelperRotation.RotateVector(lookAtVector, -90, Plane.XZ) + lookAtVector * 5 * lav_factor; Vector3 offsetCamTarget = HelperRotation.RotateVector(lookAtVector, -90, Plane.XZ) + lookAtVector * 2 + Vector3.UnitY * 2 * lav_factor2; // Berechne die neue Kameraposition anhand der gesammelten Infos: Vector3 newCamPos = HelperRotation.CalculateRotationForArcBallCamera( playerPosition, // Drehpunkt 10f, // Distanz zum Drehpunkt _currentCameraRotation.X, // Drehung links/rechts _currentCameraRotation.Y, // Drehung oben/unten false, // invertiere links/rechts? false // invertiere oben/unten? ); // Setze die neue Kameraposition und das Kameraziel: CurrentWorld.SetCameraPosition(newCamPos + offsetCamPos); CurrentWorld.SetCameraTarget(playerPosition + offsetCamTarget); } }
Schreibe einen Kommentar