Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I asked that question at StackOverflow, but I've been told, that SO is not the right place for code reviews and I've been pointed here.


I've read a lot about using MVC in game development and it seems to be a good way (speaking of testing, code reusing, etc ...)

I created a XNA project and tried to implement MVC. But I'm not sure if I'm doing it right.

Could you have a look at it?

--

I seperated the game into three blocks:

  • Renderers (the "View")
  • GameObjects and GameLogic (the "Model")
  • Controllers

On top of these components is a GameEngine object (created by the XNA game class) which instantiates all of the components and handles the draw and update methods (game class calls GameEngine.Draw and GameEngine.Update)

public class GameEngine
{
    private readonly HUDRenderer m_HUDRenderer;
    private readonly Game m_game;
    private readonly List<IRenderer> m_lstRenderer = new List<IRenderer>();

    private readonly Player m_player;
    private readonly PlayerRenderer m_playerRenderer;
    private readonly World m_world;
    private readonly WorldController m_worldController;

    private readonly WorldRenderer m_worldRenderer;


    public GameEngine(Game game)
    {
        m_game = game;

        m_player = new Player();
        m_world = new World(m_player);

        // Controller
        m_worldController = new WorldController(m_world);

        // Views
        m_worldRenderer = new WorldRenderer(m_world);
        m_lstRenderer.Add(m_worldRenderer);

        m_playerRenderer = new PlayerRenderer(m_world);
        m_lstRenderer.Add(m_playerRenderer);

        m_HUDRenderer = new HUDRenderer(m_world);
        m_lstRenderer.Add(m_HUDRenderer);
    }

    public void Update(GameTime gameTime)
    {
        m_worldController.Update(gameTime);
    }

    public void Draw(GameTime gameTime, DrawContext drawContext)
    {
        drawContext.Begin();

        // ########## ADD ALL DRAW METHODS ##########

        foreach (IRenderer renderer in m_lstRenderer)
        {
            renderer.Render(gameTime, drawContext);
        }

        // ########## END OF ADD ALL DRAW METHODS ##########

        drawContext.End();
    }

    /// <summary>
    /// Loads all the content
    /// </summary>
    /// <param name="content"> </param>
    public void LoadContent(ContentManager content)
    {
    }
}

Additionally GameEngine creates the Player object and a World object. All GameObjects are POCOs. The World holds the Player, the "obstacles" and "enemies".

public class World
{
    public List<List<Entity>> WorldGrid;

    public World(Player player)
    {
        Player = player;
        FPSCounter = new FPSCounter("0", new Vector2(16, 16), Color.White);
    }

    public FPSCounter FPSCounter { get; private set; }
    public Player Player { get; private set; }
}

The World is passed as an argument to the Renderers so they have access to the object they need to draw and the world (if the objects need to visually interact with the world).

 public class HUDRenderer : IRenderer
{
    private readonly World m_world;

    public HUDRenderer(World world)
    {
        m_world = world;
    }

    #region IRenderer Members

    public void Render(GameTime gameTime, DrawContext drawContext)
    {
        m_world.FPSCounter.FrameCount += 1;

        if (m_world.FPSCounter.Font != null)
        {
            drawContext.SpriteBatch.DrawString(m_world.FPSCounter.Font, m_world.FPSCounter.Text, m_world.FPSCounter.Position, m_world.FPSCounter.Color);
        }
        else
        {
            drawContext.SpriteBatch.DrawString(drawContext.DefaultFont, m_world.FPSCounter.Text, m_world.FPSCounter.Position, m_world.FPSCounter.Color);
        }
    }

    #endregion
}

The Controller recieves input and changes the model by using the GameLogic.

public class WorldController
{
    private readonly World m_world;
    private KeyboardState m_keyboardState;
    private MouseState m_mouseState;

    public WorldController(World world)
    {
        m_world = world;
    }

    public void Update(GameTime gameTime)
    {
        m_keyboardState = Keyboard.GetState();
        m_mouseState = Mouse.GetState();

        var hudLogic = new HudGLO();
        hudLogic.CalculateFPS(gameTime, m_world.FPSCounter);
    }
}

And the Views render everything.

public class HUDRenderer : IRenderer
{
    private readonly World m_world;

    public HUDRenderer(World world)
    {
        m_world = world;
    }

    #region IRenderer Members

    public void Render(GameTime gameTime, DrawContext drawContext)
    {
        m_world.FPSCounter.FrameCount += 1;

        if (m_world.FPSCounter.Font != null)
        {
            drawContext.SpriteBatch.DrawString(m_world.FPSCounter.Font, m_world.FPSCounter.Text, m_world.FPSCounter.Position, m_world.FPSCounter.Color);
        }
        else
        {
            drawContext.SpriteBatch.DrawString(drawContext.DefaultFont, m_world.FPSCounter.Text, m_world.FPSCounter.Position, m_world.FPSCounter.Color);
        }
    }

    #endregion
}

I'm passing the World object in most of the other objects. Does this make sense? Should it be static somewhere?

Am I even getting close to the MVC principle?

Where do you put logic concerning an object (like player movement). Does it reside in the object itself or is it "outsourced" in the gamelogic? OOP vs. MVC?

--

If you want to see the complete code you can find the project at: https://github.com/bux578/XNA-MVC-Template

If it's somehow helpful to you, feel free to extend, fork or copy it.

share|improve this question
2  
Please include code in the question. "This site is for code reviews, which are hard to do when the code is behind a link somewhere out there on the internet. If you want a code review, you must post the relevant snippets of code in your question. It is fine to post a "see more" link (though, do be careful — very few reviewers will be willing to click through and read thousands of lines of your code), but the most important parts of the code must be placed directly in the question." (from the FAQ) –  palacsint Oct 12 '12 at 9:22
2  
@palacsint I added the code to the question. Thank you for the hint. –  Jo David Oct 12 '12 at 10:17
    
Why GameLogic is a model? Logic is something that controls another "something", thus it is more controller than model. –  kknot Nov 16 '12 at 14:25
1  
This is a good question, and it's a pity that it has not received a good and thorough answer - or at least some discussion. I added a bounty. Hopefully this will spark good attention and discussion, and even renew the asker's interest in the community. :) –  ANeves Dec 10 '12 at 19:05
add comment

1 Answer

To answer your questions, 1) I would make the World a singleton, therefore both eliminating the need for quite a few params and the need to put it as a static field somewhere. However, make sure that retrieving the instance is a lightweight method, because it will happen a lot. As for the game logic, I would say it depends. For objects which have only one or three instances, I would put the logic in the class, but for more numerous things, put that in a seperate object.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.