Archive for XNA

Resource Pool in F#

Erik Schulz, who has written a bunch of articles on how to make XNA games with F# has ported the Resource Pool class I wrote about in F#. Cool!

type FPool<'a>(newRoutine, capacity : int) =
    let queue = Queue<'a> capacity

    member this.Count = queue.Count

    member this.New() =
        if queue.Count > 0 then queue.Dequeue() else newRoutine()

    member this.Return(item) =
        queue.Enqueue(item)

I’ve been toying around with F# recently, it’s good to see an example that you can easily compare and contrast with the C# version. Has anyone else tried out F#?

Comments

XNA Resource Pool

This is likely an old topic at this point, considering the XNA framework has been out for several years. However, I meant to follow up on the topic of Resource Pooling after I posted the presentation materials from my ONETUG presentation on XNA last February. This is a simple resource pool that you can use to mitigate memory allocation issues in the XNA framework.

The canonical example of where a pool is useful, is a game entity firing bullets.  If you simply create a new instance of a bullet each time you fire, you will soon run out of memory. To avoid allocating new memory each time, you can reuse bullets that have moved off-screen or have collided with something.  There are several implementations that have been posted online such as:

These are great, they definitely do the job.  However, they have a common issue in that they want to take on too much responsibility. In both cases, the resource pool acts as an array to hold all known instances in addition to being concerned with object construction logic.

I wanted a simple resource pool which provided the functionality of providing a “new” instance of an object when I needed one. So I created my own; The basic design is that there are only two methods: “New”, and “Return”.  The new method returns a new instance that is ready to use, while the return method adds a previously obtained object back into the pool.

using System;
using System.Collections.Generic;

namespace Scurvy
{
    public class Pool<T> where T : class, new()
    {
        private Queue<T> queue;
        private Action<T> newRoutine;

        public Pool(int capacity)
        {
            this.queue = new Queue<T>(capacity);
        }

        public Pool()
        {
            this.queue = new Queue<T>();
        }

        public Pool(Action<T> newRoutine)
            : this()
        {
            this.newRoutine = newRoutine;
        }

        public int Count { get { return this.queue.Count; } }

        public T New()
        {
            T item;

            item = queue.Count > 0 ? queue.Dequeue() : new T();
            if (this.newRoutine != null) this.newRoutine(item);

            return item;
        }

        public void Return(T item)
        {
            queue.Enqueue(item);
        }
    }
}

An interesting feature of this pool is that you can control the object initialization logic by providing a simple lambda to the constructor. Any initialization logic (such as resetting “isdead” fields, or resetting positions) can be done there and it will be executed for each new instance.

I’d love to get feedback on this class if you end up using it in a project. Thanks!

Comments (2)

The Next Decade in Software

The scientists are already hard at work at coming up with predictions for the next 10 years. I thought it would be interesting to extract from the list, the predictions that are directly related to software … along with a few recommendations on how to get started today.

  • Augmented Reality
    This one is almost already a reality. A number of iPhone apps use the compass, gps, and camera as a viewport to overlay information on top of the world. A few years ago, Johnny Lee posted some amazing videos on how to use cheap consumer hardware to meld real and virtual worlds. It is clear that 3D graphics programming will be very helpful in this field … why not start learning now?
  • True artificially intelligent computer programs
    This one seems to be the most far fetched. Not because the field is not progressing, because it is, but because it’s been promised for so long. The biggest problem I think is lack of a clear goal; you can say you want something that learns, but learns what? There needs to be a catalyst that makes it clear what people really want/need from an intelligence. In my opinion, the game industry is pushing the state of the art here.
  • Cell phone apps that will act as a health monitor … Sort of an OnStar system for the body
    Since the iPhone proved to everyone that you can have a powerful computer in your pocket, new devices have started appearing that try to piggyback off of the success. I’m looking forward to more people making symbiotic peripherals for phones like the iphone, android based devices, and hopefully WinMo if they ever get their act together.  Mobile programming will surely be a skill to watch in the next decade.
  • Cloud computing
    I was a little surprised to see a reference to cloud computing in a science article. But it makes sense when you think about it, because scientists need to make increasingly complex models to prove their theories and solve problems, they will need more and more processing power to do it.

    I don’t think that it will be worth it for the average “you and me” to invest time into learning how to make cloud computing infrastructures. The big 3 (Microsoft, Google, and Amazon) will commoditize these infrastructures and make them easily available … for a price of course. Learning how to make programs that thrive in the clouds however, will prove to be useful. I’ve written some about this topic recently. You can start programming in functional languages like F#, or learn how to program shaders using HLSL to teach your brain how to think in highly parallelizable terms.

