9
\$\begingroup\$

Thinking about a common game, doesn't matter the type of the game, it's very likely that we need some camera type. For example:

  • Debug camera: controlled by keyboard and mouse, with that we are able to move around in any place of our scene.
  • Scripted camera: with that we can instruct the camera to move around, following a determinate path.
  • Player camera.
  • ...

Each of these camera types has its own update function. The easiest (and bad) system,is to have a camera manager class with a generic update function and specialized update functions for every camera type. Inside the generic update function we have a switch statement that, based on the camera type, calls the proper update function.

Instead of this I've thought to another approach: strategy pattern. We move each camera behavior (update method) in an appropriate class that implements a common interface. In the camera manager we have a member to that interface, and we can set dinamically any behavior we want.

What do you think about that? What other systems do you suggest me? Thanks.

Additional info: there is the are real possibility that I need more than one camera active, for example for reflections. In short, I must take account also of that.

\$\endgroup\$
1
  • \$\begingroup\$ Just saw your additional info note. Check my edit then. \$\endgroup\$ Dec 20, 2011 at 20:49

1 Answer 1

12
\$\begingroup\$

The strategy patterns seems like a good bet to me. To take it a step further, your camera manager should remain ignorant of the concrete camera types. You would register and change camera implementations externally by id (I used a string for flexibility but could be an enum or an int too), for instance (without any error checking):

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

Edit

Additional info: there is the are real possibility that I need more than one camera active, for example for reflections. In short, I must take account also of that.

That's trivial to add. Just change currentCamera to:

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

Change SetCamera to ToggleCamera (or add a boolean to SetCamera, your choice):

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

And change the Update method to update all active cameras instead of only the current one:

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

In my example, you'd also need to replace the View property with a GetView method taking the id of the camera as parameter. But that's a detail that depends on your camera interface anyway:

// You could optionally add a check to see if the camera is active
Matrix GetView(string id) { return cameras[id].View; }
\$\endgroup\$
8
  • \$\begingroup\$ Yes, I like your approach. In fact, in my question, I've forgotten that the camera manager don't knows anything about the specific camera types, otherwise we have another switch statement for that. \$\endgroup\$
    – enigma
    Dec 20, 2011 at 17:03
  • \$\begingroup\$ By the way, I noticed that you have two questions but never accepted an answer. Do you know how that's done? It's the button right below the downvote button. \$\endgroup\$ Dec 20, 2011 at 18:07
  • \$\begingroup\$ Just don't go crazy over-engineering a solution, adding dependency injection, factory of factories, camera domain scripting languages; you know what I mean =) NOTE: It's entirely possible that you want more than 1 camera attached to a scene, don't lock yourself into an API that won't allow that concept. \$\endgroup\$ Dec 20, 2011 at 19:09
  • \$\begingroup\$ @PatrickHughes, you're right. Probably I will need more than one camera attached to the scene (added in my question). \$\endgroup\$
    – enigma
    Dec 20, 2011 at 20:45
  • 1
    \$\begingroup\$ For having multiple cameras, I would recommend drawing what each camera sees to a RenderTarget, then using SpriteBatch to draw each one, Obviously scaling each one depending on how many cameras there are. \$\endgroup\$
    – FrenchyNZ
    Dec 21, 2011 at 1:07

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .