Design eines Kamerasystems

8

Wenn wir an ein gemeinsames Spiel denken, spielt es keine Rolle, welche Art von Spiel wir spielen. Es ist sehr wahrscheinlich, dass wir einen Kameratyp benötigen. Zum Beispiel:

  • Debug-Kamera: Mit Tastatur und Maus gesteuert, können wir uns an jedem Ort unserer Szene bewegen.
  • Skriptkamera: Damit können wir die Kamera anweisen, sich auf einem bestimmten Pfad zu bewegen.
  • Player Kamera.
  • ...

Jeder dieser Kameratypen verfügt über eine eigene Aktualisierungsfunktion. Das einfachste (und schlechteste) System besteht darin, eine Kameramanager-Klasse mit einer allgemeinen Aktualisierungsfunktion und speziellen Aktualisierungsfunktionen für jeden Kameratyp zu haben. Innerhalb der generischen Aktualisierungsfunktion haben wir eine switch-Anweisung, die basierend auf dem Kameratyp die richtige Aktualisierungsfunktion aufruft.

Stattdessen habe ich mir einen anderen Ansatz überlegt: das Strategiemuster. Wir verschieben jedes Kameraverhalten (Aktualisierungsmethode) in eine geeignete Klasse, die eine gemeinsame Schnittstelle implementiert. Im Kameramanager haben wir ein Mitglied für diese Benutzeroberfläche, und wir können jedes gewünschte Verhalten dynamisch festlegen.

Was denkst du darüber? Welche anderen Systeme schlagen Sie mir vor? Vielen Dank.

Zusätzliche Infos: Es besteht die reale Möglichkeit, dass ich mehr als eine Kamera aktiv brauche, zum Beispiel für Reflexionen. Kurz gesagt, ich muss auch das berücksichtigen.

Rätsel
quelle
Habe gerade deine zusätzliche Info-Notiz gesehen. Überprüfen Sie dann meine Bearbeitung.
David Gouveia

Antworten:

11

Die Strategiemuster scheinen mir eine gute Wette zu sein. Um noch einen Schritt weiter zu gehen, sollte Ihr Kameramanager die konkreten Kameratypen nicht kennen. Sie würden Kameraimplementierungen extern anhand der ID registrieren und ändern (ich habe aus Gründen der Flexibilität eine Zeichenfolge verwendet, könnte aber auch eine Aufzählung oder eine Int sein) (ohne Fehlerprüfung):

public interface ICamera
{
    void Update(float dt);
    Matrix View { get; }
}

public class CameraManager
{
    private Dictionary<string, ICamera> cameras;
    private ICamera currentCamera;

    public void RegisterCamera(string id, ICamera camera) { cameras[id] = camera; }
    public void SetCamera(string id) { currentCamera = cameras[id]; }

    public void Update(float dt) { currentCamera.Update(dt); }
    public Matrix View { get { return currentCamera.View; } }
}

public class DebugCamera : ICamera {}
public class PlayerCamera : ICamera {}
public class ScriptedCamera : ICamera {}

void Test()
{
    // Create camera manager
    CameraManager cameraManager = new CameraManager();

    // Register cameras
    cameraManager.RegisterCamera("Debug", new DebugCamera());
    cameraManager.RegisterCamera("Player", new PlayerCamera());
    cameraManager.RegisterCamera("Scripted", new ScriptedCamera());

    // Change active camera
    cameraManager.SetCamera("Player");
}

Bearbeiten

Zusätzliche Infos: Es besteht die reale Möglichkeit, dass ich mehr als eine Kamera aktiv brauche, zum Beispiel für Reflexionen. Kurz gesagt, ich muss auch das berücksichtigen.

Das ist trivial hinzuzufügen. Wechseln Sie einfach currentCamerazu:

List<ICamera> activeCameras = new List<ICamera>();

Wechseln Sie SetCamerazu ToggleCamera (oder fügen Sie SetCamera Ihrer Wahl einen Booleschen Wert hinzu):

void ToggleCamera(string id)
{
    ICamera camera = cameras[id];
    if(activeCameras.Contains(camera))
        activeCameras.Remove(camera);
    else
        activeCameras.Add(camera);
}

Und ändern Sie die UpdateMethode, um alle aktiven Kameras anstatt nur der aktuellen zu aktualisieren:

void Update(float dt) { activeCameras.ForEach(c => c.Update(dt)); }

In meinem Beispiel müssten Sie die ViewEigenschaft auch durch eine GetViewMethode ersetzen, die die ID der Kamera als Parameter verwendet. Aber das ist ein Detail, das sowieso von Ihrer Kameraoberfläche abhängt:

// You could optionally add a check to see if the camera is active
Matrix GetView(string id) { return cameras[id].View; }
David Gouveia
quelle
Ja, ich mag deinen Ansatz. Tatsächlich habe ich in meiner Frage vergessen, dass der Kameramanager nichts über die spezifischen Kameratypen weiß, andernfalls haben wir eine andere switch-Anweisung dafür.
Rätsel
Übrigens ist mir aufgefallen, dass Sie zwei Fragen haben, aber nie eine Antwort akzeptiert haben. Weißt du wie das geht? Es ist der Button direkt unter dem Downvote-Button.
David Gouveia
Machen Sie einfach keine verrückte Überentwicklung einer Lösung, indem Sie Abhängigkeitsinjektionen, Fabriken von Fabriken und Skriptsprachen für Kameradomänen hinzufügen. Sie wissen, was ich meine =) HINWEIS: Es ist durchaus möglich, dass Sie mehr als eine Kamera an eine Szene anhängen möchten. Schließen Sie sich nicht an eine API an, die dieses Konzept nicht zulässt.
Patrick Hughes
@PatrickHughes, du hast recht. Wahrscheinlich brauche ich mehr als eine Kamera an der Szene (in meiner Frage hinzugefügt).
Rätsel
1
Für mehrere Kameras würde ich empfehlen, das, was jede Kamera sieht, in ein RenderTarget zu zeichnen und dann SpriteBatch zu verwenden, um jede Kamera zu zeichnen. Dabei wird natürlich jede Kamera skaliert, je nachdem, wie viele Kameras es gibt.
FrenchyNZ