Diseño de un sistema de cámara.

8

Pensando en un juego común, no importa el tipo de juego, es muy probable que necesitemos algún tipo de cámara. Por ejemplo:

  • Cámara de depuración: controlada por teclado y mouse, con eso podemos movernos en cualquier lugar de nuestra escena.
  • Cámara con secuencia de comandos: con eso podemos indicarle a la cámara que se mueva, siguiendo un camino determinado.
  • Cámara de jugador
  • ...

Cada uno de estos tipos de cámaras tiene su propia función de actualización. El sistema más fácil (y malo) es tener una clase de administrador de cámara con una función de actualización genérica y funciones de actualización especializadas para cada tipo de cámara. Dentro de la función de actualización genérica tenemos una declaración de cambio que, según el tipo de cámara, llama a la función de actualización adecuada.

En lugar de esto, he pensado en otro enfoque: patrón de estrategia. Movemos el comportamiento de cada cámara (método de actualización) en una clase apropiada que implemente una interfaz común. En el administrador de cámara tenemos un miembro para esa interfaz, y podemos configurar dinámicamente cualquier comportamiento que queramos.

¿Qué piensas sobre eso? ¿Qué otros sistemas me sugieres? Gracias.

Información adicional: existe la posibilidad real de que necesite más de una cámara activa, por ejemplo, para reflexiones. En resumen, debo tener en cuenta también eso.

enigma
fuente
Acabo de ver su nota de información adicional. Mira mi edición entonces.
David Gouveia

Respuestas:

11

Los patrones de estrategia me parecen una buena apuesta. Para ir un paso más allá, el administrador de su cámara debe permanecer ignorante de los tipos concretos de cámaras. Debería registrar y cambiar las implementaciones de la cámara externamente por id (utilicé una cadena para flexibilidad pero también podría ser una enumeración o un int), por ejemplo (sin verificación de errores):

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");
}

Editar

Información adicional: existe la posibilidad real de que necesite más de una cámara activa, por ejemplo, para reflexiones. En resumen, debo tener en cuenta también eso.

Eso es trivial de agregar. Solo cambia currentCameraa:

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

Cambie SetCameraa ToggleCamera (o agregue un booleano a SetCamera, su elección):

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

Y cambie el Updatemétodo para actualizar todas las cámaras activas en lugar de solo la actual:

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

En mi ejemplo, también necesitaría reemplazar la Viewpropiedad con un GetViewmétodo que tome la identificación de la cámara como parámetro. Pero ese es un detalle que depende de la interfaz de su cámara de todos modos:

// You could optionally add a check to see if the camera is active
Matrix GetView(string id) { return cameras[id].View; }
David Gouveia
fuente
Sí, me gusta tu enfoque. De hecho, en mi pregunta, he olvidado que el administrador de la cámara no sabe nada sobre los tipos de cámara específicos, de lo contrario, tenemos otra declaración de cambio para eso.
enigma
Por cierto, noté que tienes dos preguntas pero nunca aceptaste una respuesta. ¿Sabes cómo se hace? Es el botón justo debajo del botón de voto negativo.
David Gouveia
Simplemente no se vuelva loco al diseñar una solución, agregando inyección de dependencia, fábrica de fábricas, lenguajes de secuencias de comandos de dominio de cámara; sabes lo que quiero decir =) NOTA: es muy posible que quieras más de 1 cámara conectada a una escena, no te encierres en una API que no permita ese concepto.
Patrick Hughes
@PatrickHughes, tienes razón. Probablemente necesitaré más de una cámara conectada a la escena (agregada en mi pregunta).
enigma
1
Para tener varias cámaras, recomendaría dibujar lo que cada cámara ve en un RenderTarget, luego usar SpriteBatch para dibujar cada una, obviamente escalando cada una dependiendo de cuántas cámaras haya.
FrenchyNZ