Time is always the ultimate author of history, so we will have to wait and see how many of these predictions turn out to be true.  But one thing is clear, if you learn how to make games, there is a good chance you will be successful in the next decade ;-)

Comments (1)

ONETUG XNA Presentation Files

As promised, here are the presentation files from the ONETUG presentation the other night.

http://codecube.net/bloguploads/ONETUG_XNA_20090129.zip

The .zip contains both the powerpoint slides that I used in the presentation, and the two sample projects I developed during the presentation.

  • TwoD
    • This sample shows some basic 2D techniques for dealing with sprites on the screen.
    • Simple velocity calculations for locomotion (Position += Velocity)
    • Orbiting one sprite around another
    • Launching projectiles at a steady pace.
    • Sprite helper class that makes it easy to position sprites around the world.
    • I didn’t use it in the sample, but I also have a ResourcePool datatype that makes it easy to reuse entities without having to reallocate new memory.  This is actually a really useful technique, I’d like to write about it in a separate blog post.
  • ThreeD
    • First Person Shooter style Camera.  It’s a GameComponent, so you just have to add it to the Components collection to use it.
    • Used the QuadDrawer class from the 3D Audio sample.  I added a few useful overloads and methods to let you draw billboarded sprites and the floor.
    • ModelSprite that makes drawing sprites and positioning it about the world easy.
    • Used the Sky box processor from the Generated Geometry sample.
    • All the helper classes (QuadDrawer, ModelSprite, and Sky) all know the camera, so they can make use of its view and projection matrix.

Thanks to everyone who showed up :-)

Comments

Using the LateBinder

Heh, I seemed to have not realized that I didn’t include any usage information on the LateBinder in the last post.  So here is the how and why you’d want to use this class.

Say you have a need to dynamically get or set the property of some class using the string name of the property.  Normally, the answer would be to use reflection, get the PropertyInfo, extract the MethodInfo of the getter or setter, and then invoke that method using the reflection API.  Hardly very usable … and if you’re not careful, you will end up paying the reflection cost everytime because you have to keep looking up the PropertyInfo and all that.

Enter the LateBinder<T> … using this class, you can do:

MyClass mcInstance = new MyClass();

LateBinder<MyClass> binder = LateBinder<MyClass>.Instance;
binder[mcInstance, "Name"] = “my name”;
string name = (string)binder[mcInstance, "Name"];

The late binder (on windows) uses the System.Reflection.Emit API to generate a DynamicMethod, which is much faster to call than the reflection invoke because it’s pre-compiled using custom built IL instructions.  It also caches them in the late binder instance so that it only has to be compiled once … and furthermore, if you use the singleton .Instance method, you only have to do the compilation once per application run since it keeps the data around in a static variable.

Beneath the hood, the original version of the late binder was using this class.  But I had to change the design of the class to support the cross platform aspect of it and to add in the static support.  It was pretty fun, I ended up using reflector to decompile some sample code I wrote in a console app so I could see what IL instructions I had to use to get/set the statics … so with this version of LateBinder, it supports getting and setting both properties and fields … regardless of whether they are instance or static fields/properties.

Now, on XBox and Zune, the story changes a bit because System.Reflection.Emit does not exist.  So, in this new version I posted, it falls back to simply using reflection.  However, it does keep the propertyinfo in that static cache, so at least you won’t have to pay the penalty of looking for it every time.

So to get back to the original question on usage (ie. when/why would I want to use it) … it probably wouldn’t be a good idea to use this in a tight loop in runtime code.  However, for certain tools and custom serialization code … it could certainly be very useful.  For example, you can relatively easily write code using this that will transfer property values from one class to another … assuming the property names are the same.  The list goes on and on as to how this is useful.

Comments (2)

New LateBinder

A long time ago, I posted a class called LateBinder to this site (the previous blog software).  I went on to use it rather prodigiously at work, and it also turned out to be a boon to others who visited this site (for example, Victor of FlatRedBall fame).  Unfortunately, it did have a few limitations; namely that it didn’t support getting/setting static fields and properties, and it also didn’t work on the xbox360 and zune because the System.Reflection.Emit namespace wasn’t available.

He asked me the other day the feasibility of supporting the static properties, and after a few days of hacking about, I’ve added that, and then some :-)

The version (below) not only supports static fields and properties, but it also supports the xbox360 and zune platforms.  Be warned though, I had to fall back on using simple reflection on the non-windows platforms … so the perf will obviously be slightly slower. 

