Showing posts with label XNA. Show all posts
Showing posts with label XNA. Show all posts

Friday, August 9, 2013

Preparing for AI

Another programming excursion... can you tell I've been doing a lot of that lately? I've been reading up on AI programming  ("Artificial Intelligence", just in case anyone's not familiar with the abbreviation). Technically, it's "weak" AI I'm looking at now, but I'd love to include some strong AI elements in Spacer... Think about it: a game that actively learns how the gamer plays and adapts accordingly.  Sounds awesome to me

This is totally NOT what I'm creating... *shifty eyes*
But I digress,

For my purposes, preparing a game to handle an AI boils down to the old dilemma of whether to use inheritance or composition for game objects.  For now, the only objects in the game  that have any kind of self-control are Ships.  I'm not going into all the details on how the Ship class is setup, but I'd like them to be pooled objects.  Before I started messing with the bulk of the solution discussed below, the only ship present was an instance of a derived class; PlayerShip.  This worked fine for debugging up to this point, but here's why I no longer like using a derived class to exert control over an object:
  1. Using instances of both the base class and its derived class (or instances of two different derived classes) screws up the existing object pooling.  If you have 2 ships in your pool, the first is a PlayerShip and the second is an BotShip, you're gonna need to either re-instantiate when you need a new object (which defeats the whole purpose of object pooling), do a lot of fancy casting to make it work (which is just a headache), or re-design ObjectPools entirely to store and fetch multiple types of objects within the same pool (which, let's face it, is too much work)
  2. The game shouldn't care whether it's updating a PlayerShip or a BotShip!  You don't want a human player or an AI player treated any different when calling the Update method, for instance.  If you do, it's very easy to give abilities to one or the other, or force yourself to repeat logic to prevent that from happening.  If a ship needs to move 200 meters starboard, it doesn't matter who issued the order (Captain Picard or the Borg queen), the game logic should move the ship the same way.
So, how to we address the issue instead? Ask yourself this: what do both ships have or own (as opposed to are or are not)? They both have a Controlling Entity! Not to get too philosophical, but here "Entity" is taken to mean "An independent, decision-making thing". (super technical. I know, right?). But both a human player or an AI decision tree meet this definition! The Entity class just contains a set of basic properties that the ship looks at during it's update phase:

abstract class Entity
{
 // Ship's Input variables:
 protected Vector2 desiredFocalDirection; // The direction the pilot wants the ship to face
 protected Vector2 desiredEngineFireDirection; // The direction the helmsman wants the ship to move
 protected bool activatePrimaryEquipment; // Should you attempt to activate any onboard equipment?
 // Other properties omitted... you get the idea.

 #region Public Properties

 public Vector2 DesiredFocalDirection { get { return desiredFocalDirection; } }
 public Vector2 DesiredEngineFireDirection { get { return desiredEngineFireDirection; } }
 public bool ActivatePrimaryEquipment { get { return activatePrimaryEquipment; } }

 #endregion

 public Entity(){ }

 public abstract void LoadContent(ContentManager content); // Load any resources derived entities need (ex: screen output information for the player to make decisions, or an AI personality)
 public abstract void UnloadContent(); // Clean up!
 public abstract void Update(GameTime gameTime) // Update your ShipInputVariables!

 public virtual void Initialize(Ship givenShip)
 {
  shipControlled = givenShip;
  shipControlled.SetControllingEntity(this);
 }
}

These Entities are maintained by something outside the physics or gameplay calculations, and the "Ship's Input Variables" are set in derived classes: PlayerEntity and BotEntity. In PlayerEntity, they are set by the controller/keyboard input, and in BotEntity: by the AI logic.  Now, we just have to give each ship an Entity (via a SetControllingEntity method), from which it reads it's input variables during it's Update phase. To help clarify, have a much-simplified UML diagram:



So that's it, composition wins out over inheritance... this time.  What's even better? We have a clean separation of responsibility! LocalSpace handles all the physics engine calculations and collision detection, the PlayerEntity handles translating input device states into intention, and the BotEntity handles translating AI decision-making into intention.  Heck, throw an EntityManagement class in there storing a collection (or ObjectPool, anyone?) of Entities to manage adding/removing players: when a player leaves, swap his ship's ControllingEntity with a BotEntity (that's been learning his gameplay style... again, I'm not creating SkyNet), and the action can continue when your friend gets called home for dinner! Feeling like making things more awesome? Create a new class derived from Entity: SquadronEntity, that contains a list of BotEntities, and can override decisions made by the individual bots for a coordinated battle strategy!

... this is how the Technological Singularity will come about, isn't it?...


Wednesday, July 31, 2013

Object Pooling: Resource Recycling!

Alright, so we're 2-for-2 regarding posts about Spacer; I guess I've made quite a lot of progress on it lately. The concept of object pooling isn't new to programming, but it's new to me.  As an added bonus, this concept is very useful to programming things other than just video games; I could easily see it being used for particle physics or computational chemistry simulations (or, I suppose hundreds of business-type applications).  Therefore, that will be the topic of this post.  Object pooling is essentially digital recycling.

