Projeto de um sistema de câmera

8

Pensando em um jogo comum, não importa o tipo de jogo, é muito provável que precisemos de algum tipo de câmera. Por exemplo:

  • Câmera de depuração: controlada pelo teclado e mouse, com isso somos capazes de nos mover em qualquer lugar da nossa cena.
  • Câmera com script: com isso, podemos instruir a câmera a se mover, seguindo um caminho determinado.
  • Câmera do jogador.
  • ...

Cada um desses tipos de câmera possui sua própria função de atualização. O sistema mais fácil (e ruim) é ter uma classe de gerenciador de câmeras com uma função de atualização genérica e funções especializadas de atualização para cada tipo de câmera. Dentro da função de atualização genérica, temos uma instrução switch que, com base no tipo de câmera, chama a função de atualização adequada.

Em vez disso, pensei em outra abordagem: padrão de estratégia. Movemos o comportamento de cada câmera (método de atualização) em uma classe apropriada que implementa uma interface comum. No gerenciador de câmeras, temos um membro para essa interface e podemos definir dinamicamente qualquer comportamento que desejar.

O que você acha disso? Que outros sistemas você me sugere? Obrigado.

Informações adicionais: existe a possibilidade real de eu precisar de mais de uma câmera ativa, por exemplo, para reflexões. Em suma, devo levar em conta também isso.

enigma
fonte
Acabei de ver sua nota informativa adicional. Verifique minha edição então.
David Gouveia

Respostas:

11

Os padrões de estratégia parecem ser uma boa aposta para mim. Para dar um passo adiante, seu gerente de câmera deve permanecer ignorante quanto aos tipos concretos de câmera. Você registraria e alteraria as implementações de câmera externamente por id (usei uma string para flexibilidade, mas também poderia ser um enum ou int), por exemplo (sem nenhuma verificação de erro):

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

Informações adicionais: existe a possibilidade real de eu precisar de mais de uma câmera ativa, por exemplo, para reflexões. Em suma, devo levar em conta também isso.

Isso é trivial para adicionar. Apenas mude currentCamerapara:

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

Mude SetCamerapara ToggleCamera (ou adicione um booleano ao SetCamera, sua escolha):

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

E mude o Updatemétodo para atualizar todas as câmeras ativas, em vez de apenas a atual:

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

No meu exemplo, você também precisará substituir a Viewpropriedade por um GetViewmétodo que tome o ID da câmera como parâmetro. Mas esse é um detalhe que depende da interface da câmera:

// You could optionally add a check to see if the camera is active
Matrix GetView(string id) { return cameras[id].View; }
David Gouveia
fonte
Sim, eu gosto da sua abordagem. De fato, na minha pergunta, esqueci que o gerente da câmera não sabe nada sobre os tipos específicos de câmeras, caso contrário, temos outra declaração de chave para isso.
20911 enigma
A propósito, notei que você tem duas perguntas, mas nunca aceitou uma resposta. Você sabe como isso é feito? É o botão logo abaixo do botão de voto negativo.
David Gouveia
Apenas não enlouqueça ao projetar uma solução, adicionando injeção de dependência, fábrica de fábricas, linguagens de script de domínio de câmera; você entende o que quero dizer =) NOTA: É perfeitamente possível que você queira mais de uma câmera conectada a uma cena; não se prenda a uma API que não permita esse conceito.
Patrick Hughes
@PatrickHughes, você está certo. Provavelmente vou precisar de mais de uma câmera conectada à cena (adicionada na minha pergunta).
Enigma
11
Por ter várias câmeras, eu recomendaria desenhar o que cada câmera vê em um RenderTarget e, em seguida, usar o SpriteBatch para desenhar cada uma, dimensionando obviamente cada uma, dependendo de quantas câmeras existem.
precisa saber é o seguinte