It’s been a while since I posted something new. That’s due to the fact that I’ve been working on a small game. My intent was to design and build a fully-functional game to demonstrate AJAX, C# and SVG. The trick to completing something like this is to make sure the scope is small enough that it can be completed in a short time. I chose a turn-based game to keep the code simple. This game is a basic Axis-vs-Allies type board game using a hex board layout. I chose the hex layout to make the a game a bit more challenging and the hex board has 6 directions instead of 4 primary and 4 diagonals.
I named the game “Battlefield One.” Not overly creative, just a temporary name. Here’s the basic design document:
Battlefield One
Feel free to download and thumb through the details. There’s mention of two types of units in the game, but I trimmed it down to just infantry. No tanks at this time. That’s easy to add though, since there is an object called “Unit” that I used to contain the defense, offense, movement, etc. This object can easily be expanded to represent other units.
Follow this link to play the game:
Battlefield One Game
Here’s a screenshot of part of the game board:
The first task I performed was rendering the playing board. There are a lot of decisions that can be made here, but I chose to render the beehive grid with lines on top of a background picture. The trick was getting the picture to line up. So I wrote some SVG code to paint one hexagon and repeated a grid of these shapes. As I’ve mentioned in a previous post, this board is really no more than an offset checkerboard, where every other column is offset by 1/2 the height of the previous cell. Once I had a grid printed on the screen I had to make sure my browser was set to 100% (yup, I forgot that step and had to redo this next step). Next I took a snapshot of the entire screen and put it inside Photoshop. You can use any paint program you like, I’m comfortable with Photoshop and this problem just screamed “layers!” to me. After I put the screenshot on a layer in Photoshop, I filled in the green areas for all the cells except the four cities. I made up an easy pattern of city building roofs and roads and then I just copied to all 4 city locations. Then I put my background into the SVG code before rendering the beehive cells.
That pretty much completed the background picture. In future versions of this game, I hope to add roads and make the movement factor double when a unit uses a road. But for now, it’s just a green field.
Next I defined a unit and worked out the rendering portion. For units, the center icon is just a PNG file that I created. The unit type will define which PNG file will be rendered in the center of the unit box. The four corners are numbers representing the defense, offense, movement and fire range. The top center number is a number that I added for troubleshooting purposes. I left it in for now. It represents the unique unit number. This was a snafu that I ran into when I was debugging a deleted unit problem.
The unit objects are grouped into a list:
private List<Unit> AllUnits = new List<Unit>();
The only issue with using a list is that deleting a unit causes the list to compress and the indexes to each item is now changed (at least for units after the deleted unit). So I inserted a variable in the Unit class called “Number” which represents the unique unit number:
public class Unit
{
public int Number { get; private set; }
public int Defense { get; set; }
public int Offense { get; private set; }
public int Movement { get; private set; }
public int Range { get; private set; }
public int UnitType { get; private set; }
public int X { get; set; }
public int Y { get; set; }
public NATIONALITY Nationality { get; private set; }
public UNITCOMMAND Command { get; set; } // used by enemy units only
public int DestX; // used by enemy units only
public int DestY; // used by enemy units only
}
I created a couple enum’s for NATIONALITY and UNITCOMMAND. There’s nothing fancy going on here, it’s just my way of keeping track of what is set. It also helps in the “if” statements to see what is being compared. The enums are as follows:
public enum NATIONALITY { Allied, German };
public enum UNITCOMMAND { None, Wait, Destination, Defend };
At the moment, I’m only using the “None” and “Destination” status of the UNITCOMMAND variable. I initialize the Unit class to a Command of “None” and then I change the command to “Destination” once I have set a unit DestX and DestY for enemy units.
The Game AI
I managed to crank out enough C# and JavaScript to allow the allied units to move around the map board. The computer player was still dead (i.e. not moving or attacking). I decided to work on the enemy move phase of the game. I kept the game AI as simple as possible. Basically, the enemy will count the total number of units, divide by 4 (which is the number of cities on this map), then set the destination for each group to a different city.
That was all I setup initially. I didn’t bother with attacking or detecting any end game results. The movement of units included a method to force move restrictions on the desired movement (I called this the SnapTo method). This method will make sure the unit only travels one unit from its current location, it can’t overlap another unit and they can’t go off the edges of the map.
There was a problem that I ran into. My algorithm computed which units would move and did the SnapTo operation inside the C# code, then sent it back through an AJAX return to the calling JavaScript that performed the actual move. The problem is that the order that the units are moved can determine if there is another unit in the square that will be moved to. So I decided to just send the data to the JavaScript in no particular order, then I looped through a queue of move orders. If the unit was blocked, I swapped that unit to the back of the queue and then continued moving other units. After a few attempts to move a unit and passing it over, eventually the space it was destined to move into will be empty (vacated by another unit just moved).
Next, I did the enemy attack phase. I decided that if the enemy bumped into an allied unit, it would just attack during the attack phase. So I wrote a method to search for allied units that are one hex away from a German unit, then send both unit numbers and the battle result back to the JavaScript from the calling AJAX.
Last, I completed the code for the allied attack phase. The JavaScript that triggers this sends and AJAX command to the C# code which does the battle calculation, sending back the results. The return JavaScript function deletes the unit object from the SVG code.
Game Goals
There are 2 possible goals that can be achieved to win or lose the game. The first goal is to capture all 4 cities. The German or Allied side needs to capture all 4 to win the game. If either side has only 3 units or less, then that goal is not achievable. The second goal is to destroy all the enemy units (or the enemy must destroy all the allied units). When one team or the other destroys the other’s units, the game is won.
The game can become a draw due to the fact that the enemy AI splits groups of units for each city. Once the group of units reaches the destination city, they just sit there waiting for something to happen. Unfortunately, it doesn’t do the enemy much good to have 3 or 4 units sitting on one city while the allied player sits on another city with one remaining unit. The enemy will not seek out and destroy the allied unit. This is a weakness that I’ll be fixing next.
Game Code
I’m going to spend some time and refactor the code to clean up all the scraps I left on the floor of the sausage factory. Once I do that, I’ll post the code for anybody to download and examine. Though I haven’t completely tested this on an iPad, I have done some preliminary testing and it works pretty good. The total amount of code for this game is about 860 lines of JavaScript and 730 lines of C# code. Just a little something I do on a weekend.
Update 6/12/2013:
I performed a few bug fixes while refactoring the code. Now that I have been able to play the game several times in a row without a hiccup, I feel confident that it’s pretty close to bug free.
Update 6/13/2013:
Here’s the entire project for download: BattleField One Project.