Posts Tagged ‘C#’

Ear Bleeding Java Generics

May 18, 2011

In my previous post, I blather on about my adjustment to Java from C#.

Now that I’ve had a little while, I’ve been adjusting a bit better.

I am realizing that a simplistic “port” is not what I am doing.

I am doing a “translation”.

I do not let curly braces fool me.

Just because both are present in C# and Java does not mean that I can express the same concepts in the same way.

Sometimes I cannot even express a concept in a similar way.

I started with my C# classes that deal with boards and mazes.

In C#, these are highly genericized.

So, I set out to write them in Java in a highly genericized manner.

Doing this was a mistake.

Why?

Three reasons.

One, I think my original solution may have been a bit on the “clever” side. The one true thing about all clever code is that it will come back to bite you later. I use generic types for the contents of a board cell, the contents of a maze cell (which is actually a subclass of board cell), the contents of a portal between maze cells. Relying on the language feature in C# that enables me to instantiate these classes, I used them mercilessly. In Java I needed to switch over to interfaces and factory classes, because the templates started to get really confusing.

Two, there was a significant design flaw in my C# code. This is common with organically grown code like this. I have a number of static (read “global”) objects for dealing with things like the item and creature lists. Recently, I decided that this was not the best way to go about things.  I also don’t have one large “game” object, which I normally do in cases like these, to contain all of the subordinate game objects and state. I decided to restructure so that the static classes were no longer static, and that the various tables would be put together into a single tableset, and this tableset object would be given to the various other classes that need them.

When translating to Java, I noticed that things would be a lot easier if everything knew what its parent was, and could talk up and down the hierarchy. There should be the big Game object, which is the parent of the tableset and the maze (which is the chief other object in the game), and so I attempted to do this with typed generics in Java, with a nifty interface (also generic) that allows specification of a type of parent. I was going along quite well until I got to a class that would need five template parameters, at which point I decided to ditch generics entirely, and use interfaces and the “Object” class for the parent.

Don’t get me wrong. I’m fine with generics, but my limit is type parameters. After that, my ears start to bleed.

Extension Methods. I Like Them.

May 4, 2011

Yes, I’m about three years late to this party, but so it goes.

The tool used to write HamQuest is Microsoft Visual Web Developer 2010 Express.

It has been since I moved to this tool last year.

Originally HamQuest was a WinForms application in Microsoft Visual C# 2005 Express, later moved to 2008, then switched to Silvelight, and finally moved into 2010.

Which means that much of the HamQuest codebase is the 2005 flavor of C#, and while certain areas of the codebase have had to morph as it migrated from one tool to another, most notably the change from XmlNodes to XElements in the move to Silverlight, a lot of code remained in the older style.

Now, a lot has changed in HamQuest itself.

For instance, the representation of the items, creatures, and terrain moved from hard coded arrays into xml configuration files, and in fact became very sophisticated with the user of reflection as time went on.

Unfortunately, the added flexibility of XML made for some painfully awful constructs in order to get information as simple as hitpoints.

For example:

CreatureTable.GetCreatureDescriptor(CreatureIdentifier).GetProperty<IStatisticHolder>(GameConstants.Properties.Health).Value

For context, CreatureTable is a static class, with a static member function GetCreatureDescriptor, which naturally retrieves a descriptor for a creature based on the string CreatureIdentifier.  From there, I use the generic method GetProperty to retrieve the GameConstants.Properties.Health(a const string containing “health”) into a type called IStatisticHolder, from which I can finally retrieve the value.

Ugly and long.

However, it would be so much nicer to do:

CreatureTable.GetCreatureDescriptor(CreatureIdentifier).GetHealth()

The problem is that the Descriptor class doesn’t know anything about the properties it holds. It just loads them from an XML file.

In fact, I don’t actually WANT the Descriptor class to know anything about the properties it holds, because the same Descriptor class is used for Creatures, Terrain, and Items.

And this is where extension methods come in.

