Model-View-Controller

Purpose:

  • To simplify code architecture.

Description:

  • Logic is separated into 3 main groups of functionality:
    • Model: Data.
    • View: Interface/Rendering.
    • Controller: Business/Game Logic.
  • Models:

    • Hold Data/State.
    • Serialise and Deserialise (saving).
    • Convert between types.
    • Are accessed but never do any accessing (they are “dumb” data objects).
  • Views:

    • Can get data from models.
    • Should never mutate models.
    • Strictly implements the functionality of its class:
      • Acts as a black box.
      • Does not store the core data (as this is what the model should store).
      • Does not contain game/business logic.
  • Controllers:

    • Do not store core data.
    • Update and use the Model’s data.
    • Manages Unity’s scene workflow.

Example:

This is a relatively simple example where some racers are created and set to race against each other across a console window.

  • Racers:

    • Each racer has a RacerData object which is the model. This data gets manipulated by a RacerController. All the racer controllers are set to race against each other by the race simulator. The RaceSimulator is also a controller.
    • The RacerRenderer contains the logic to “draw” the racers as they are raced against one another by the race simulator. It reads the racer’s data but does not modify it in any way

Racer MVC

using System;
using System.Threading;
using System.Collections.Generic;

class MainClass
{
	public static void Main (string[] args)
	{
		RaceSimulator simulation= new RaceSimulator(Console.WindowWidth);
		RacerRenderer renderer 	= new RacerRenderer();

		// Add the player to the simulation
		Console.WriteLine("Enter your name and press Enter.");
		string playerName = Console.ReadLine();
		RacerFactory.CreateRacer(playerName, simulation, renderer);

		// Add other racers to simulation
		string[] racerNames = new string[]{"Jack", "Joe", "Jane", "Jenny", "Jason"};
		foreach(string racerName in racerNames)
		{
			RacerFactory.CreateRacer(racerName, simulation, renderer);
		}

		// Game Loop
		while(true)
		{
			simulation.Update();
			renderer.Render();

			// Fixed framerate for simplicity
			Thread.Sleep(300);
		}
	}
}

/// <summary>
/// MODEL
/// - Stores the racer data.
/// </summary>
public class RacerData
{
	public string name;
	public int x;
	public int y;
	public int speed;
	public int lap;
}

/// <summary>
/// CONTROLLER
/// - Game Logic which modifies the racer's data.
/// </summary>
public class RacerController
{
	public RacerController(RacerData data)
	{
		_data = data;
	}

	public void SetPosition(int y)
	{
		_data.y	= y;
	}

	public void Move()
	{
		_data.x += _data.speed;
	}

	public void CompleteLap()
	{
		_data.lap++;
		_data.x = 0;
	}

	public bool WithinBounds(int width)
	{
		return _data.x <= width;
	}

	private RacerData _data;
}

/// <summary>
/// CONTROLLER
/// - Makes the individual race controllers race against one another.
/// </summary>
public class RaceSimulator
{
	public RaceSimulator(int width)
	{
		_width 	= width;
		Racers 	= new List<RacerController>();
	}

	public void AddRacer(RacerController racer)
	{
		racer.SetPosition(Racers.Count);
		Racers.Add(racer);
	}

	public void Update()
	{
		foreach(RacerController racer in Racers)
		{
			racer.Move();

			if(!racer.WithinBounds(_width))
			{
				racer.CompleteLap();
			}
		}
	}

	public List<RacerController> Racers { get; private set; }
	int _width;
}

/// <summary>
/// VIEW
/// - Draws the racers
/// </summary>

public class RacerRenderer
{
	public RacerRenderer()
	{
		_racers	= new List<RacerData>();
	}

	public void AddRacer(RacerData racerData)
	{
		_racers.Add(racerData);
	}

	public void Render()
	{
		Console.Clear();

		foreach(RacerData racer in _racers)
		{
			string racerInfo = racer.name + ", Lap: " + racer.lap;

			if(racer.x < Console.WindowWidth)
			{
				Console.SetCursorPosition(racer.x, racer.y);
				Console.Write(racerInfo);
			}
		}
	}

	List<RacerData> _racers;
}

/// <summary>
/// Helper factory class to create and configure the racer objects.
/// </summary>
static class RacerFactory
{
	static Random _random = new Random();

	public static void CreateRacer(string name, RaceSimulator simulation, RacerRenderer renderer)
	{
		RacerData racerData = new RacerData();
		racerData.name	= name;
		racerData.x 	= 0;
		racerData.y		= 0;
		racerData.lap	= 0;
		racerData.speed	= _random.Next(1, 10);

		RacerController racerController	= new RacerController(racerData);

		simulation.AddRacer(racerController);
		renderer.AddRacer(racerData);
	}
}

Sources:

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s