Random Maze Experiment

Where we left off

Not too long ago I decided to see what it would take to generate a random maze like those found in the Intellivision game Minotaur. It turned out to be a bit easier than I expected so I decided to crack open the code and add some random objects to the map. What good is a maze without some weapons, armor, and enemies anyway?


Object model

The first thing to figure out is what type of objects can we have in this maze. Here's what I came up with:

Objects

Oh, this would be a good time to mention that instead of the D&D theme I'm going with a space theme. Yeah, yeah real original and all that. So the weapons, armor, enemies, healing items, and eventually the player have separate life and cyber meters. If they both go to zero there's trouble. Simple enough.

Also simple enough is turning these into small classes that basically function like structs. I would have used structs but the whole inheritance thing is kinda handy:

public class RoomObject

{

  public int image; //eventually will be used to store a pointer to the image

  public int level; //how powerful the object is

  public RoomObject(int image,int level) 

  { 

    this.image=image; this.level=level; 

  }

  public RoomObject Clone() 

  { 

    return(new RoomObject(this.image,this.level)); 

  }

}

public class EquipableItem : RoomObject

{

  public int bioPower;

  public int cyberPower;

  public EquipableItem(int image,int level,int bioPower,int cyberPower) : base(image,level)

  { 

    this.bioPower=bioPower; 

    this.cyberPower=cyberPower; 

  }

  public new EquipableItem Clone() 

  { 

    return(new EquipableItem(this.image,this.level,this.bioPower,this.cyberPower)); 

  }

}

public class Armor:EquipableItem

{

  public int equipWhere;

  public Armor(int image,int level,int bioPower,int cyberPower,int equipWhere) : base(image,level,bioPower,cyberPower) 

  { 

    this.equipWhere=equipWhere; 

  }

  public new Armor Clone() 

  { 

    return(new Armor(this.image,this.level,this.bioPower,this.cyberPower,this.equipWhere)); 

  }

}

[... and so on ...]


Game data

The next thing to do is to load up all the possible weapons, armor, enemies, items, and whatever that can appear in the game. What we're going to do is create some arrays that contain 15 objects ordered from weakest to strongest. If we have a maze with 12 levels, the mix of things that can appear will range from [current_level-1]-[current_level+3]. So on level 1 we'd have random weapons, armor, enemies, and items from the [0]-[3] range in the array, on level 12 anything from [11]-[14] could appear. Not sure how close that is to the original game but it seems like a good place to start. Creating all these arrays looks something like:

Weapon[] weapons=new Weapon[15];

Armor[] armor=new Armor[15];

Enemy[] enemies=new Enemy[15];

UsableItem[] usableItems=new UsableItem[15];

Container[] containers=new Container[15];

[...]

//weapons

weapons[0]=new Weapon(ImagePointers.Weapon.LaserPistol,1,2,2,int.MaxValue,ImagePointers.WeaponAnimation.LaserPistol);

weapons[1]=new Weapon(ImagePointers.Weapon.ThrowingShiv,1,5,1,1,ImagePointers.WeaponAnimation.ThrowingShiv);

weapons[2]=new Weapon(ImagePointers.Weapon.Flamethrower,1,4,3,int.MaxValue,ImagePointers.WeaponAnimation.LaserRifle);

weapons[3]=new Weapon(ImagePointers.Weapon.LaserRifle,1,3,4,int.MaxValue,ImagePointers.WeaponAnimation.LaserRifle);

weapons[4]=new Weapon(ImagePointers.Weapon.PulseBomb,1,1,5,1,ImagePointers.WeaponAnimation.PulseBomb);

[... and so on for level 2 and 3 weapons ...]

armor[0]=new Armor(ImagePointers.Armor.Gloves,1,1,1,0);

armor[1]=new Armor(ImagePointers.Armor.Boots,1,1,1,1);

armor[2]=new Armor(ImagePointers.Armor.Helmet,1,1,1,2);

[... and so on for all the remaining game data ...]


Scattering the objects

Now we need to randomly select from these arrays and scatter them across the map. The first point of order is adding the ladder to the next level. Maybe it should be an elevator instead, whatever. Let's make sure it's not right next to an entrance while we're at it:

//find a place for the ladder

int randX=rand.Next(2,10);

int randY=rand.Next(2,10);

rooms[randX,randY].roomObject=new Decoration(ImagePointers.Decoration.Ladder,1);

Now it's time to add all the other stuff. We're going to clone the objects from the game data arrays because at some point when we add combat we don't want to accidentally override the base values:

//add some weapons

int weaponsToAdd=rand.Next(2,5);

for(int weaponNum=0;weaponNum<=weaponsToAdd;weaponNum++) 

{

  int randWeaponIndex=rand.Next(currentLevel-1,currentLevel+3);

  Coordinate c=getRandomOpenRoom();

  rooms[c.x,c.y].roomObject=weapons[randWeaponIndex].Clone();

}

//add some armor

int armorToAdd=rand.Next(2,5);

for(int armorNum=0;armorNum<=armorToAdd;armorNum++)

{

  int randArmorIndex=rand.Next(currentLevel-1,currentLevel+3);

  Coordinate c=getRandomOpenRoom();

  rooms[c.x,c.y].roomObject=armor[randArmorIndex].Clone();

}

//add some enemies

int enemiesToAdd=rand.Next(3,5);

for(int enemiesNum=0;enemiesNum<=enemiesToAdd;enemiesNum++)

{

  int randEnemyIndex=rand.Next(currentLevel-1,currentLevel+3);

  Coordinate c=getRandomOpenRoom();

  rooms[c.x,c.y].roomObject=enemies[randEnemyIndex].Clone();

}

[... and so on ...]

When all is said and done, the map now looks a bit fuller:

Maze with random objects

It's not perfect. For starters there are too many doors, I should revisit that algorithm later. Otherwise, not too shabby.



What's next?

So I guess the next logical step in all this would be to create the first person view and animation. This is probably where I'll quit out of frustration. Graphics programming has never been my strong point nor something I'm particularly passionate about. Then again, I've made a lot of progress on this in a short amount of time so maybe I'll give it a go...


Tweet