I am fairly proud of how I was able to refactor the code to encapsulate the cross-platform differences.  If you look at the LateBindFactory abstract class, it uses a factory method to instantiate the platform-specific version.  This way, I was able to keep the pre-processor directives to a minimum, using them only where I needed … and also keeping the same public API for both platforms.

Let me know if this is useful for you  :-)

#region Using Statements

#if !XBOX360 && !ZUNE
#define USE_EMIT
#endif

using System;
using System.Collections.Generic;
using System.Reflection;
#if USE_EMIT
using System.Reflection.Emit;
#endif

#endregion

namespace Scurvy
{
    /// <summary>
    /// Provides a simple interface to late bind a class.
    /// </summary>
    /// <remarks>The first time you attempt to get or set a property, it will dynamically generate the get and/or set
    /// methods and cache them internally.  Subsequent gets uses the dynamic methods without having to query the type’s
    /// meta data.</remarks>
    public sealed class LateBinder<T>
    {
        #region Fields

        private static LateBindFactory factory = LateBindFactory.Create();
        private BindingFlags propertyFlags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static;
        private Type mType;
        private Dictionary<string, GetHandler> mPropertyGet;
        private Dictionary<string, SetHandler> mPropertySet;

        private Dictionary<Type, List<string>> mFields;

        private T mTarget = default(T);

        private static LateBinder<T> _instance;

        #endregion

        #region Properties

        public static LateBinder<T> Instance
        {
            get { return _instance; }
        }

        /// <summary>
        /// The instance that this binder operates on by default
        /// </summary>
        /// <remarks>This can be overridden by the caller explicitly passing a target to the indexer</remarks>
        public T Target
        {
            get { return mTarget; }
            set { mTarget = value; }
        }

        /// <summary>
        /// Gets or Sets the supplied property on the contained <seealso cref=”Instance”/>
        /// </summary>
        /// <exception cref=”InvalidOperationException”>Throws if the contained Instance is null.</exception>
        public object this[string propertyName]
        {
            get
            {
                //ValidateInstance();
                return this[mTarget, propertyName];
            }
            set
            {
                //ValidateInstance();
                this[mTarget, propertyName] = value;
            }
        }

        /// <summary>
        /// Gets or Sets the supplied property on the supplied target
        /// </summary>
        public object this[T target, string propertyName]
        {
            get
            {
                ValidateGetter(ref propertyName);
                return mPropertyGet[propertyName](target);
            }
            set
            {
                ValidateSetter(ref propertyName);
                mPropertySet[propertyName](target, value);
            }
        }

        #endregion

        #region Methods

        #region Constructors

        static LateBinder()
        {
            _instance = new LateBinder<T>();
        }

        public LateBinder(T instance)
            : this()
        {
            mTarget = instance;
        }

        public LateBinder()
        {
            mType = typeof(T);
            mPropertyGet = new Dictionary<string, GetHandler>();
            mPropertySet = new Dictionary<string, SetHandler>();

            mFields = new Dictionary<Type, List<string>>();
        }
        #endregion

        #endregion

        #region Public Accessors

        /// <summary>
        /// Sets the supplied property on the supplied target
        /// </summary>
        /// <typeparam name=”K”>the type of the value</typeparam>
        public void SetProperty<K>(T target, string propertyName, K value)
        {
#if !USE_EMIT

            // find out if this is a property or field
            Type type = typeof(T);

            PropertyInfo propertyInfo = type.GetProperty(propertyName);

            if (propertyInfo != null)
            {
                propertyInfo.SetValue(target, value, null);
            }

            else
            {
                FieldInfo fieldInfo = type.GetField(propertyName);

                if (fieldInfo != null)
                {
                    fieldInfo.SetValue(target, value);
                }
                else
                {
                    throw new ArgumentException(“Cannot find property or field with the name ” + propertyName);
                }

            }

#else
            ValidateSetter(ref propertyName);

            if (mPropertySet.ContainsKey(propertyName))
            {
                mPropertySet[propertyName](target, value);
            }
            else
            {
                // This is probably not a property so see if it is a field.

                FieldInfo fieldInfo = mType.GetField(propertyName);

                if (fieldInfo == null)
                {
                    string errorMessage =
                        “LateBinder could not find a field or property by the name of ” + propertyName +
                        “Check the name of the property to verify if it is correct.”;
                    throw new System.MemberAccessException(errorMessage);
                }
                else
                {
                    object[] args = { value };
                    mType.InvokeMember(propertyName, BindingFlags.SetField, null, target, args);
                }
            }
#endif
        }