I have a class called DescriptorExtenders (a static class), and to it I add the following static function:

        public static int GetHealth(this Descriptor theDescriptor)
{
if(theDescriptor==null) return 0;
IStatisticHolder holder = theDescriptor.GetProperty<IStatisticHolder>(GameConstants.Properties.Health);
if (holder == null) return 0;
return holder.Value;
}

And blammo. I have my nifty GetHealth function, which I can use elsewhere in the code.

In addition, my extension method can do things like check for null, and return “safe” values if I want.

Some of the properties got really strange, especially for things like the Health example above.

The reason is that an enemy creature on the map needed to look the same as the player avatar.

Configuration Files Run Amok!

July 26, 2010

“Amok” is one of those strange words, but I’ll save that for another time.

HamQuest has 74 different items, which sounds like a lot if you’ve ever played the game, but really it isn’t, once you consider what an “item” in HamQuest really is.

An item is an object in which the player can interact.  It is not a creature, which moves around and can attack you, it is not terrain, which is there no matter what.

The list of items breaks down into the following groups:

  • Doors: 24.
  • Keys: 7.
  • Weapons: 5.
  • Consumables: 3.
  • Armors: 5.
  • Treasures: 11.
  • Chests: 1.
  • Hiddens: 3.
  • Traps: 3.
  • Amulet: 1.
  • Tools: 1.
  • Megaham: 1.
  • Exit: 1.
  • Portal: 1.
  • Light Sources: 3.
  • Shoppes: 4.

Really this isn’t so much, as the various doors exist because there is one for each direction and one for each color, making fully a third of the items.

Also, treasures are really much the same, just giving differing amounts of gold, and so can be considered different subitems of the same item.

Which brought me to the point I found myself: managing a huge xml file with item descriptors, each with numerous xml tags.

At first, this wasn’t so bad, but as the list of items grew, it became more and more difficult to manage.  If I added a new property, I had to add it 74 different places in the file.  It was easy to lose track of what I did or didn’t do.

So I decided to split these off into their own files, and have the items.xml file point to the files they were in, like so:

<item file=”config/items/weapons/dagger.xml”/>
<item file=”config/items/weapons/shortsword.xml”/>
<item file=”config/items/weapons/longsword.xml”/>
<item file=”config/items/weapons/twohandedsword.xml”/>

And this was pretty neat.  I could now more easily manage the items.  Yes, it means that I now need to manage more files, but this is still a good idea.

Then I noticed in similar items that there is a lot of duplication in items that are similar.

I had already made it possible to do direct inheritance, because I recursed provided that the file=”” attribute in the file I loaded was there.

And I planned on using it, except that the first items in the list are the doors.

There are some properties shared by all doors: they don’t show up in inventory; they aren’t randomly placed in rooms; you can’t find one in a chest; and so on.

There are some properties shared by doors going east: they are all placed in a certain location.

There are some properties shared by all red doors: they are unlocked by red keys; they have the same messages when bumped into or opened.

So I decided to make it possible to inherit from multiple files, like so:

<item file=”config/items/doors/templates/all.xml,config/items/doors/templates/east.xml,config/items/doors/templates/red.xml,config/items/doors/red/east.xml”/>
<item file=”config/items/doors/templates/all.xml,config/items/doors/templates/north.xml,config/items/doors/templates/red.xml,config/items/doors/red/north.xml”/>
<item file=”config/items/doors/templates/all.xml,config/items/doors/templates/south.xml,config/items/doors/templates/red.xml,config/items/doors/red/south.xml”/>
<item file=”config/items/doors/templates/all.xml,config/items/doors/templates/west.xml,config/items/doors/templates/red.xml,config/items/doors/red/west.xml”/>

The order can be important.  If a later loaded file has the same property, it replaces the original.

In this way, I have implemented prototype based multiple inheritance.

HamQuest’s Road To Silverlight

February 9, 2010

After moving JetLag over to Silverlight, I figured I’d get started on HamQuest.  It was well positioned to do so, due to the humongous refactor I did a while back to split out the game and rendering logic.

From the looks of things, the rendering part is going to be the easy bit in Silverlight, as HQ is really nothing more than a big bunch of stacked bitmap tiles that get swapped out. Silverlight is well suited for the type of rendering I am doing… way better than the .NET WinForms stuff using a PictureBox.

