Design and C# Possibilities

Started by
2 comments, last by Promit 14 years, 12 months ago
I have a game where I have an Item class. Instead of making each instance of that to belong to only one type like Weapon, Armor, Consumable, Radio, and so on, I'd like to, instead, let each instance of the Item object have multiple "properties". That's because I want to let them be very customizable, and have for example a survival jacket that is also a container, a helmet that has a radio, and so on. What I need is: A class that contains, as one of its elements, a list of properties, each one belonging to a different class (maybe all of them inheriting the same Property class). I thought of: List<Property> myPropertyList = new List<Property>(); And then: ListProperty.Add(new Armor); ListProperty.Add(new Radio); Is that possible to implement in the way explained? How close could I get to implement that sort of thing using C#? Does the "as" keyword need to or is able to be used to any utility here (so the Add() will accept the "heirs" of Property base class)? Thanks!
Advertisement
You've stumbled roughly on what most people describe as a component system. The classic paper, at least when applied to games, is Scott Bilas' GDC presentation. Read the first 20 slides or so; after that it shifts into high gear and goes into a lot of in depth advanced technical tricks that are entirely unnecessary for an indie/hobbyist.

Read that first and then we can start taking a look at putting it into practice [smile]
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
That's SO awesome! :P

Specially the part when he talks about what I wanted to do, the component system.

By looking at that I suppose the List<> won't do it, but maybe an object[] or an Array?

I can work out the code and stuff, but I need the idea of which data structures will work best as that is something you know a lot better than me.

Thanks again!
No, List<T> works just fine. The way I did this was like so:
	public abstract class GoComponent	{		[Browsable(true),		Category("\t\tGeneral"),		Description("The name of this component. Useful for linking or debugging.")]		public string Name		{			get;			set;		}		private GameObject m_parent;		[Browsable(false)]		public GameObject Parent		{			get { return m_parent; }		}		protected virtual void OnAddToObject(GameObject parent)		{		}		protected virtual void OnAddToWorld(GameWorld world)		{		}		protected virtual void OnRemoveFromObject()		{		}		protected virtual void OnRemoveFromWorld(GameWorld world)		{		}		internal void AddToObject(GameObject parent)		{			Debug.Assert(m_parent == null);			Debug.Assert(parent != null);			OnAddToObject(parent);			m_parent = parent;		}		internal void AddToWorld(GameWorld world)		{			Debug.Assert(world != null);			OnAddToWorld(world);		}		internal void RemoveFromObject()		{			Debug.Assert(m_parent != null);			Debug.Assert(Removable);#if !EDITOR			//Components are removed from the world, then from the object			if(m_parent.World != null)				OnRemoveFromWorld(m_parent.World);#endif			OnRemoveFromObject();			m_parent = null;		}		internal void RemoveFromWorld(GameWorld world)		{			Debug.Assert(world != null);			OnRemoveFromWorld(world);		}		[Category("\t\tGeneral")]		public virtual bool Removable		{			get			{				return true;			}		}		public virtual IGoComponentTemplate GetTemplate()		{			return null;		}		public virtual void Update(TimeSpan elapsedTime)		{		}		public virtual string ToXml()		{			return "";		}	}	public class GameObject	{		private List<GoComponent> m_components = new List<GoComponent>();		[Category("\t\tGeneral"), Browsable(true),		Description("The name of this game object. Useful for linking or debugging.")]		public string Name { get; set; }		[Browsable(false)]		public GameWorld World { get; private set; }		[Browsable(false)]		public virtual bool IsDead { get { return false; } }		public GameObject()			: this("[No name]")		{		}		public GameObject(string name)		{			this.Name = name;		}		public T QueryComponent<T>() where T : GoComponent		{			foreach(GoComponent component in m_components)			{				T value = component as T;				if(value != null)					return value;			}			return null;		}		public IEnumerable<T> QueryComponents<T>() where T : GoComponent		{			foreach(GoComponent component in m_components)			{				T value = component as T;				if(value != null)					yield return value;			}			yield break;		}		public void AddComponent(GoComponent component)		{			component.AddToObject(this);#if !EDITOR			if(World != null)				component.AddToWorld(World);#endif			m_components.Add(component);		}		public void RemoveComponent(GoComponent component)		{			Debug.Assert(component.Removable);			Debug.Assert(m_components.Contains(component));#if !EDITOR			if(World != null)				component.RemoveFromWorld(World);#endif			component.RemoveFromObject();			m_components.Remove(component);		}		[Browsable(false)]		public IEnumerable<GoComponent> Components		{			get { return m_components; }		}		internal void ResetComponents(int reserve)		{			m_components = new List<GoComponent>(reserve);		}		protected virtual void OnAddToWorld(GameWorld world)		{		}		protected virtual void OnRemoveFromWorld()		{		}		internal void AddToWorld(GameWorld world)		{			Debug.Assert(this.World == null);			Debug.Assert(world != null);#if !EDITOR			OnAddToWorld(world);			foreach(GoComponent component in m_components)			{				component.AddToWorld(world);			}#endif			World = world;		}		internal void RemoveFromWorld()		{			Debug.Assert(this.World != null);#if !EDITOR			foreach(GoComponent component in m_components)			{				component.RemoveFromWorld(this.World);			}			OnRemoveFromWorld();#endif			World = null;		}		public virtual void Update(TimeSpan elapsedTime)		{			foreach(GoComponent component in m_components)			{				component.Update(elapsedTime);			}		}		public virtual void Draw(RenderPhase phase)		{			foreach(GoComponent component in m_components)			{				IVisualComponent visual = component as IVisualComponent;				if(visual == null)					continue;				visual.Draw(phase);			}		}		internal virtual string ToXml()		{			string xml = "";			xml += XmlTools.OpenTag("GameObject");      //<GameObject>            xml += XmlTools.WriteValue("name", Name);            xml += XmlTools.OpenTag("Components");			foreach(GoComponent gc in Components)			{				xml += gc.ToXml();			}            xml += XmlTools.CloseTag();			xml += XmlTools.CloseTag();                //</GameObject>			return xml;		}	}

I'm still playing with a lot of the details but hopefully that helps.
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.

This topic is closed to new replies.

Advertisement