        public object GetField(T target, ref string propertyName)
        {
            Binder binder = null;
            object[] args = null;

            return mType.InvokeMember(
               propertyName,
               BindingFlags.GetField,
               binder,
               target,
               args
               );
        }

        /// <summary>
        /// Gets  the supplied property on the supplied target
        /// </summary>
        /// <typeparam name=”K”>The type of the property being returned</typeparam>
        public K GetProperty<K>(T target, ref string propertyName)
        {
            ValidateGetter(ref propertyName);
            return (K)mPropertyGet[propertyName](target);
        }

        public object GetProperty(T target, ref string propertyName)
        {
            ValidateGetter(ref propertyName);
            return mPropertyGet[propertyName](target);
        }

        #endregion

        #region Private Helpers

        private void ValidateInstance()
        {
            if (mTarget == null)
            {
                throw new InvalidOperationException(“Instance property must not be null”);
            }
        }

        private void ValidateSetter(ref string propertyName)
        {
            if (!mPropertySet.ContainsKey(propertyName))
            {
                PropertyInfo propertyInfo = mType.GetProperty(propertyName, this.propertyFlags);

                if (propertyInfo != null)
                {
                    mPropertySet.Add(propertyName, factory.CreateSetHandler(mType, propertyInfo));
                }
            }
        }

        private void ValidateGetter(ref string propertyName)
        {
            if (!mPropertyGet.ContainsKey(propertyName))
            {
                mPropertyGet.Add(propertyName, factory.CreateGetHandler(mType, mType.GetProperty(propertyName)));
            }
        }

        #endregion

        #region Contained Classes

        internal delegate object GetHandler(object source);
        internal delegate void SetHandler(object source, object value);
        internal delegate object InstantiateObjectHandler();

        internal abstract class LateBindFactory
        {
            public LateBindFactory()
            {
            }

            public static LateBindFactory Create()
            {
#if USE_EMIT
                return new DynamicMethodFactory();
#else
                return new ReflectionFactory();
#endif
            }

            public abstract InstantiateObjectHandler CreateInstantiateObjectHandler(Type type);
            public abstract GetHandler CreateGetHandler(Type type, PropertyInfo propertyInfo);
            public abstract GetHandler CreateGetHandler(Type type, FieldInfo fieldInfo);
            public abstract SetHandler CreateSetHandler(Type type, PropertyInfo propertyInfo);
            public abstract SetHandler CreateSetHandler(Type type, FieldInfo fieldInfo);
        }

#if USE_EMIT
        internal sealed class DynamicMethodFactory : LateBindFactory
        {
            public DynamicMethodFactory()
            {
            }

            #region Public Methods

            public override InstantiateObjectHandler CreateInstantiateObjectHandler(Type type)
            {
                ConstructorInfo constructorInfo = type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[0], null);
                if (constructorInfo == null)
                {
                    throw new ApplicationException(string.Format(“The type {0} must declare an empty constructor (the constructor may be private, internal, protected, protected internal, or public).”, type));
                }

                DynamicMethod dynamicMethod = new DynamicMethod(“InstantiateObject”, MethodAttributes.Static | MethodAttributes.Public, CallingConventions.Standard, typeof(object), null, type, true);
                ILGenerator generator = dynamicMethod.GetILGenerator();
                generator.Emit(OpCodes.Newobj, constructorInfo);
                generator.Emit(OpCodes.Ret);
                return (InstantiateObjectHandler)dynamicMethod.CreateDelegate(typeof(InstantiateObjectHandler));
            }

            public override GetHandler CreateGetHandler(Type type, PropertyInfo propertyInfo)
            {
                MethodInfo getMethodInfo = propertyInfo.GetGetMethod(true);

                DynamicMethod dynamicGet = CreateGetDynamicMethod(type);
                ILGenerator getGenerator = dynamicGet.GetILGenerator();

                if (!getMethodInfo.IsStatic)
                {
                    getGenerator.Emit(OpCodes.Ldarg_0);
                }
                getGenerator.Emit(OpCodes.Call, getMethodInfo);
                BoxIfNeeded(getMethodInfo.ReturnType, getGenerator);
                getGenerator.Emit(OpCodes.Ret);

                return (GetHandler)dynamicGet.CreateDelegate(typeof(GetHandler));
            }

