Code Sample

Here’s sample piece of code in C# (for Unity). It is a simple and generic status message system, and should give some idea of what kind of practices I use when writing code. The core of the system is MessageManager, messages are held in Message objects and at the bottom is MessageManagerDemo, a simple Unity component for demonstrating usage. If you want to test the system in action, copy the three classes to a Unity project, add MessageManagerDemo component to a gameobject, and press play.

MessageManager.cs

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace Lusmu.GenericTools
{
	/// <summary>
	/// Message manager.
	///
	/// Manages status messages, but does not render them on screen.
	/// One instance can be accessed statically through MessageManager.Main,
	/// or you can create separate instances with new MessageManager().
	///
	/// Add messages with Add(Message message), Add(string text) or
	/// Add(string title, string text, int priority, float lifeTime, Texture image)
	/// Get messages with GetTopmost() or GetMessage(int index)
	/// Remove messages with RemoveTopmost(), RemoveMessage(Message message)
	/// or RemoveById(int id)
	/// </summary>
	public class MessageManager
	{
		private static MessageManager instance;
		public static MessageManager Main
		{
			get
			{
				if (instance == null)
				{
					instance = new MessageManager ();
				}

				return instance;
			}
		}

		public event System.Action<Message> MessageAdded;

		public int MessageCount { get { return Messages.Count; } }

		public List<Message> Messages { get; set; }

		public int DefaultPriority  { get; set; }

		public bool OrderMessagesByPriority { get; set; }

		private int _maxMessages = 1000;
		public int MaxMessages
		{
			get { return _maxMessages; }
			set { if (_maxMessages > 0) _maxMessages = value; }
		}

		private float _defaultLifeTime = 10;
		public float DefaultLifeTime
		{
			get { return _defaultLifeTime; }
			set { if (_defaultLifeTime > 0) _defaultLifeTime = value; }
		}

		public MessageManager ()
		{
			Messages = new List<Message> ();
		}

		public MessageManager (	int maxMessages, float defaultLifeTime,
								int defaultPriority, bool orderMessagesByPriority)
		{
			this.MaxMessages = maxMessages;
			this.DefaultLifeTime = defaultLifeTime;
			this.DefaultPriority = defaultPriority;
			this.OrderMessagesByPriority = orderMessagesByPriority;
		}

		// ================================================================
		#region public API
		/// <summary>
		/// Gets the message that should be displayed next.
		/// </summary>
		public Message GetTopmost()
		{
			return GetMessage(0);
		}

		/// <summary>
		/// Gets the message with specified index from the message queue.
		/// </summary>
		public Message GetMessage (int index)
		{
			if (index < Messages.Count) return Messages [index];
			else return null;
		}

		/// <summary>
		/// Adds a message to its appropriate place in the message queue.
		/// </summary>
		public void AddMessage (string text)
		{
			AddMessage (string.Empty, text, DefaultPriority, DefaultLifeTime, null);
		}

		/// <summary>
		/// Adds a message to its appropriate place in the message queue.
		/// </summary>
		public void AddMessage (string title, string text, int priority,
								float lifeTime, Texture image)
		{
			Message message = new Message (title, text, priority, image, lifeTime);
			AddMessage (message);
		}

		/// <summary>
		/// Adds a message to its appropriate place in the message queue.
		/// </summary>
		public void AddMessage (Message message)
		{
			if (OrderMessagesByPriority)
			{
				int index = 0;
				for (index = 0; index < Messages.Count; index++)
				{
					if (message.priority > Messages [index].priority) break;
				}

				Messages.Insert (index, message);
			}
			else
			{
				Messages.Add (message);
			}

			if (Messages.Count > MaxMessages)
			{
				RemoveLowestOldest();
			}

			OnAddMessage(message);
		}

		/// <summary>
		/// Removes the topmost message from the message queue.
		/// </summary>
		public void RemoveMessage (Message message)
		{
			Messages.Remove (message);
		}

		/// <summary>
		/// Removes the topmost message from the message queue.
		/// </summary>
		public void RemoveTopmost()
		{
			RemoveMessage(0);
		}

		/// <summary>
		/// Removes a message from message queue by its id number.
		/// </summary>
		public void RemoveById(int id)
		{
			Message message = Messages.FirstOrDefault(m => m.messageId == id);

			if (message != null) Messages.Remove(message);
		}

		/// <summary>
		/// Removes a message by its index in the message queue.
		/// </summary>
		public void RemoveMessage(int index)
		{
			if (index >= 0 && index < MessageCount)
			{
				Messages.RemoveAt(index);
			}
		}

		/// <summary>
		/// Removes all messages at or below the specified priority.
		/// </summary>
		public void RemoveByPriority(int priorityToRemove)
		{
			for (int i = Messages.Count - 1; i >= 0; i--)
			{
				if (Messages[i].priority <= priorityToRemove)
				{
					Messages.RemoveAt(i);
				}
			}
		}

		/// <summary>
		/// Removes the oldest message of the lowest priority.
		/// </summary>
		public void RemoveLowestOldest()
		{
			Message messageToRemove
				= Messages.OrderByDescending(m => m.priority).FirstOrDefault();

			if (messageToRemove != null)
			{
				Messages.Remove(messageToRemove);
			}
		}

		/// <summary>
		/// Clears the message list.
		/// </summary>
		public void Clear()
		{
			Messages.Clear();
		}
		#endregion

		void OnAddMessage(Message message)
		{
			// Only raise the event if message was added successfully
			if (MessageAdded != null && Messages.Contains(message))
			{
				MessageAdded(message);
			}
		}
	}
}

