Archive for February 2012

Speech Bubble Sample

So I allowed myself to get sidetracked to throw together a sample to answer a question in the App Hub forums. Since I love RPG games, both playing and developing, this will probably be useful to me sometime in the future so that’s how I’m justifying it.

The sample, which you can get from here, shows a quick semi-dynamic speech bubble with a couple of options. The class is less than 150 lines, allows however many lines of text you want, shows a graphic to let the user know if there’s more text that the character has to provide, and shows a pointer to the character that can be placed on either the left or right side of the bottom of the bubble. It uses more of my fantastic programmer art, but should work with whatever graphics you replace it with, assuming you don’t deviate from how I’ve set up the graphics. I could have used just one corner graphic and rotated for the other 3 sides, but I was lazy. Smile

Here’s the class in all its glory:

public enum PointerType

public class SpeechBubble
    private int _width;

    private Vector2 _location;

    private string[] _text;

    private SpriteFont _font;

    //bubble textures
    private Texture2D _bottomBorder;
    private Texture2D _interior;
    private Texture2D _leftBorder;
    private Texture2D _leftBottomCorner;
    private Texture2D _leftTopCorner;
    private Texture2D _rightBorder;
    private Texture2D _rightBottomCorner;
    private Texture2D _rightTopCorner;
    private Texture2D _topBorder;

    private bool _more;
    private Texture2D _moreGraphic;

    private PointerType _pointerType;
    private Texture2D _pointer;

    public SpeechBubble(ContentManager content, int width, Vector2 location, string[] text, bool more = false, PointerType pointerType = PointerType.None)
        _font = content.Load<SpriteFont>("font");

        _bottomBorder = content.Load<Texture2D>("bottomBorder");
        _interior = content.Load<Texture2D>("interior");
        _leftBorder = content.Load<Texture2D>("leftBorder");
        _leftBottomCorner = content.Load<Texture2D>("leftBottomCorner");
        _leftTopCorner = content.Load<Texture2D>("leftTopCorner");
        _rightBorder = content.Load<Texture2D>("rightBorder");
        _rightBottomCorner = content.Load<Texture2D>("rightBottomCorner");
        _rightTopCorner = content.Load<Texture2D>("rightTopCorner");
        _topBorder = content.Load<Texture2D>("topBorder");

        _moreGraphic = content.Load<Texture2D>("more");

        _pointer = content.Load<Texture2D>("pointer");

        _location = location;
        _width = width;

        _text = text;

        _more = more;

        _pointerType = pointerType;

    public void Draw(SpriteBatch sb)
        sb.Draw(_leftTopCorner, _location, Color.White);
        sb.Draw(_topBorder, new Rectangle((int)_location.X + _leftTopCorner.Width, (int)_location.Y, _width - _leftTopCorner.Width * 2, _leftTopCorner.Height), Color.White);
        sb.Draw(_rightTopCorner, _location + new Vector2(_width - _rightTopCorner.Width, 0), Color.White);

        for (int i = 0; i < _text.Length + (_more ? 1 : 0); i++)
            sb.Draw(_leftBorder, new Vector2(_location.X, _location.Y + _leftTopCorner.Height + (i * _leftBorder.Height)), Color.White);
            sb.Draw(_interior, new Rectangle((int)_location.X + _leftBorder.Width,
                                    (int)_location.Y + _leftTopCorner.Height + (i * _leftBorder.Height),
                                    _width - _leftBorder.Width * 2,
            sb.Draw(_rightBorder, new Vector2(_location.X + _width - _rightBorder.Width, _location.Y + _leftTopCorner.Height + (i * _leftBorder.Height)), Color.White);

            //leave space for more graphic if necessary
            if (i < _text.Length)
                sb.DrawString(_font, _text[i], new Vector2((int)_location.X + _leftBorder.Width, (int)_location.Y + _leftTopCorner.Height + (i * _leftBorder.Height)), Color.Black);

        sb.Draw(_leftBottomCorner, _location + new Vector2(0, _leftTopCorner.Height + (_text.Length + (_more ? 1 : 0)) * _leftBorder.Height), Color.White);

            case PointerType.Left:
                sb.Draw(_pointer, _location + new Vector2(_leftBottomCorner.Width, _leftTopCorner.Height + (_text.Length + (_more ? 1 : 0)) * _leftBorder.Height), Color.White);

                sb.Draw(_bottomBorder, new Rectangle((int)_location.X + _leftBorder.Width + _pointer.Width, 
                                                        (int)_location.Y + _leftTopCorner.Height + (_text.Length + (_more ? 1 : 0)) * _leftBorder.Height, 
                                                        _width - _leftBorder.Width - _pointer.Width - _rightBorder.Width, 

            case PointerType.Right:
                sb.Draw(_bottomBorder, new Rectangle((int)_location.X + _leftBorder.Width,
                                                    (int)_location.Y + _leftTopCorner.Height + (_text.Length + (_more ? 1 : 0)) * _leftBorder.Height, 
                                                    _width - _leftBorder.Width - _pointer.Width - _rightBorder.Width, 

                sb.Draw(_pointer, _location + new Vector2(_width - _pointer.Width - _rightBorder.Width, _leftTopCorner.Height + (_text.Length + (_more ? 1 : 0)) * _leftBorder.Height), Color.White);

            case PointerType.None:
                sb.Draw(_bottomBorder, new Rectangle((int)_location.X + _leftBorder.Width,
                                                    (int)_location.Y + _leftTopCorner.Height + (_text.Length + (_more ? 1 : 0)) * _leftBorder.Height,
                                                    _width - _leftBorder.Width - _rightBorder.Width, 


        sb.Draw(_rightBottomCorner, _location +  new Vector2(_width - _rightBottomCorner.Width, _leftTopCorner.Height + (_text.Length + (_more ? 1 : 0)) * _leftBorder.Height), Color.White);

        if (_more)
            sb.Draw(_moreGraphic, new Vector2(_location.X + _width - _rightBorder.Width - _moreGraphic.Width, _location.Y + _leftTopCorner.Height + (_text.Length * _leftBorder.Height)), Color.White);


Creating an instance is fairly straightforward:

SpeechBubble _bubble1;
SpeechBubble _bubble2;
SpeechBubble _bubble3;

protected override void LoadContent()

      _bubble1 = new SpeechBubble(Content, 150, new Vector2(50, 50), new string[] { "This is a test", "This is only a test", "More text follows..." }, true);
      _bubble2 = new SpeechBubble(Content, 150, new Vector2(250, 250), new string[] { "This is a test", "This is only a test", "Nothing here" },false, PointerType.Left);
      _bubble3 = new SpeechBubble(Content, 150, new Vector2(150, 450), new string[] { "Another test", "Still testing", "More follows..." }, true, PointerType.Right);

Simply call the Draw method of the class in your own draw code:

protected override void Draw(GameTime gameTime)



Feel free to let me know if I missed something that would be useful in the class.

Adding Triggers to the Platformer Starter Kit

I’ve seen a lot of posts where people are using the Platformer Starter Kit and as I was reading one, I thought having the ability to have triggers in a level might be something someone would find useful.

Triggers give the level designer the ability to make levels more challenging and diverse, instead of simply having the player run around collecting gems and power-ups in a wide open level. The added dimension of a goal that may have to be reached before exiting the level makes the game more challenging, which leads to the game possibly being more interesting to play.

The first use that I thought of for a trigger was to remove a block( s ) that impedes reaching the exit. Should be simple enough, right? Let’s find out.

I started out by figuring that two kinds of triggers might be good to have – visible and invisible. Even though triggers aren’t tiles, the level designer needs to see them in the level data, which means the code that reads the text files that hold the level data have to account for them. “T” and “I” are what I selected for the two trigger types.

In the Level.cs file’s LoadTile method, add the following to the end of the switch statement before the “default” case:

// visible trigger
case 'T':
   return new Tile(null, TileCollision.Passable);

//invisible trigger
case 'I':
   return new Tile(null, TileCollision.Passable);


For the visible trigger, the player will have to have something to see, which means we’ll need a sprite. Behold, the awesome programmer art!


I placed the file in the Sprites folder in the Content project.

The sprite doesn’t look exactly like this (at least not as I’m typing this). You can open the file in the attached source linked to at the bottom of this post to see it. The important thing is to ensure that whatever you use is sized correctly (I just opened the gem.png file and had at it) and has a transparent background.

The sprite needs an object to load it into and we’ll need something to hold one or more triggers in the level, so add the following at the top of the Level.cs file’s Level class:

private List<Trigger> triggers = new List<Trigger>();
private Texture2D triggerTexture;


The Trigger class looks like this:

public enum TileTriggerType

public class Trigger
    public Vector2 Location;
    public bool IsTriggerVisible = true;
    public Vector2 TriggerTarget = Vector2.Zero;
    public TileTriggerType TriggerType = TileTriggerType.None;
    public bool IsActive = true;

Since the text file that holds the level data is fairly set in stone as far as it’s content, we’ll use separate files to hold the data for a trigger. I decided on something fairly straightforward as far as format:


The pipe character separates the pieces of data. The first piece is the location of the trigger, the second the type of trigger, the third, the location of the tile that the trigger acts upon, the last whether or not the trigger is visible.

The following code reads the trigger file for the current level:

//load level triggers data
    using (Stream stream = TitleContainer.OpenStream("Content/triggers/" + levelIndex.ToString() + ".txt"))
        using (StreamReader sr = new StreamReader(stream))
            string line = sr.ReadLine();

            while (line != null)
                Trigger trigger = new Trigger();

                string[] data = line.Split('|');

                Vector2 vec = new Vector2(Convert.ToInt16(data[0].Substring(0, data[0].IndexOf(','))), Convert.ToInt16(data[0].Substring(data[0].IndexOf(',') + 1)));
                trigger.Location = vec;
                trigger.TriggerType = (TileTriggerType)Convert.ToInt16(data[1]);
                vec = new Vector2(Convert.ToInt16(data[2].Substring(0, data[2].IndexOf(','))), Convert.ToInt16(data[2].Substring(data[2].IndexOf(',') + 1)));
                trigger.TriggerTarget = vec;
                trigger.IsTriggerVisible = data[3] == "1" ? true : false;


                line = sr.ReadLine();
catch (Exception ex)
    //do nothing

triggerTexture = Content.Load<Texture2D>("Sprites/trigger");


The last piece of the puzzle is to handle the player hitting the trigger. Add the following to the Update method of the Level class after the UpdateEnemies(gameTime) line:

//check for hitting trigger
if (Player.IsAlive && Player.IsOnGround)
    foreach(Trigger trigger in triggers)
            //offset to center of trigger texture
            if (Player.BoundingRectangle.Contains((int)trigger.Location.X * Tile.Width + Tile.Width / 2, (int)trigger.Location.Y * Tile.Height + Tile.Height / 2))
                trigger.IsActive = false;
                switch (trigger.TriggerType)
                    case TileTriggerType.MoveTile:

                    case TileTriggerType.RemoveTile:
                        tiles[(int)trigger.TriggerTarget.X, (int)trigger.TriggerTarget.Y] = new Tile(null, TileCollision.Passable);



I’ve only handled the RemoveTile trigger type. I’m leaving the MoveTile as an exercise for the reader (that’s my story and I’m sticking to it!).

I modified the first level to add a wall blocking the exit and set the trigger near it so the player can see the tile being removed:


Save everything and give it a try. Assuming I didn’t miss anything you should be able to hit the trigger and see the top block in the wall disappear, enabling you to reach the exit. If I did miss something please let me know. In that case you can download the source from here and give it a try.

Other possible triggers that I could see being useful:

  • Moving blocks to enable the player to reach areas not accessible otherwise
  • Moving blocks to crush enemies (this would be a pretty big modification)
  • Moving blocks to prevent enemies from reaching and area and allowing the player to safely move through that area
  • Moving blocks to allow access to power-ups
    One thing that currently isn’t handled by this code is the ability to have a trigger modify multiple tiles. This isn’t a big enhancement. Simply change the TriggerTarget member of the Trigger class to a List<Vector2>, change the code to read the trigger file to handle one or more pieces of data (possibly by making the target data the last piece of data read) and changing the code in the Level class Update method to loop through this List.
    There are a lot of areas of level design that are opened up by a pretty simple modification to the game code. I’d love to see what people can come up with.
    If anyone can think of other small enhancements to the kit, let me know.

Modifying Platformer Starter Kit–Adding Health

So there was another post on the AppHub forums where someone was asking about how to add health to the character in the Platformer Starter Kit rather than having him die immediately when touching an enemy. I’d cobbled together a bunch of mods that had previously been done and thought this might make another good one.

Implementing this turned out to be pretty simple. Just two files need updating, Level.cs and Player.cs and I added two sprites – a health bar and a 1×1 pixel texture to fill in the healthbar.



(magnified may times Open-mouthed smile)


First, the changes to the Player.cs file. At the top where all the members are declared add:

private int health = 100;
//private int lives = 3;
private int lives = 1;
private bool touchingEnemy;

public bool TouchingEnemy
    get { return touchingEnemy; }
    set { touchingEnemy = value; }

public int Health
    get { return health; }


Notice, the old “lives” member has been commented out and replaced. The player now only has one life, but can be injured a number of times before dying (which we’ll see in a second).

Previously, when the player was touched by an enemy the OnKilled method was called. We need to add a new method (I put it right under the OnKilled method):

public void OnInjured()
    touchingEnemy = true;

    health -= 10;

    if (health == 0)
        isAlive = false;


Now we’ll add the textures necessary to render the health bar and the members of the level class to load the textures into.

You can either save the textures above by right-clicking on them, create your own, or grab them out of the zip file attached to this post. Drop them into the “sprites” folder in the content project (or wherever you want, but you’ll have to change the relevant code that loads them).

Add the following code to the Level.cs file’s section where the other members are declared:

private Texture2D healthBar;
private Vector2 healthBarLoc;
private Texture2D healthTexture;


Then add the following to the Level.cs constructor:

//load healthbar textures
healthBar = Content.Load<Texture2D>("sprites/healthbar");
healthTexture = Content.Load<Texture2D>("sprites/health");
healthBarLoc = new Vector2(Width * Tile.Width - 205, 5);


The Width member of the Level class returns the width of the screen measure in number of tiles, so we have to do a little multiplication and offset from the edges of the screen a bit.

Now add the matching method to injure the player that we had in the Player class (again, I added this right below the OnKilled method):

private void OnPlayerInjured()


And we’ll call it in the UpdateEnemies method:

private void UpdateEnemies(GameTime gameTime)
    foreach (Enemy enemy in enemies)

        // Touching an enemy now just injures the player
        if (enemy.BoundingRectangle.Intersects(Player.BoundingRectangle))
            if (!player.TouchingEnemy)

private void UpdatePlayerCollision(bool touchingEnemy)
    player.TouchingEnemy = touchingEnemy;


That should be it. Save everything and run the game. You should see the health bar change every time you touch an enemy. You’ll have to advance to the second level to see one. After ten touches the character should die and you’ll be presented with a dialog. I haven’t changed the dialog or relevant code to restart the game, nor did I remove the sprite rendering the number of lives the player has. I wanted to keep the latter in so that the option to add a life power-up can be done without breaking the game. The former is something for you to implement. Smile

Hopefully someone will find this useful.


Source code can be downloaded from here.

Is Crowd Funding the Future of Game Development?

With Double Fine’s recently fully-funded (and then some) Kickstarter project leading the way (yes, I know there have been many other game development projects on Kickstarter, but none with the PR that this has received), we may start seeing a new way of doing game development, which would be a significant shift in the industry. This could eliminate publishers and allow studios to self-publish on any digital distribution system they want, Steam being the primary one of course.

The big question for me is, could this type of funding allow cancelled projects to be revived and, if so, would studios be able to do it, or allowed to do it depending on IP ownership. There are any number of cancelled projects that I’d love to see this happen for:

Instead of hiring additional personnel, studios could outsource the work to quality smaller studios or indie teams. This would allow these studios to continue to function while building a reputation for themselves. Of course, big name IP shouldn’t be the first games released this way until it’s proven that teams are capable of doing a quality job.

This could be a huge step in the evolution of game development and I hope to see more studios following Double Fine’s lead. I certainly would like to get some of my game ideas out there in the crowd funding arena. It could be the start of going full-time game dev.

When will the next evolutionary step in MMOs come?

I was hoping for Star Wars: The Old Republic to be the next step in the evolution of MMOs. Imagine my disappointment after playing for a couple dozen hours to discover that it’s basically WoW reskinned. Sad smile Sure, it’s got some things that are different and it’s cool to play as a Jedi, but at it’s core there’s nothing really new here. Certainly nothing that I’m going to pay every month for when there are tons of great games sitting on my shelves from the past two Christmases waiting to be played.

I keep asking myself why hasn’t a company taken the MMO genre to the next level? Are they afraid of the risk? That’s a good possibility. Publishers aren’t going to fund a game that deviates too far from what’s sold in the past. But anything with the Star Wars label slapped on it usually sells (how many people are going to waste their money watching 3Dified versions of the Star Wars movies? You’re not going to find me doing so). So why didn’t Bioware and Lucas Arts make it the game it should have been instead of just playing it safe? Would it have cost too much? Perhaps, but according to what info I could find it’s already sold over 2M copies so I think it’s safe to say that it’s going to be making a good bit of money despite what it cost to develop. Surely they could have taken a bit more time up front to make it WoW++.

Tech is at a point, both hardware and software, where it seems that truly dynamic worlds are possible. Why should gamers be satisfied with areas where mobs respawn every couple of minutes. Talk about immersion breaking! Why should gamers be satisfied with assembly-line quests? How is it realistic that I can deliver the same letter to someone that thousands of others players have already delivered or rescue an NPC that’s been rescued already? Why is grinding still necessary to keep players player a game and thus giving the publisher more money? (A side question is why do players keep finding grinding fun and are willing to spend money to do so?)

So what would it take to move MMOs to the next level? A couple things off the top of my head:

1) A total redesign of the quest system – no more Fed-Ex or “Kill [x] [mob type]”. The “Rescue [NPC]” quest might still be valid, but only for the first person to complete it. After that anyone else that’s on the quest would have it removed from their quest log and it would never be available again (unless the NPC wandered off and was captured again). What’s that you say? “That’s not fair?” Who said it had to be fair? Why does every player (or class of players depending on the MMO) have to have the same quests available to them? “Because that’s the way it’s always been!” < smack > Stop thinking like that. We’re talking new and improved here.

What’s that leave us with then? Some of it depends on the MMO and what kinds of things can be done in the game world. Which ties in to the next thing:

2) A world that’s as alive as can be made. This would require a lot of work. Any NPC should be able to be killed. Period. If it’s important that an NPC stay alive, that NPC should be sufficiently protected, just like you would expect. This means that serious penalties should exist for random killing of people, just like you would expect.

Factions and reputation exist in most MMOs to some degree, but this reputation has to extend to areas around where an act a player commits warrants that reputation change. If a player kills an NPC and is seen or it’s discovered that the player was responsible, authorities in the surrounding areas should be made aware and kill/attempt to capture the player on sight. The penalties for being captured would have to be seriously examined, again depending on the game world of the MMO. Death penalty, confiscation of assets, incarceration (not being able to play for a period of time – yes I said that!), etc. are all possibilities.

A more alive world would feed back into the quest system as things happened. Quests would be dynamically created for certain events. What kind of things? Let’s consider:

  • An NPC puts out a hit on another NPC for some reason
  • A player could offer a reward for rescuing their wife/husband/child that’s been kidnapped or captured by an enemy
  • An NPC wants to put a competitor out of business by having the player rough him up or destroy his business establishment
  • The Thieves Guild offers the player (who belongs to the Guild of course) an opportunity to steal something
  • An NPC hires the player to build or make him something (necessitating a good crafting system of course)
  • A king hires players as part of his army or a squad to wage war against a rival king.

The possibilities are virtually limitless, depending on the effort the devs want to put into making the world as alive as possible.

2a) Part of this more alive world would have to be a real economy system, which means the loot system has to be completely overhauled. I’ve never understood how I could loot a huge sword off a dead animal or even a giant insect. What were the devs thinking?!?

2b) Money would have to be earned mainly through quests or crafting if the player wants to buy better equipment or other things like a house/land, if that’s an option. For a game I’m thinking about, the former would be provided and I’m not sure if the latter makes sense.

2c) Politics and intrigue could make the game more interesting. We’ve seen MMOs with different races combating one another before, but this could still be taken a step further. Assassinations, kidnappings, rescue attempts, espionage, full-on wars, etc. could all involve the players and lead to rewards, notoriety and fame, or even elevate the player to a position of influence in the world.

3) Players wouldn’t be able to cart around tons of loot, unless they were carrying bags of holding. If said bags of holding were so commonplace that every character could buy on, there’s a problem however. For non-fantasy/comic book world settings, this wouldn’t be a possibility anyway. Useful loot from creatures would be relatively rare, unless the creature itself is rare or parts of it can be used somehow (potions, spell components, etc.).

4) This would mean killing things just to gain experience would be revamped as it wouldn’t be as necessary nor mean as much. Yes, a player’s skill with weapons might increase from killing things, but this would be limited and caps would have to be put on how far a character’s skill can increase through repetition of the same activity.

5) Magic, combat, and skills are all usually fairly well done in MMOs for my taste, but I’d like to see magic at least affect the world more. Spells that cause plagues or result in famine across the land, massive spells of construction or destruction, etc. would make things a lot more interesting if a player was able to cast them.