            public override GetHandler CreateGetHandler(Type type, FieldInfo fieldInfo)
            {

                DynamicMethod dynamicGet = CreateGetDynamicMethod(type);
                ILGenerator getGenerator = dynamicGet.GetILGenerator();

                if (!fieldInfo.IsStatic)
                {
                    getGenerator.Emit(OpCodes.Ldarg_0);
                }
                getGenerator.Emit(OpCodes.Ldfld, fieldInfo);
                BoxIfNeeded(fieldInfo.FieldType, getGenerator);
                getGenerator.Emit(OpCodes.Ret);

                return (GetHandler)dynamicGet.CreateDelegate(typeof(GetHandler));
            }

            public override SetHandler CreateSetHandler(Type type, PropertyInfo propertyInfo)
            {
                MethodInfo setMethodInfo = propertyInfo.GetSetMethod(true);

                DynamicMethod dynamicSet = CreateSetDynamicMethod(type);
                ILGenerator setGenerator = dynamicSet.GetILGenerator();

                if (!setMethodInfo.IsStatic)
                {
                    setGenerator.Emit(OpCodes.Ldarg_0);
                }
                setGenerator.Emit(OpCodes.Ldarg_1);
                UnboxIfNeeded(setMethodInfo.GetParameters()[0].ParameterType, setGenerator);
                setGenerator.Emit(OpCodes.Call, setMethodInfo);
                setGenerator.Emit(OpCodes.Ret);

                return (SetHandler)dynamicSet.CreateDelegate(typeof(SetHandler));
            }

            public override SetHandler CreateSetHandler(Type type, FieldInfo fieldInfo)
            {
                DynamicMethod dynamicSet = CreateSetDynamicMethod(type);
                ILGenerator setGenerator = dynamicSet.GetILGenerator();

                if (!fieldInfo.IsStatic)
                {
                    setGenerator.Emit(OpCodes.Ldarg_0);
                }
                setGenerator.Emit(OpCodes.Ldarg_1);
                UnboxIfNeeded(fieldInfo.FieldType, setGenerator);

                if (!fieldInfo.IsStatic)
                {
                    setGenerator.Emit(OpCodes.Stfld, fieldInfo);
                }
                else
                {
                    setGenerator.Emit(OpCodes.Stsfld, fieldInfo);
                }

                setGenerator.Emit(OpCodes.Ret);

                return (SetHandler)dynamicSet.CreateDelegate(typeof(SetHandler));
            }

            #endregion

            #region Private Methods

            private static DynamicMethod CreateGetDynamicMethod(Type type)
            {
                return new DynamicMethod(“DynamicGet”, typeof(object), new Type[] { typeof(object) }, type, true);
            }

            // CreateSetDynamicMethod
            private static DynamicMethod CreateSetDynamicMethod(Type type)
            {
                return new DynamicMethod(“DynamicSet”, typeof(void), new Type[] { typeof(object), typeof(object) }, type, true);
            }

            // BoxIfNeeded
            private static void BoxIfNeeded(Type type, ILGenerator generator)
            {
                if (type.IsValueType)
                {
                    generator.Emit(OpCodes.Box, type);
                }
            }

            // UnboxIfNeeded
            private static void UnboxIfNeeded(Type type, ILGenerator generator)
            {
                if (type.IsValueType)
                {
                    generator.Emit(OpCodes.Unbox_Any, type);
                }
            }

            #endregion
        }
#endif

#if !USE_EMIT
        internal sealed class ReflectionFactory : LateBindFactory
        {
            public ReflectionFactory()
            {
            }

            public override InstantiateObjectHandler CreateInstantiateObjectHandler(Type type)
            {
                return delegate()
                {
                    return Activator.CreateInstance(type);
                };
            }

            public override GetHandler CreateGetHandler(Type type, PropertyInfo propertyInfo)
            {
                MethodInfo method = propertyInfo.GetGetMethod(true);

                return delegate(object source)
                {
                    return method.Invoke(method.IsStatic ? null : source, null);
                };
            }

            public override GetHandler CreateGetHandler(Type type, FieldInfo fieldInfo)
            {
                return delegate(object source)
                {
                    return fieldInfo.GetValue(fieldInfo.IsStatic ? null : source);
                };
            }

            public override SetHandler CreateSetHandler(Type type, PropertyInfo propertyInfo)
            {
                MethodInfo method = propertyInfo.GetSetMethod();

                return delegate(object source, object value)
                {
                    method.Invoke(method.IsStatic ? null : source, new object[] { value });
                };
            }