Message.cs

using UnityEngine;

namespace Lusmu.GenericTools
	{
	/// <summary>
	/// A message.
	///
	/// Can contain title, text and image.
	/// Also has priority, lifetime and timestamp.
	/// The message is equipped with a readonly messageId,
	/// that is based on static messageCount.
	/// </summary>
	public class Message
	{
		public string title = string.Empty;

		public string text;

		public Texture image = null;

		public int priority = 10;
		public System.DateTime timestamp;
		public readonly int messageId;
		public float lifeTime = 10;

		public static int messageCount { get; private set; }

		public Message (string text)
			: this (string.Empty, text, 10, null, 10)
		{}

		public Message (string title, string text, int priority)
			: this (title, text, priority, null, 10)
		{}

		public Message (string title, string text, int priority,
						Texture image, float lifeTime)
		{
			this.title = title;
			this.text = text;
			this.priority = priority;
			this.timestamp = System.DateTime.Now;
			this.image = image;
			this.lifeTime = lifeTime;

			messageId = messageCount;
			messageCount ++;
		}

		public override string ToString()
		{
			return messageId + " " + title + " " + text;
		}
	}
}

MessageManagerDemo.cs

using UnityEngine;
using Lusmu.GenericTools;

public class MessageManagerDemo : MonoBehaviour
{
	MessageManager manager;
	Message current;

	void Start()
	{
		manager = MessageManager.Main;
		manager.MessageAdded += OnAddMessage;
	}

	void OnDestroy()
	{
		// Remember to remove event listener
		if (manager != null)
			manager.MessageAdded -= OnAddMessage;
	}

	void Update ()
	{
		if (current != null)
		{
			// Age the current message,
			// and remove if lifeTime spent
			current.lifeTime -= Time.deltaTime;
			if (current.lifeTime <= 0)
			{
				manager.RemoveTopmost();
				current = manager.GetTopmost();
			}
		}
	}

	void OnAddMessage(Message newMessage)
	{
		// When a message is added, show it unless it has a lower
		// priority then current
		if (current == null || newMessage.priority > current.priority)
		{
			current = newMessage;
		}
	}

	void OnGUI()
	{
		if (current != null)
		{
			// Draw current message text
			GUI.Label(new Rect(10, 10, Screen.width - 20, 30),
						current.text);

			// Button for removing the current, and showing next
			if (GUI.Button(new Rect(10, 100, 250, 50), "Next"))
			{
				manager.RemoveTopmost();
				current = manager.GetTopmost();
			}
		}

		// Show how many messages in queue
		if (manager.MessageCount > 1)
		{
			GUI.Label(new Rect(10, 50, Screen.width - 20, 30),
						(manager.MessageCount - 1) + " more messages in queue");
		}

		// Button for adding a message with random message
		if (GUI.Button(new Rect(10, 170, 250, 50), "Add Random message"))
		{
			manager.AddMessage("A message with a number " + Random.Range(1, 999));
		}
	}
}


Leave a Reply

Please log in using one of these methods to post your comment:

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