Проектирование системы камер

8

Думая об общей игре, не имеет значения тип игры, очень вероятно, что нам нужен какой-то тип камеры. Например:

  • Камера отладки: управляется клавиатурой и мышью, благодаря чему мы можем перемещаться в любом месте нашей сцены.
  • Сценарий камеры: с этим мы можем дать команду камере двигаться по определенному пути.
  • Камера плеера.
  • ...

Каждый из этих типов камер имеет свою функцию обновления. Самая простая (и плохая) система - это иметь класс диспетчера камер с общей функцией обновления и специализированными функциями обновления для каждого типа камеры. Внутри общей функции обновления у нас есть оператор switch, который в зависимости от типа камеры вызывает соответствующую функцию обновления.

Вместо этого я подумал о другом подходе: шаблон стратегии. Мы перемещаем каждое поведение камеры (метод обновления) в соответствующий класс, который реализует общий интерфейс. В диспетчере камеры у нас есть член к этому интерфейсу, и мы можем динамически устанавливать любое поведение, которое мы хотим.

Что ты об этом думаешь? Какие еще системы вы мне предлагаете? Спасибо.

Дополнительная информация: есть реальная возможность, что мне нужно более одной активной камеры, например, для отражений. Короче говоря, я должен учитывать и это.

загадка
источник
Только что увидел вашу дополнительную информационную заметку. Проверьте мои изменения тогда.
Дэвид Гувейя

Ответы:

11

Шаблоны стратегии кажутся мне хорошей ставкой. Чтобы сделать еще один шаг, ваш менеджер камеры должен оставаться в неведении о конкретных типах камер. Вы могли бы зарегистрировать и изменить реализации камеры внешне по идентификатору (я использовал гибкость строки, но мог быть также enum или int), например (без какой-либо проверки ошибок):

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

редактировать

Дополнительная информация: есть реальная возможность, что мне нужно более одной активной камеры, например, для отражений. Короче говоря, я должен учитывать и это.

Это тривиально, чтобы добавить. Просто измените currentCameraна:

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

Измените SetCameraна ToggleCamera (или добавьте логическое значение для SetCamera, на ваш выбор):

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

И измените Updateметод для обновления всех активных камер вместо только текущей:

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

В моем примере вам также необходимо заменить Viewсвойство GetViewметодом, принимающим идентификатор камеры в качестве параметра. Но это деталь, которая все равно зависит от интерфейса вашей камеры:

// You could optionally add a check to see if the camera is active
Matrix GetView(string id) { return cameras[id].View; }
Дэвид Гувея
источник
Да, мне нравится ваш подход. На самом деле, в моем вопросе я забыл, что диспетчер камер ничего не знает о конкретных типах камер, в противном случае у нас есть еще один оператор switch для этого.
загадка
Кстати, я заметил, что у вас есть два вопроса, но никогда не принимал ответ. Ты знаешь как это делается? Это кнопка прямо под кнопкой понижения.
Дэвид Гувейя
Только не сходите с ума из-за разработки решения, добавления внедрения зависимостей, фабрики фабрик, языков сценариев домена камеры; вы понимаете, что я имею в виду =) ПРИМЕЧАНИЕ: вполне возможно, что вы хотите, чтобы к сцене было подключено более 1 камеры, не привязывайтесь к API, который не допускает эту концепцию.
Патрик Хьюз
@PatrickHughes, ты прав. Возможно, мне понадобится более одной камеры, прикрепленной к сцене (добавлено в моем вопросе).
загадка,
1
Для нескольких камер я бы порекомендовал нарисовать то, что видит каждая камера, в RenderTarget, а затем использовать SpriteBatch для рисования каждой из них, очевидно, масштабируя каждую из них в зависимости от количества камер.
FrenchyNZ