            public override SetHandler CreateSetHandler(Type type, FieldInfo fieldInfo)
            {
                return delegate(object source, object value)
                {
                    fieldInfo.SetValue(fieldInfo.IsStatic ? null : source, value);
                };
            }
        }
#endif
        #endregion
    }
}

Comments

Finite State Machine

Thanks to the wonderful waybackmachine, I was able to dig up an old article of mine from the old blog software that I hadn’t seen for a long time.  Figured I’d post it up for posterity … plus, you never know if a service like archive.org is going to be around forever:

http://web.archive.org/web/20041204125618/http://www.codecube.net/item.asp?cc_ItemID=247

One of these days, I’ll get around to updating this sample to XNA as I can think of a number of ways that I could factor the code a bit better:

———————-

After reading a great article over at ai-junkie.� The article describes the tenets of “state driven agent design” much better than I ever could, but just for reference, here’s a quick rundown.
It is often regarded by many in the ai field that one of the most basic forms of artificial intelligence is using a state based architecture. In the end, it breaks down to being a bunch of if/then/else branches. They can easily be represented as flowcharts and are very easy to understand by most which makes it easy for non-technical people to help with the design of the ai.
I decided I’d like to make an implementation of the sample code he provides in C# (the article presents the code in c++). The sample code is a little miner dude … he gets up in the morning, heads down to the mine to gather gold nuggets. When he gets thirsty, he heads out to the bar and buys a beer. When his pockets are full, he heads to the bank to deposit his gold. When he gets tired, he goes home and sleeps. And eventually, once he deems he has enough gold, he gits outta dodge!
On to the code …

Download Sample Project Files

IState interface

The IState interface is how you implement the actual “intelligence”. The idea is that an entity can only be in one state at any given time, so you can use this interface to dictate what happens when that state is entered, when to leave that state, and where to go.

public interface IState
{
	void Enter(IEntity entity);
	void Execute(IEntity entity);
	void Exit(IEntity entity);
}

Entities

Every entity that uses the state machine must implement the IEntity interface. This simply dictates that the entity must keep track of the current state, the previous state, and provide a mechanism for changing state. For the sake of reusing common code, I also implemented an EntityBase class which is a simple IEntity implementation. You can create your own, or subclass it if you need additional functionality.

public interface IEntity
{
	IState CurrentState {get;set;}
	IState PreviousState {get;set;}
	void ChangeState(IState newState);
}   public class EntityBase : IEntity
{
	private IState mCurrentState;
	private IState mPreviousState;   #region IEntity Members   public IState CurrentState
	{
		get
		{return mCurrentState;}
		set
		{mCurrentState = value;}
	}   public IState PreviousState
	{
		get
		{return mPreviousState;}
		set
		{mPreviousState = value;}
	}   public void ChangeState(IState newState)
	{
		if (CurrentState != null)
			CurrentState.Exit(this);   PreviousState = CurrentState;
		CurrentState = newState;   newState.Enter(this);
	}   #endregion
}

Now, if you go back and read the original article, you’ll notice that his implementation didn’t store the previous state. I added that property because I think it might make the state machine a bit more versatile if your code is able to know what state it was previously in, thus having the ability to change its behavior. Others say that’s bad practice because they think that each state should have predictable behavior, and if you want different behavior, that should be another state. I’m still undecided about whether I agree with that …

Miner

The miner class is going to be the concrete implementation of the IEntity interface. Notice how we define additional properties such as: Fatigue, Thirs, and GoldNuggets. As the state machine puts it through its paces, those properties will change and dictate the when states transition to another state.

public class Miner : EntityBase
{
	public Miner()
	{}   public int Fatigue = 0;
	public int Thirst = 0;
	public int GoldNuggets = 0;
	public int Savings;
}

Concrete State Implementations

For the sake of saving space, I will only print one of the State classes, the first one. download the sample project to see the rest.

	class EnterMineAndDigForNugget : IState
	{
		private EnterMineAndDigForNugget()
		{}

		private static EnterMineAndDigForNugget _instance;
		public static EnterMineAndDigForNugget Instance
		{
			get
			{
				if (_instance == null)
				{
					_instance = new EnterMineAndDigForNugget();
				}
				return _instance;
			}
		}

		#region IState Members

		public void Enter(IEntity entity)
		{
			Console.WriteLine("Entering the mine");
		}

		public void Execute(IEntity entity)
		{
			Miner m = entity as Miner;
			Console.WriteLine("Picked Up a Nugget");
			m.GoldNuggets++;
			m.Thirst++;
			m.Fatigue++;

			if (m.GoldNuggets >= 8) 			{
				m.ChangeState(VisitBankAndDepositGold.Instance);
				return;
			}

			if (m.Fatigue >= 10)
			{
				m.ChangeState(GoHomeAndSleepTilRested.Instance);
				return;
			}

			if (m.Thirst >= 6)
				m.ChangeState(QuenchThirst.Instance);

		}

		public void Exit(IEntity entity)
		{
			Console.WriteLine("Leaving the mine");
		}

	#endregion
}