One part that wasn’t quite as smooth as I’d have liked it to be was the configuration files (creatures.xml, items.xml, and terrains.xml). I had originally used the XmlDocument/XmlNode set of classes to go through them. Silverlight doesn’t much care for that, and instead uses XDocument and XNode, which has a just different enough syntax to make a person crazy.

And another challenging part were the map files (they have a file extension of .cqm, and they are binary files I have used for very simple map structures since my Cybiko days. CQM stands for “CyQuest Map”, for the vaporware CyQuest, which would have been a lot like HamQuest, so the file format is a fitting homage).  In the WinForms client, I just open a filestream. In Silverlight, they are resources, and I had to determine the correct way to open them, which took a while to research.

Now the configuration files and map files load. The maze generates. We’ll see how well things start to get drawing.

Pathfinding At Last!

February 3, 2010

I probably mentioned before (or maybe I didn’t) that the monster AI in HamQuest was rather simplistic.  It was essentially the following:

1. Flip a coin

2. If it lands on heads, move the creature randomly

3. If it lands on tails:

3a. If creature y > player y, move north, and done

3b. If creature y < player y, move south, and done.

3c. If creature x < player x, move east, and done.

3d. If creature x > player x, move west, and done.

Naturally, while this gets the monsters generally towards the player over time, it mostly just made the monsters line up, and it was easy to manipulate their movement, especially because they could not move through items.

So, I implemented a very simply A* based system that allows the monsters to look at the “how far away am I ” value of its neighboring cells, and move to the one with the lowest value.

And I tried it out, and the monsters swarmed the player, quickly overwhelming and killing him.

So I put the random factor into the movement again, but made it a different chance of random movement for the various monsters. Goblins and thieves move more randomly, whereas the undead move dead on for the player.  The summoner and necromancer move the most randomly, as their job is to throw monsters at the player.

I also haven’t won a game in a really long time, and I have NEVER managed to kill a dragon.

The “THING” class

March 16, 2008

As stated previously, I am porting a version of Rogue from 1984 originally written in C for DOS into C#.

Many things wind up easy to port.  Most #defines wind up as const or readonly fields.  Everything winds up a static field or method of a single Program class.

However, the THING “class” was the strangest bit to port thus far.

THING represents either a monster or an item.

It is a union.

Each of the two substructs in the union contain pointers to other THING variables.

So, its a linked list *AND* a union.

Now, I’m attempting to do a “faithful” port, which means it is my goal to get as close to the original as possible (within reason), so I’ve got a kind of ugly re-representation of THING in my code.  It works, anyway.

When porting old code like this, I don’t typically question these things too heavily.  I have to rely on the good faith of the developer twenty four years ago.  He had a perfectly good reason for choosing a union.  I just don’t see what it was.

Rogue Port

March 15, 2008

So what if I don’t have focus?

Along side other things, I am doing a port of Rogue into C#.  In particular, I’m doing a port of the Epyx version 1.48 for DOS.

The method of porting is very similar to the method I use to port old BASIC games into C#.  First, I move all of the code into C# file with every line commented.  Then I go and slowly replace the commented lines with equivalent C# code.

Rogue, however, is rather unlike the BASIC games I have ported.  In BASIC, there was typically only a single listing/file to port.  Rogue has dozens of C files.

So I decided to abuse the “partial class” feature of C#.  Each of the C files went into a CS file with the same name.  There is a namespace around the code, and the code exists within “partial class Program”.  Yes, I have a Program class that spans nearly 40 files.

I can hear the C# people cringe.

But it just goes to show… a language like C# doesn’t force anybody into object oriented programming.

Space Trader for XNA is GO!

March 12, 2008

Space Trader is a game for Palm, and it is my desire to port it to XNA.

Of course, it has periodically been my desire to port it to the Yahoo! Widget Engine, JavaScript, and plain C#. I have taken up the project a number of times, and failed at it. I’ve got lots of stray code to show for it.

