MazeMaker

Overview

Maze Maker is a framework game developers (customizers) use to create first person adventure games. In a typical game the user (players) guides a hero through a maze of rooms connected by doorways. The hero seeks the room containing a treasure. However, the treasure requires a certain number of keys to open. Each room contains some number of keys, which the hero must collect in order to open the treasure. For example, once the hero has found the treasure it might be necessary for him to backtrack in order to collect a sufficient number of keys to open the treasure. 

Unfortunately, monsters hide in each room. As the hero enters a room, the monsters attack. Hero and monsters exchange blows and attempt to block the blows they receive. An unblocked blow reduces the health of the recipient. Initially, the health is 100%. When health reaches 0% the character (hero or monster) dies.

Fortunately, some rooms also contain medicine bowls, which the hero can drink to improve his health.

The game ends when the hero dies or when the hero unlocks the treasure.

Customizers must extend the definitions of room, monster, and hero with specific details dealing with appearance and behavior.

Requirements Model

Functional Requirements (Use Cases)

Customization

customize

Playing

play

Design Model

The Framework

framework

The Creators

creators

A D&D Customization

dnd

Implementation

The Framework

interface Character {
   String description();
}

interface Monster extends Character {
   void attack(Hero h);
}

abstract class Hero  implements Character {
   private Room location;
   abstract public void defend(Monster m);
   public void move(Room r) {
      location = r;
   }
}

abstract class Maze {
   private Set<Room> rooms;
   public Maze() {
      rooms = new HashSet<Room>();
   }
   public void add(Room r) {
      rooms.add(r);
   }
   abstract public String description();
}

abstract class Room {
   private Set<Monster> monsters;
   private Set<Room> neighbors;
   public Room() {
      monsters = new HashSet<Monster>();
      neighbors = new HashSet<Room>();
   }
   public void add(Monster m) {
      monsters.add(m);
   }
   public void connect(Room r) {
      neighbors.add(r);
      r.neighbors.add(this);
   }
   abstract public String description();
}

Building Mazes

interface MazeFactory {
   Monster makeMonster();
   Hero makeHero();
   Maze makeMaze();
   Room makeRoom();
}

interface MazeBuilder {
   Maze getMaze();
   Room addRoom();
   void connect(Room r1, Room r2);
   void addMonster(Room r);
   void addHero(Room r);
}

class Director {
   private static Director theDirector;
   private Director() { }
   public static Director getDirector() {
      if (theDirector == null) {
         theDirector = new Director();
      }
      return theDirector;
   }

   public Maze buildMaze(MazeBuilder builder) {
      Room r1 = builder.addRoom();
      Room r2 = builder.addRoom();
      builder.connect(r1, r2);
      builder.addMonster(r1);
      builder.addMonster(r2);
      builder.addHero(r1);
      return builder.getMaze();
   }

   public Maze buildMaze(MazeFactory kit) {
      Maze maze = kit.makeMaze();
      Room r1 = kit.makeRoom();
      Room r2 = kit.makeRoom();
      r1.connect(r2);
      maze.add(r1);
      maze.add(r2);
      Monster m1 = kit.makeMonster();
      Monster m2 = kit.makeMonster();
      r1.add(m1);
      r2.add(m2);
      Hero h = kit.makeHero();
      h.move(r1);
      return maze;
   }
}

A D&D Implementation

class Dragon implements Monster {
   public void attack(Hero h) {
      System.out.println("Belch flames");
   }
   public String description() {
      return "A fire-breathing monster";
   }
}

class Knight extends Hero {
   public void defend(Monster m) {
      System.out.println("Hide behind shield");
   }
   public String description() {
      return "A knight in shining armor";
   }
}

class Castle extends Maze {
   public String description() {
      return "A dilapidated castle";
   }
}

class Dungeon extends Room {
   public String description() {
      return "A dark and damp dungeon";
   }
}

Implementing the Builders

class CastleFactory implements MazeFactory {
   public Monster makeMonster() {
      return new Dragon();
   }
   public Hero makeHero() {
      return new Knight();
   }
    public Maze makeMaze() {
      return new Castle();
   }
    public Room makeRoom() {
      return new Dungeon();
   }
}

class CastleBuilder implements MazeBuilder {
   private Castle castle = new Castle();
   public Maze getMaze() { return castle; }
   public Room addRoom() {
      Room r = new Dungeon();
      castle.add(r);
      return r;
   }
   public void connect(Room r1, Room r2) {
      r1.connect(r2);
   }
   public void addMonster(Room r) {
      r.add(new Dragon());
   }
   public void addHero(Room r) {
      Knight k = new Knight();
      k.move(r);
   }
}

Putting it all together

public class MazeDemos {
   public static void main(String[] args) {
      Director d = Director.getDirector();
      Maze m1 = d.buildMaze(new CastleFactory());
      Maze m2 = d.buildMaze(new CastleBuilder());
      System.out.println("done");
   }
}