What will happen is that the app will create a loop and continue to execute the entity’s current state (whatever that state may be). It is up to the state itself to decide when it is time to move to another state. That’s what makes this such a powerful AI technique because you can easily change the state transition patterns and modify the entity’s behavior.

You will also want to notice that the state class is implemented as a singleton. I did this because every time you want to switch states, you need an instance of the state class. The original implementation had me instantiating a new class every time … I can imagine that this would be a performance hit in an actual game … so by using the Singleton pattern, I ensure that there’s only one state class at any given time.

TypeSafe Enum Pattern

I found this pattern about a year ago, and I love it. Here we see it implemented and described by Andy Smith. In retrospect, I could have used this pattern to have a States class with instances of all the individual states. I think this would have looked a little cleaner … but oh well.

Output

This is the generated output from the sample project:

C:\Documents and Settings\jdmartinez\My Documents\testProjects\MinerGame\bin\Deb
ug>MinerGame.exe
Entering the mine
Picked Up a Nugget
Picked Up a Nugget
Picked Up a Nugget
Picked Up a Nugget
Picked Up a Nugget
Picked Up a Nugget
Leaving the mine
Buyin' a beer (-1 gold)! Gulp Gulp Gulp Gulp Gulp Gulp  - Ahhh
Entering the mine
Picked Up a Nugget
Picked Up a Nugget
Picked Up a Nugget
Leaving the mine
Depositing 8 Gold ... I now have 8 gold saved up
Home Sweet Home
ZZZZZZZZ'nother day, 'nother doller
Entering the mine
Picked Up a Nugget
Picked Up a Nugget
Picked Up a Nugget
Leaving the mine
Buyin' a beer (-1 gold)! Gulp Gulp Gulp Gulp Gulp Gulp  - Ahhh
Entering the mine
Picked Up a Nugget
Picked Up a Nugget
Picked Up a Nugget
Picked Up a Nugget
Picked Up a Nugget
Picked Up a Nugget
Leaving the mine
Depositing 8 Gold ... I now have 16 gold saved up
Home Sweet Home
ZZZZZZZZ'nother day, 'nother doller
Entering the mine
Picked Up a Nugget
Leaving the mine
Buyin' a beer (-1 gold)! Gulp Gulp Gulp Gulp Gulp Gulp Gulp  - Ahhh
Entering the mine
Picked Up a Nugget
Picked Up a Nugget
Picked Up a Nugget
Picked Up a Nugget
Picked Up a Nugget
Picked Up a Nugget
Leaving the mine
Buyin' a beer (-1 gold)! Gulp Gulp Gulp Gulp Gulp Gulp  - Ahhh
Entering the mine
Picked Up a Nugget
Picked Up a Nugget
Picked Up a Nugget
Leaving the mine
Depositing 8 Gold ... I now have 24 gold saved up
Home Sweet Home
ZZZZZZZZ'nother day, 'nother doller
Entering the mine
Picked Up a Nugget
Picked Up a Nugget
Picked Up a Nugget
Leaving the mine
Buyin' a beer (-1 gold)! Gulp Gulp Gulp Gulp Gulp Gulp  - Ahhh
Entering the mine
Picked Up a Nugget
Picked Up a Nugget
Picked Up a Nugget
Picked Up a Nugget
Picked Up a Nugget
Picked Up a Nugget
Leaving the mine
Depositing 8 Gold ... I now have 32 gold saved up
YEEEEEHAAWWWWWWW ... headin' back east with 32 gold nuggets

Comments (3)

Installing XNA 3.0 from Scratch

It’s by no means rocket surgery, but I recently cleared out an older laptop so that I can do all my XNA development there instead of taking up my other computer’s hard-drive.  So I figured I’d post the all of the apps that I installed and the install order in case it was useful to anyone else :-)

  1. Microsoft .NET Framework 2.0
  2. Visual Studio 2008 C# Express
  3. XNA Game Studio 3.0 CTP
  4. Paint.NET
  5. XSI Mod Tool