I guess Randall Munroe's stick figure comics are influencing me.  Also the fact that this comment is in the alt text.


The basic idea is to avoid constantly creating and destroying objects, which is very processor-expensive when you're dealing with potentially hundreds of complex objects. To accomplish this, we create a bunch of "empty" instances of the class we need, activate them as needed, and deactivate them for reuse when we're done. That is, instead of "new-ing up" a bullet every time an in-game gun fires, turn to your "bullet pool" and activate the next inactive bullet.

There are a couple keys to making object pooling work:

  1. All objects being pooled should have an empty constructor
  2. The pooled objects should all have some "initialize" or "activate" method
  3. Be sure to clean up the object after you are done using it... you don't want any residual properties left over from the previous usage. 
Without further adieu, here's the code sample for my generic pooling:
class ObjectPool<t> where T : IPoolableObject
{
 #region Private Fields

 private List<t> activeItems;
 private Queue<t> inactiveItems;
 private int resizeAmount;

 #endregion

 #region Public Properties

 public T this[int index] { get { return this.activeItems[index]; } }
 public int Count { get { return activeItems.Count; } }
 public List<t> InactiveObjects { get { return inactiveItems.ToList(); } }

 #endregion

 public ObjectPool(int Capacity, int ResizeAmount = 1)
 {
  if (Capacity < 1)
   throw new ArgumentOutOfRangeException("The capacity must be 1 or greater");
  if (ResizeAmount < 1)
   throw new ArgumentOutOfRangeException("The resize amount must be 1 or greater");

  activeItems = new List<t>();
  inactiveItems = new Queue<t>();
  resizeAmount = ResizeAmount;

  //Fill up the inactive items list
  System.Reflection.ConstructorInfo constructor = typeof(T).GetConstructor(new Type[0]);
  for (int i = 0; i < Capacity; i++)
  {
   inactiveItems.Enqueue((T)constructor.Invoke((object[])null));
  }
 }

 public T ActivateItem(string ObjectModelName, Vector2 StartingPosition, float StartingOrientation, Vector2? StartingVelocity = null, float StartingAngularVelocity = 0)
 {
  if (inactiveItems.Count == 0) //enlarge the queue if we've run out of objects! 
  {
   System.Reflection.ConstructorInfo constructor = typeof(T).GetConstructor(new Type[0]);
   for (int i = 0; i < resizeAmount; i++)
   {
    inactiveItems.Enqueue((T)constructor.Invoke((object[])null));
   }
  }

  T newItem = inactiveItems.Dequeue();
  activeItems.Add(newItem);
  newItem.ActivateObject(ObjectModelName, StartingPosition, StartingOrientation, StartingVelocity, StartingAngularVelocity);
  return newItem;
 }

 public void DeactivateItem(T item)
 {
item.DeactivateObject();
inactiveItems.Enqueue(item);
  activeItems.Remove(item);
 }

 // The stuff below just makes the ObjectPool fancy, allowing you to call a "foreach" loop on the pool or simply get a list of all the active objects:
 public IEnumerator<t> GetEnumerator()
 {
  return (IEnumerator<t>)this.activeItems.GetEnumerator();
 }

 public List<t> ToList()
 {
  return activeItems;
 }
}