Of course, this would be at max level capabilities, which mean not a lot of players should be able to reach that level. It should be more difficult than it is to max out your level. Players shouldn’t be able to power-level for a couple hours and reach it, nor should they be able to chew through content quickly.

Obviously a lot of this is going to alienate a lot of players, but hopefully a company would think it’s more important to advance the genre than just produce another WoW clone and suck as many players as possibly from other MMOs. The question is, what company is going to step up to the plate and take a swing? Hopefully someone will make the attempt soon. The genre can’t keep going as it has, at least not if they want me to play.

The Perils of Coding on the Fly

So I thought I could get the “character” editor for my game (you know, the only one I’m working on like a good developer! See the relevant “squirrel” post previously) up and running quickly. There’s not a lot of options to select from in creating a “character” in the game, so I figured it would be a quick screen to whip up. I should have known better. Sad smile

Usually, if a chunk of code isn’t that complicated I don’t take the time to make it object-oriented. Why do we use OOP methodologies anyway? For me it comes down to a couple of things:

  • Ease of understanding
  • Ease of re-use
  • Ease of maintenance
  • Piecing chunks of code together is usually easier than writing one huge chunk of code (this ties in to the other three somewhat)

For small, uncomplicated screens in a game (which I anticipated this being) usually none of these 4 things are lost if you code the screen in a non-OO manner. Menu screens in most games are a good example. There’s not much going on except detecting the selection of a menu item and moving to the next screen. An option screen isn’t that much harder – you just have to read and write out some data to a file to save the state of the options the player selects.