Feels good to “Start over” as it were, without having to have four different versions of visual studio (2k5, 2k5 express, 2k8, 2k8 express) and all the other development crud that goes into “the day job”

Comments

XNA Presentation Source

Apologies for the delay, but I finally got around to packaging up the presentation that I did in my ONETUG presentation in august.  For those who were not in attendance, the entire presentation was written in XNA.  I also ended up using the FlatRedBall engine to handle a lot of the rendering and collision.

I originally didn’t want to make a huge deal about the fact that I was using a third party engine because I wanted the focus of the presentation to be on techniques that you could use with or without an engine instead of specific APIs of that engine.  However, the meeting attendees seemed very receptive and interested in the engine anyways … which is great because FlatRedBall is a really great engine.  I wholeheartedly suggest checking it out because it makes a great many things so much easier.

Another surprise to me was that there was a lot of interest in the code that ran the actual presentation.  After an impromptu run-through of the code at the end of the presentation, I decided to put a few details for those who were interested (along with the download link below).

I had a great time doing the presentation and I wanted to thank all the good comments that came my way from it.  I would definitely be interested in doing another one that dives into some more detail, particularly 3D concepts which seemed to be a recurring request.

DOWNLOAD

http://codecube.net/bloguploads/AugustONETUGXNA.rar

  • Presentation class, handles the main presentation navigation.  Gamepad 1′s left and right bumper provided the "forward" and "backwards" navigation.
  • PresentationScreen class, handles secondary navigation between same-screen indexes.  Also handles the updating of all "IndexActions".  Gamepad 1′s A and B buttons provided the forward/backwards index navigation
  • IndexAction class, provides a simple mechanism to add custom functionality when a screen index is entered or exited.
  • *.scnx files, created using FRB’s SpriteEditor, each main presentation screen has one .scnx file, which itself defines multiple indexes using a naming convention.

Comments (1)

Zune Review

I recently acquired a Zune and I wanted to write about my experiences with it.  Disclaimer: I got the Zune using the "MVP Bucks" that I received from my recent MVP Award.  While I may have gotten this essentially for free, this is not a paid review and reflects only my experiences with the product :-)

Overall, I’d say that I’m fairly happy with the Zune so far … aside from a few nagging issues.

  • Zune Software/Marketplace
    • The same xbox live gamertag/account is used for the Zune along with the same microsoft point system.  This was pretty convenient because I can use the same account settings to add points … and if I add points on the xbox, they are usable for zune content.
    • The social aspect of the zune marketplace is, to me, very compelling.  I really like being able to see what some of my friends are listening to … I’ve already purchased a few songs just because I saw someone else play it.
    • Some of the songs are offered in DRM-free MP3 format.  I hope this is a trend that continues because I would gladly pay for the music … but would definitely like the freedom of taking my purchase with me if I ever decide to stop using the Zune.
    • I love that I can buy a song on the website, and the next time I launch the zune software it will automatically download.  Hopefully Microsoft can take this concept to the XBox.
  • Podcasts
    • This is by far the best part of my zune experience so far.  The sync features is *awesome*.  I can subscribe to a podcast, and then based on the subscription settings in the zune software the podcast will automatically be synched to the zune.  After I listen to it, it will automatically be removed and the next one loaded onto the device.  Awesome!
  • Wireless
    • Social … I know one person that has a zune (which now goes unused due to his recent iPhone purchase).  He brought it in and we swapped a couple of songs over the wireless connection.  Pretty cool I guess.
    • You can sync over the wifi network, would be awesome if I had a desktop, aside from that, meh.  Seemed to kill the battery as well.
  • Bugs
    • All has unfortunately not been rosy in the kingdom of the zune.  I’ve already come across some randomly intermittent 404s when trying to add microsoft points to my account and a few other parts of the zune website.  They cleared up pretty quickly though so it’s not a huge deal.
    • More disturbing though has been the hardware issues.  A week or two back, the zunepad stopped working.  After getting pretty frustrated, some googling revealed that I could wipe the device clean from the zune software, which would reboot it.  This did seem to work and I was able to resync all my content.
    • A few days ago, the play/pause button stopped working all of a sudden.  So far, no combination of rebooting or clearing the content has seemed to bring the functionality back.  I’m probably going to have to call support and see if they can replace it (assuming it’s under warranty, which I imagine it is)

So overall, I’ve got a fairly positive feeling on the zune (assuming my hardware issues can be resolved) … am excited to see what Microsoft’s next plans are for the platform, especially as it relates to XNA!

Comments (2)