The original was written in C, and is heavily forms based (as one might expect for a Palm app). Fortunately, all of the resources for the UI, strings, alerts, bitmaps, etc were recoverable using the PalmOne tools (they extract them into a nice XML file).

It is also GPL, which means I don’t even need to talk to the author to do this port. And I haven’t.

There is already a C# port for windows, but it has some differences in it that I don’t like, including the “put all of the screens on one window” thing that I don’t care for.

The screens are all 160×160, which really can’t give too much information at a time. Currently, I’m working on it in 800×600.

One of the first things I did was to make a utility app to scan in the resource xml files. I did this mainly for the large number of string and alert resources. The forms I just have to duplicate by hand, since they need to grow in size anyway.

Which brings me to control issues. The Palm version used (duh) the stylus, for which the windows equivalent would be the mouse. However, in XNA the target controller should be the 360 controller and the keyboard (the two controllers that both windows and the 360 support) but more importantly, everything should be doable from a game pad. It’ll be interesting to see what I can come up with for equivalent controls.

Diamond Maze

March 2, 2008

diamondmaze_ss_200803020917.png

Well, there’s not much to it yet, but the maze is present, and the player can move about the maze.  There is nothing for him to do yet, however.

Some differences from the original version include a different screen resolution (800×600 instead of the original 640×480).  I did not change the actual number of ascii cells, which remains 40×30, it just scales the sprites to the 20×20 from the 16×16 in the bitmap.

However, the area left for the minimap has changed this time.  Originally, this area was 128×128, and it is now 160×160.  Since the minimap consists of individual pixels, and I don’t want to be scaling something like that, I’m going to  change the size of the entire map to 160×160.

Originally, the individual “rooms” of the maze were 16×16, and there was a grid of 8×8 of them.  This leaves me with a decision to make.  Stay with the 16×16 rooms and change the number of them to 100?  Or, stick with 64 rooms and make them 20×20?  Or, go with a totally different room size completely.

After that, I have a few other decisions to make.  The original game had 4 differently colored doors, and the differently colored keys to go with them.  Do I leave it at 4, or change it?  The four potions: invincibility, freeze, health, and wealth.  Keep as is or add/remove/modify the list?

In any case, the end result should be interesting, and recognizably  the same game as the original, so it really doesn’t matter what is decided as long as it keeps the game fun.

Maze Generation Code and Diamond Maze

March 1, 2008

The following is the current iteration of the maze generation algorithm I’m using.  Currently, I am working on a remake of Diamond Maze with XNA.

Yes, it will be using the same ASCII style graphics as it did originally.  This is more of a “ramp up on how I’m going to do stuff in XNA” than anything else.

A colleague of mine once referred to Diamond Maze as a roguelike, which I had never really thought of it as, but I guess the term does accurately describe the game.  I usually associate a way more elaborate combat system and inventory system than what I used in DM.

This code is my implementation of Pim’s algorithm.  It isn’t terribly useful without the associated classes, but I just wanted to share it.

public void Generate(int randomSeed)
{
Random random = new Random(randomSeed);
Clear();
List<MazeCell> frontier = new List<MazeCell>();
MazeCell cell = GetCell(random.Next(Width), random.Next(Height));
cell.Frontier = false;
int direction;
for (direction = MazeDirections.First; direction <= MazeDirections.Last; ++direction)
{
if (cell.Neighbors[direction] != null && cell.Neighbors[direction].Frontier)
{
frontier.Add(cell.Neighbors[direction]);
}
}
while (frontier.Count > 0)
{
cell = frontier[random.Next(frontier.Count)];
frontier.Remove(cell);
cell.Frontier = false;
do
{
direction = random.Next(MazeDirections.Count);
}while(cell.Neighbors[direction]==null || cell.Neighbors[direction].Frontier);
cell.Portals[direction].Open = true;
for (direction = MazeDirections.First; direction <= MazeDirections.Last; ++direction)
{
if (cell.Neighbors[direction] != null && cell.Neighbors[direction].Frontier && !frontier.Contains(cell.Neighbors[direction]))
{
frontier.Add(cell.Neighbors[direction]);
}
}
}
}