IPoolableObject, here is a really simple interface inherited by your pooled objects. It's everything that's needed for a "new" bullet and everything it needs to clean up after itself (dirty object..).  The ObjectModelName is used as a lookup value for both a pre-loaded texture and the statistics library entry (ex: health, speed, armor, ect..., remember? See the previous post if you don't). StartingPosition, StartingOrientation, StartingVelocity, and StartingAngularVelocity are all relavent quantities for the physics engine.  As for cleanup, everything of relevance gets overwritten during the ActivateObject call, so there really isn't anything to the DeactivateObject method.  Your objects don't have to have these parameters (or lack-there-of), I'm just throwing them out there as an example.

interface IPoolableObject
{
 void ActivateObject(string ObjectModelName, Vector2 StartingPosition, float StartingOrientation, Vector2? StartingVelocity = null, float StartingAngularVelocity = 0);
void DeactivateObject();
}

Also, the bit about the "ResizeAmount" isn't really necessary. I just wanted something to fall back on if the initial capacity guess was too small and isn't the app barfing by throwing a "queue empty" exception.  You could just have the pool return null; make sure your code knows how to interpret a null object, though.

As for how it's implemented in the larger game, it's super effective!

// Create and construct the pool:
public ObjectPool<bullet> BulletPool;
BulletPool = new ObjectPool<bullet>(100);

// Activate a new bullet:
Bullet newBullet = bulletPool.ActivateItem(BulletTypeFired, StartingLocation, StartingOrientation, StartingVelocity);

// Insert a bunch of code about how your app uses the newBullet

// and finally, deactivate it when you are finished:
BulletPool.DeactivateItem(newBullet);

So there you have it.  I'd like to give some credit to a couple other sources that I kinda picked and chose my favorite parts from: Jason Mitchell, Thomas Aylesworth, and the XNA Wiki: Generic Resource Pool.

Thursday, July 18, 2013

Keeping track of object stats: A database-like layer to video games

First post, woo-hoo!
I love video games; so much so that I'm going to start things off with a video game I've been working on (and is still very much in development).  It's a top-down 2D RPG/Adventure where the player pilots a customized ship, written in C#/XNA, and this will probably not be the last time you read about "Spacer" on this blog...  The quandary conquered stems from setting up something that's considered good programming practice: layers. Maybe it's already a known solution, but I couldn't find much when I was researching it...

I don't really see much of this in scientific applications, but in a lot of business-type applications, there are often three layers: database, logic, and view.  I'm going to focus on the separation of the database and logic layers.

In my initial commit to the game, every object had it's own hard-coded statistics associated to it.  For instance, the WeaponSystem class looked something like this:

class WeaponSystem : Equipment {
bool canFire;
double rateOfFire;
float energyPerShot;
int numOfShots, numOfShotsMax;
TimeSpan timer;

public WeaponSystem() {
//arbitrary values:
rateOfFire = 0.25; //in seconds
energyPerShot = 10f;
energyReserve = 100f;
numOfShotsMax = 50;
equipmentName = "Weapons";

//calculated quantities:
energyReserveMax = numOfShotsMax * energyPerShot;
numOfShots = (int)(energyReserve / energyPerShot);
timer = TimeSpan.Zero;
}

//There is more code about how the WeaponSystem works, but not important here
}

(hey, don't judge. Guns are important to a space adventurer... Jayne agrees, see?)

This would mean creating a class for every type of weapon system: lasers, missiles, torpedoes, etc... Bleck! The logic of the game shouldn't depend on the specific values you give to your objects, and honestly, shouldn't care what the values are so long as they are valid values!

Since hard-coding values is bad, the idea was to create a sort of "Stats Library;" a single place to store all these values to look up as needed. This really just meant separating the "arbitrary values" in the above code to it's own serializable class, and dumping it's corresponding XML file(s) into the content project. For organization's sake, all these "StatsLibrary objects"  were put into a separate VS project (this project comprises the data layer, the original game project is the logic layer).  The separation turned out something like this:
public class WeaponSystemStats
{
public string Name { get; set; }
public string BulletTypeFired { get; set; }
public double CoolDownTime { get; set; }
public float EnergyPerShot { get; set; }
int MaximumNumberOfShotsStored { get; set; }
}

<?xml version="1.0" encoding="utf-8" ?>
<XnaContent>
<Asset Type="Spacer.StatsLibrary.WeaponSystemStats">
<Name>TestGun</Name>
<BulletTypeFired>TestLaser</BulletTypeFired>
<CoolDownTime>0.25</CoolDownTime>
<EnergyPerShot>10.0</EnergyPerShot>
<MaximumNumberOfShotsStored>50</MaximumNumberOfShotsStored>
</Asset>
</XnaContent>

(keep in mind, this advancement didn't happen over sequential commits, the WeaponSystem class evolved a bit.  For instance "RateOfFire" turned into "CoolDownTime", also note the "BulletTypeFired" string: this same idea was applied to the projectiles fired from the WeaponSystem)

Now, we have a nice way to store data, a "database layer," if you will. Rather than each object storing it's own statistics, all it has to know is what kind of object it is (use a unique string, enum, or whatever other identifying method you want; in this example, it happens to be the "Name" property), everything else can just be looked up from a single source! Originally, this single-source was just a Dictionary object, which works fine for getting things to work, but why stop there?

Being completely OCD, the content project was already organized into folders of XML documents for each game object, why not load everything at once? Create a generic StatisticsLibrary object:
class StatisticLibrary<t> where T : IStatsLibraryEntry //This is just an interface with a single property: Name
{
Dictionary<string, T> library;

public void LoadLibrary(ContentManager Content, string contentFolder)
{
library = new Dictionary<string, T>();

DirectoryInfo di = new DirectoryInfo(Content.RootDirectory + "\\" + contentFolder);
if (!di.Exists)
throw new DirectoryNotFoundException();

FileInfo[] files = di.GetFiles("*.*");
foreach (FileInfo file in files)
{
string extensionlessFile = Path.GetFileNameWithoutExtension(file.Name);
T value = Content.Load<t>(contentFolder + "\\" + extensionlessFile);
string key = value.Name;

library.Add(key, value);
}
}

public T GetStatistic(string Name)
{
return library[Name];
}
}

Now, we can use a static object of each game object to lookup whatever data we need, where ever we need it! Just use the static object to access it from the logic layer. (Theoretically, you can access our new statistics library from the view layer, but it's generally regarded as bad coding practice; only allow a layer to access an adjacent layer). Now, you don't have to load everything in the specified content sub-folder, I just do because Spacer is still in pretty early development stages, and I don't have enough content to notice a difference in performance, but if you've got a lot of complex content, selectively loading material would be worth considering.

So there you have a basic database layer for a game:

  •  Create a serializable model for each game object (you can use inheritance to greatly simplify these!) that is separate from your logic that updates the object
  • Make as many XML (or JSON, or binary,...) docs as you want for object data
  • Populate and access via a static library object