I wrongly believed the editor screen wouldn’t be much more difficult than a typical options screen. That’s come back to bite me.

The problem is mainly due to handling navigation between all the graphical elements on the screen that the player can select and drawing those elements with the option for each the player has selected. I’ve ended up with a bunch of variables for each object that obviously would be better suited to bundling up in a class and just having a list of each class object. I did this with the in-game level editor and it made it a lot easier. I don’t know why I figured I wouldn’t need it here. Oh, that’s right, I know why – I didn’t plan the screen out before I started coding. Embarrassed smile

Luckily ripping everything out and making it more OO shouldn’t be much more than a good night’s coding. I am thinking a bit beforehand about how I’ll do it though.

Lesson learned. Hopefully others will benefit from my mistake.

Game Update and Other Stuff

Well, I didn’t quite get to where I wanted by the end of the month, but at least I made progress. The level editor is mostly done, although not fully tested. The “character” editor is probably 50% done. The plan is to get it completed for the next Dream Build Play, which I think is quite doable.

The squirrel did attack (see my previous post) and I opened up The Agency project when I realized the tileset I was using wasn’t going to work for all situations. I also took another look at Hero Engine to see how easy it was to work with. There’s a cute little bunny farming world that they set up to show how some things are done (quests, menus, area picking, etc.). I would need to read a lot more of the documentation to find out if it’s a truly viable solution for a spy game like I’ve been fooling around with, especially since it would be just me working on it at the moment.

A huge (to me at least) thing that’s happened since my last post is that I’m waiting for a phone interview to be set up with an actual game studio. I keep an eye out every once in a while for positions at various companies just to see how the industry is going and I happened to see positions for which I’m actually qualified! That’s extremely rare since I don’t do C++ anymore. I sent in my resume for a couple of positions and got a reply back from one. I’m hoping to hear back from the other as well but we’ll see. This would be life changing in that I’d have to move, but given my current job instability I’d have to seriously consider uprooting the family if they make me an offer that’s enough to support us, especially since it’s the opportunity of a lifetime. At least I’d have the hope of some potential for growth there. I’m slowly digging myself into a hole at my current job as we’re nowhere near current with technology.

I was excited to see that the local chapter of the IGDA is starting back up with a meeting Thursday. If you’re in the Baltimore area, come out and join in – 7 p.m. at The Green Turtle in Hunt Valley. There’s a ton of talent in the area and past meetings have been pretty awesome so I’m hoping for good stuff this year.