104
BOMBERMAN Source code : BomberBGM.java import java.io.*; public class BomberBGM { private static Object player; private static int lastSelection = -1; static { if (Main.J2) { try { player = new SoundPlayer( new File(BomberMain.RP + "Sounds/BomberBGM/"). getCanonicalPath()); } catch (Exception e) { new ErrorDialog(e); } ((SoundPlayer)player).open(); } } public static void change(String arg) { if (Main.J2) { int i = 0; while (i < ((SoundPlayer)player).sounds.size() && ((SoundPlayer)player).sounds.elementAt(i). toString().indexOf(arg) < 0) i += 1; if (i != lastSelection && i < ((SoundPlayer)player).sounds.size()) { lastSelection = i; ((SoundPlayer)player).change(lastSelection, true); } } }

Bomber Man

Embed Size (px)

Citation preview

Page 1: Bomber Man

BOMBERMANSource code :

BomberBGM.java

import java.io.*;

public class BomberBGM {

private static Object player; private static int lastSelection = -1;

static { if (Main.J2) { try { player = new SoundPlayer( new File(BomberMain.RP + "Sounds/BomberBGM/"). getCanonicalPath()); } catch (Exception e) { new ErrorDialog(e); } ((SoundPlayer)player).open(); } }

public static void change(String arg) { if (Main.J2) { int i = 0; while (i < ((SoundPlayer)player).sounds.size() && ((SoundPlayer)player).sounds.elementAt(i). toString().indexOf(arg) < 0) i += 1; if (i != lastSelection && i < ((SoundPlayer)player).sounds.size()) { lastSelection = i; ((SoundPlayer)player).change(lastSelection, true); } } }

public static void stop() { if (Main.J2) { ((SoundPlayer)player).controlStop();

Page 2: Bomber Man

} }

public static void mute() { if (Main.J2) { ((SoundPlayer)player).mute(); } }

public static void unmute() { if (Main.J2) { ((SoundPlayer)player).unmute(); } }}

BomberBonus.javaimport java.awt.*;import javax.swing.*;import java.io.*;

public class BomberBonus extends Thread { /** map object */ private BomberMap map = null; /** position */ private int x = 0; private int y = 0; /** frame count */ private int frame = 0; /** alive flag */ private boolean alive = true; /** bonus type */ private int type = 0; /** bomb sprite image handles */ private Image[] images = null; /** rendering hints */ private static Object hints = null;

private static int FIRE = 0; private static int BOMB = 1;

static { /** if java runtime is Java 2 */

Page 3: Bomber Man

if (Main.J2) { /** create the rendering hints for better graphics output */ RenderingHints h = null; h = new RenderingHints(null); h.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); h.put(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); h.put(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); h.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); h.put(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); hints = (RenderingHints)h; } }

/** * Constructs a bonus. * @param map map object * @param x x-coordinate * @param y y-coordinage * @param type bonus type; */ public BomberBonus(BomberMap map, int x, int y, int type) { this.map = map; this.x = x; this.y = y; this.type = type; this.images = BomberMap.bonusImages[type];

setPriority(Thread.MAX_PRIORITY); start(); }

/** * Main loop. */ public synchronized void run() { while (alive) { /** draw the bonus */ map.paintImmediately(x, y, BomberMain.size, BomberMain.size); /** rotate frame */ frame = (frame + 1) % 2; /** sleep for 130 ms */

Page 4: Bomber Man

try { sleep(130); } catch (Exception e) {} if (frame == 10) break; } /** remove it from the grid */ map.removeBonus(x, y); }

/** * Gives this bonus to a user then removes it. */ public void giveToPlayer(int player) { BomberMain.sndEffectPlayer.playSound("Bonus"); /** if it's a fire bonus */ if (type == FIRE) /** then increase the fire length by 1 */ BomberGame.players[player - 1].fireLength += 1; /** if it's a bomb bonus */ else if (type == BOMB) /** then increase the bomb count by 1 */ BomberGame.players[player - 1].totalBombs += 1; kill(); }

/** * Kills the object along with the thread */ public void kill() { alive = false; interrupt(); }

/** * Drawing method. */ public void paint(Graphics g) { /** if java runtime is Java 2 */ if (Main.J2) { paint2D(g); } /** if java runtime isn't Java 2 */ else { g.drawImage(images[frame], x, y, BomberMain.size, BomberMain.size, null); } }

/** * Drawing method for Java 2's Graphics2D * @param graphics graphics handle */

Page 5: Bomber Man

public void paint2D(Graphics graphics) { Graphics2D g2 = (Graphics2D)graphics; /** set the rendering hints */ g2.setRenderingHints((RenderingHints)hints); g2.drawImage(images[frame], x, y, BomberMain.size, BomberMain.size, null); }}

BomberFire.javaimport java.awt.*;import javax.swing.*;

public class BomberFire extends Thread { /** map object */ private BomberMap map = null; /** map grid handle */ private int[][] grid = null; /** position */ private int x = 0; private int y = 0; /** fire type */ private int type = 0; /** frame count */ private int frame = 0; /** owner */ private int owner = 0; /** bomb sprite image handles */ private static Image[][] images = null; /** rendering hints */ private static Object hints = null;

static { /** if java runtime is Java 2 */ if (Main.J2) { /** create the rendering hints for better graphics output */ RenderingHints h = null; h = new RenderingHints(null); h.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); h.put(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); h.put(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); h.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

Page 6: Bomber Man

h.put(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); hints = (RenderingHints)h; } }

public BomberFire(BomberMap map, int x, int y, int type) { this.map = map; grid = map.grid; this.x = x; this.y = y; this.type = type; this.owner = owner - 1; this.images = BomberMap.fireImages;

if (type == BomberMap.FIRE_BRICK) grid[x >> BomberMain.shiftCount][y >> BomberMain.shiftCount] = BomberMap.FIRE_BRICK; map.fireGrid[x >> BomberMain.shiftCount][y >> BomberMain.shiftCount] = true;

/** see if there is a bonus in the same spot */ if (map.bonusGrid[x >> BomberMain.shiftCount] [y >> BomberMain.shiftCount] != null) { /** if yes then remove it */ map.removeBonus(x, y); }

setPriority(Thread.MAX_PRIORITY); start(); }

/** * Main loop. */ public void run() { while (true) { /** draw the fire */ paint(); /** see if any players are in the way */ for (int i = 0; i < BomberGame.totalPlayers; i++) { /** if there is */ if ((BomberGame.players[i].x >> BomberMain.shiftCount) == (x >> BomberMain.shiftCount) && (BomberGame.players[i].y >> BomberMain.shiftCount) == (y >> BomberMain.shiftCount)) { /** then kill it */

Page 7: Bomber Man

BomberGame.players[i].kill(); } } /** increase frame */ frame = frame + 1; /** sleep for 65 ms */ try { sleep(65); } catch (Exception e) {} /** if frame is greater than 7 then it's finish burning */ if (frame > 7) break; } map.grid[x >> BomberMain.shiftCount][y >> BomberMain.shiftCount] = BomberMap.NOTHING; map.fireGrid[x >> BomberMain.shiftCount][y >> BomberMain.shiftCount] = false; /** if this is a tail or brick, then it's the last fire in the chain */ /** then refresh the screen */ map.paintImmediately(x, y, BomberMain.size, BomberMain.size); /** if this was a brick then create a bonus there */ if (type == BomberMap.FIRE_BRICK) { map.createBonus(x, y); } }

/** * Drawing method. */ public void paint() { Graphics g = map.getGraphics(); /** if java runtime is Java 2 */ if (Main.J2) { paint2D(map.getGraphics()); } /** if java runtime isn't Java 2 */ else { g.drawImage(images[type][frame], x, y, BomberMain.size, BomberMain.size, null); } g.dispose(); }

/** * Drawing method for Java 2's Graphics2D * @param graphics graphics handle */ public void paint2D(Graphics graphics) { Graphics2D g2 = (Graphics2D)graphics; /** set the rendering hints */ g2.setRenderingHints((RenderingHints)hints); g2.drawImage(images[type][frame], x, y, BomberMain.size, BomberMain.size, null);

Page 8: Bomber Man

}}

BomberImageButton.java

import java.awt.*;import javax.swing.*;import java.io.*;

public class BomberImageButton { /** this object's container */ private JPanel panel; /** x co-ordinate where the image is drawn */ private int x; /** y co-ordinate where the image is drawn */ private int y; /** ID of object (for command) */ private int ID; /** image width */ private int w; /** image height */ private int h; /** area the object controls */ private Rectangle rect; /** the images of the button: normal / outerglowed */ private Image[] images; /** stae of button: normal / outglowed */ private int state = 0;

/** rendering hints */ private static Object hints = null;

static { /** if java runtime is Java 2 */ if (Main.J2) { /** create the rendering hints for better graphics output */ RenderingHints h = null; h = new RenderingHints(null); h.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); h.put(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); h.put(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); h.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

Page 9: Bomber Man

h.put(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); hints = (RenderingHints)h; } }

/** * Construct with a MainMenu object and an array of images for use with * the button. * @param mainMenu object's container * @param images images for the button */ public BomberImageButton(JPanel panel, Image[] images) { this.panel = panel; this.images = images; /** calculate image dimension */ w = images[0].getWidth(panel); h = images[0].getHeight(panel); }

/** * Set object's parameters. * @param x x co-ordinate on window * @param y y co-ordinate on window * @param ID object's ID or command return code */ public void setInfo(int x, int y, int ID) { this.x = x; this.y = y; this.ID = ID; /** calculate area in which the object owns to handle mouse events */ rect = new Rectangle(this.x, this.y - 5, w, h + 10); }

/** * @return the ojbect's ID */ public int getID() { return ID; }

/** * Set bevel on or off * @param bevelOn true or false */ public void setBevel(boolean bevelOn) {

Page 10: Bomber Man

if (bevelOn) state = 1; else state = 0; panel.repaint(); panel.paintImmediately(x, y, w / (32 / BomberMain.size * 2), h / (32 / BomberMain.size * 2)); }

/** * Draws the button onto the window. * @param graphics graphics handler */ public void paint(Graphics graphics) { /** if java runtime is Java 2 */ if (Main.J2) { paint2D(graphics); } /** if java runtime isn't Java 2 */ else { Graphics g = graphics; /** draw the button */ g.drawImage(images[state], x, y, w / (32 / BomberMain.size * 2), h / (32 / BomberMain.size * 2), null); } }

/** * Drawing method for Java 2's Graphics2D * @param graphics graphics handle */ public void paint2D(Graphics graphics) { Graphics2D g2 = (Graphics2D)graphics; /** set the rendering hints */ g2.setRenderingHints((RenderingHints)hints); /** draw the button */ g2.drawImage(images[state], x, y, w / (32 / BomberMain.size * 2), h / (32 / BomberMain.size * 2), null); }}

BomberKeyQueue.java

Page 11: Bomber Man

public class BomberKeyQueue { /** head and tail nodes */ private Node head = null, tail = null; /** total nodes */ private int totalItems = 0;

/** * Default constructor. */ public BomberKeyQueue() { /** place holder */ }

/** * Pushes an item into the queue. * @param b byte to be pushed */ public void push(byte b) { /** create the new node object */ Node newNode = new Node(b); /** if list is empty then head and tail equals new object */ if (head == null) head = tail = newNode; /** if list isn't empty */ else { /** last object's next object equals new object */ tail.next = newNode; /** new object's previous object equals last object */ newNode.prev = tail; /** tail pointer now points to the new object */ tail = newNode; } /** increase total items count */ totalItems += 1; }

/** * Removes an item from the list then return it. * @return last item in the list */ public byte pop() { /** setup object to be returned */ byte result = 0x00; /** if list isn't empty */ if (tail != null) { /** copy last item's data */ result = tail.data;

Page 12: Bomber Man

/** last item now becomes last item's previous item */ tail = tail.prev; /** if list isn't empty now then set last item to point to null */ if (tail != null) tail.next = null; /** if list is empty then head = tail = null */ else head = tail; /** decrease total items count */ totalItems -= 1; } /** return the object */ return result; }

/** * Removes all instances of an item * @param b byte to be removed */ public void removeItems(byte b) { /** create temporary node and set it to point to head */ Node temp = head; /** loop while end of list not reached */ while (temp != null) { /** if current pointed to object's data is equal to parameter */ if (temp.data == b) { /** reset object's previous link */ if (temp.prev != null) temp.prev.next = temp.next; /** reset object's next link */ if (temp.next != null) temp.next.prev = temp.prev; /** if object is the head of list then reset head */ if (temp == head) head = temp.next; /** if object is the tail of list then reset tail */ if (temp == tail) tail = temp.prev; /** decrease total items count */ totalItems -= 1; } /** get next item in the list */ temp = temp.next; } }

/** * Removes all elements */ public void removeAll() { head = tail = null; }

Page 13: Bomber Man

/** * @return size of the list */ public int size() { return totalItems; }

/** * @return the last item in the list. */ public byte getLastItem() { /** setup data to be returned */ byte result = 0x00; /** if list isn't empty then copy last item's data */ if (tail != null) result = tail.data; /** return the data */ return result; }

/** * @return whether an item is in the list or not */ public boolean contains(byte b) { /** setup data to be returned (default to false) */ boolean result = false; /** create temporary Node object for navigation */ Node temp = head; /** loop till end of list is reached */ while (temp != null) { /** if data found then get otta here */ if (temp.data == b) { result = true; break; } /** get next item in the list */ temp = temp.next; } /** return the result */ return result; }

/** * This is the data object for the queue. */ private class Node { /** the key data */ public byte data = 0x00; /** pointers / links */

Page 14: Bomber Man

public Node prev = null, next = null;

/** * Construct with data */ public Node(byte b) { /** set data */ data = b; }

/** * Copy constructor. * @param n node to be copied */ public Node(Node n) { /** copy data */ data = n.data; /** copy the links */ prev = n.prev; next = n.next; } }}

BomberMap.javaimport java.awt.*;import java.awt.event.*;import javax.swing.*;import java.io.*;import java.util.Vector;public class BomberMap extends JPanel { /** frame object */ private BomberMain main = null; /** game over flag */ private boolean gameOver = false; /** background color */ private Color backgroundColor = null; /** the map grid array */ public int[][] grid = null; /** fire grid */ public boolean[][] fireGrid = null; /** bomb grid */ public BomberBomb[][] bombGrid = null; /** bonus grid */

Page 15: Bomber Man

public BomberBonus[][] bonusGrid = null; /** bombs */ private Vector bombs = null; /** bonuses */ private Vector bonuses = null;

/** * Bomb info class */ private class Bomb { public Bomb(int x, int y) { r = (x >> BomberMain.shiftCount); c = (y >> BomberMain.shiftCount); } public int r = 0; public int c = 0; }

/** * Bonus info class */ private class Bonus { public Bonus(int x, int y) { r = (x >> BomberMain.shiftCount); c = (y >> BomberMain.shiftCount); } public int r = 0; public int c = 0; }

/** image handles for the map images */ private static Image[][] mapImages = null; /** bomb images */ public static Image[] bombImages = null; /** fire images */ public static Image[][] fireImages = null; /** fire brick images */ public static Image[][] fireBrickImages = null; /** bonus images */ public static Image[][] bonusImages = null; /** fire type enumerations */ public static final int FIRE_CENTER = 0; public static final int FIRE_VERTICAL = 1; public static final int FIRE_HORIZONTAL = 2; public static final int FIRE_NORTH = 3; public static final int FIRE_SOUTH = 4;

Page 16: Bomber Man

public static final int FIRE_EAST = 5; public static final int FIRE_WEST = 6; public static final int FIRE_BRICK = 7; /** grid slot type enumerations */ public static final int BONUS_FIRE = -4; public static final int BONUS_BOMB = -3; public static final int NOTHING = -1; public static final int WALL = 0; public static final int BRICK = 1; public static final int BOMB = 3; /** random level generator */ private static BomberRandInt levelRand = null; /** random bonus generator */ private static BomberRandInt bonusRand = null; /** current level */ public static int level = 0; /** rendering hints */ private static Object hints = null;

static { /** if java runtime is Java 2 */ if (Main.J2) { /** create the rendering hints for better graphics output */ RenderingHints h = null; h = new RenderingHints(null); h.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); h.put(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); h.put(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); h.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); h.put(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); hints = (RenderingHints)h; }

/** create the level random generator */ levelRand = new BomberRandInt(0, 100); /** create the bonus random generator */ bonusRand = new BomberRandInt(0, 7); /** creat the image objects array */ mapImages = new Image[3][3]; /** create the bomb objects array */ bombImages = new Image[2];

Page 17: Bomber Man

/** create the fire objects array */ fireImages = new Image[8][8]; /** create the fire brick objects array */ fireBrickImages = new Image[3][8]; /** create the bonus image objects array */ bonusImages = new Image[2][2];

try { String[] strs = new String[3]; /** load the map images */ for (int i = 0; i < 2; i++) { strs[0] = BomberMain.RP + "Images/BomberWalls/" + (i + 1); strs[1] = BomberMain.RP + "Images/BomberBricks/" + (i + 1); strs[2] = BomberMain.RP + "Images/BomberFloors/" + (i + 1); for (int j = 0; j < 3; j++) { if (i == 0) strs[j] += ".jpg"; else strs[j] += ".gif"; } mapImages[i][0] = Toolkit.getDefaultToolkit().getImage( new File(strs[0]).getCanonicalPath()); mapImages[i][1] = Toolkit.getDefaultToolkit().getImage( new File(strs[1]).getCanonicalPath()); if (i == 0) mapImages[i][2] = null; else mapImages[i][2] = Toolkit.getDefaultToolkit().getImage( new File(strs[2]).getCanonicalPath()); }

String str = null; /** load the bomb images */ for (int i = 0; i < 2; i++) { str = BomberMain.RP + "Images/BomberBombs/" + (i + 1) + ".gif"; bombImages[i] = Toolkit.getDefaultToolkit().getImage( new File(str).getCanonicalPath()); }

/** load the fire images */ for (int t = 0; t < 7; t++) for (int i = 0; i < 8; i++) { str = BomberMain.RP + "Images/BomberFires/"; if (t == FIRE_CENTER) str += "C"; else if (t == FIRE_VERTICAL) str += "V"; else if (t == FIRE_NORTH) str += "N"; else if (t == FIRE_HORIZONTAL) str += "H"; else if (t == FIRE_EAST) str += "E"; else if (t == FIRE_WEST) str += "W";

Page 18: Bomber Man

else if (t == FIRE_SOUTH) str += "S"; if (t == FIRE_BRICK) fireImages[t][i] = null; else { str += (i + 1) + ".gif"; fireImages[t][i] = Toolkit.getDefaultToolkit().getImage( new File(str).getCanonicalPath()); } }

int f = 0; /** load the fire brick images */ for (int i = 0; i < 2; i++) for (f = 0; f < 8; f++) { str = BomberMain.RP + "Images/BomberFireBricks/" + (i + 1) + (f + 1) + ".gif"; fireBrickImages[i][f] = Toolkit.getDefaultToolkit().getImage( new File(str).getCanonicalPath()); }

/** load the bonus image sprites */ for (int i = 0; i < 2; i++) for (f = 0; f < 2; f++) { str = BomberMain.RP + "Images/BomberBonuses/" + (i == 0 ? "F" : "B") + (f + 1) + ".gif"; bonusImages[i][f] = Toolkit.getDefaultToolkit().getImage( new File(str).getCanonicalPath()); } } catch (Exception e) { new ErrorDialog(e); } }

public BomberMap(BomberMain main) { this.main = main; /** generator random level */ level = levelRand.draw() % 2; MediaTracker tracker = new MediaTracker(this); /** prepare the images */ try { int counter = 0; /** load the map images */ for (int i = 0; i < 2; i++) for (int j = 0; j < 3; j++) { if (mapImages[i][j] != null) { tracker.addImage(mapImages[i][j], counter++); } } /** load the bomb images */

Page 19: Bomber Man

for (int i = 0; i < 2; i++) tracker.addImage(bombImages[i], counter++); /** load the fire brick images */ for (int i = 0; i < 8; i++) fireImages[FIRE_BRICK][i] = fireBrickImages[level][i]; /** load the fire images */ for (int i = 0; i < 8; i++) for (int j = 0; j < 8; j++) tracker.addImage(fireImages[i][j], counter++);

/** wait for images to finish loading */ tracker.waitForAll(); } catch (Exception e) { new ErrorDialog(e); }

bombs = new Vector(); bonuses = new Vector(); /** create the fire grid */ fireGrid = new boolean[17][17]; /** create the bomb grid */ bombGrid = new BomberBomb[17][17]; /** create the bonus grid */ bonusGrid = new BomberBonus[17][17]; /** create the map grid */ grid = new int[17][17]; /** fill the map with walls by alternating r by c */ for (int r = 0; r < 17; r++) for (int c = 0; c < 17; c++) { /** if it's the edge */ if (r == 0 || c == 0 || r == 16 || c == 16) grid[r][c] = WALL; else if ( (r & 1) == 0 && (c & 1) == 0 ) grid[r][c] = WALL; else grid[r][c] = NOTHING; fireGrid[r][c] = false; bombGrid[r][c] = null; bonusGrid[r][c] = null; }

int x, y; BomberRandInt ri = new BomberRandInt(1, 15); /** generate random bricks */ for (int i = 0; i < 192 * 2; i++) { x = ri.draw(); y = ri.draw(); if (grid [x][y] == NOTHING) grid [x][y] = BRICK; }

/** clear corners so players can stand there */

Page 20: Bomber Man

grid [ 1][ 1] = grid [ 2][ 1] = grid [ 1][ 2] = grid [ 1][15] = grid [ 2][15] = grid [ 1][14] = grid [15][ 1] = grid [14][ 1] = grid [15][ 2] = grid [15][15] = grid [15][14] = grid [14][15] = NOTHING;

/** create background color */ backgroundColor = new Color(52, 108, 108); /** set panel size */ setPreferredSize(new Dimension(17 << BomberMain.shiftCount, 17 << BomberMain.shiftCount)); /** double buffer on */ setDoubleBuffered(true);

setBounds(0, 0, 17 << main.shiftCount, 17 << main.shiftCount); setOpaque(false); /** add the map to the bottom layer */ main.getLayeredPane().add(this, 1000); }

/** * Sets game over flag on */ public void setGameOver() { gameOver = true; paintImmediately(0, 0, 17 << BomberMain.shiftCount, 17 << BomberMain.shiftCount); }

/** * Creates a bonus. * @param x x-coordinate * @param y y-coordinate * @param owner owner */ public synchronized void createBonus(int x, int y) { int _x = (x >> BomberMain.shiftCount) << BomberMain.shiftCount; int _y = (y >> BomberMain.shiftCount) << BomberMain.shiftCount; int type = bonusRand.draw(); /** create bonus : 0 = fire; 1 = bomb */ if (type == 0 || type == 1) { bonusGrid[_x >> BomberMain.shiftCount][_y >> BomberMain.shiftCount] = new BomberBonus(this, _x, _y, type); bonuses.addElement(new Bonus(_x, _y)); } }

Page 21: Bomber Man

/** * Removes a bonus. * @param x x-coordinate * @param y y-coordinate */ public synchronized void removeBonus(int x, int y) { int i = 0, k = bonuses.size(); int r = (x >> BomberMain.shiftCount); int c = (y >> BomberMain.shiftCount); Bonus b = null; while (i < k) { b = (Bonus)bonuses.elementAt(i); if (b.r == r && b.c == c) { bonuses.removeElementAt(i); bonusGrid[b.r][b.c].kill(); bonusGrid[b.r][b.c] = null; paintImmediately(b.r << BomberMain.shiftCount, b.c << BomberMain.shiftCount, BomberMain.size, BomberMain.size); break; } i += 1; k = bonuses.size(); } }

/** * Creates a bomb. * @param x x-coordinate * @param y y-coordinate * @param owner owner */ public synchronized void createBomb(int x, int y, int owner) { int _x = (x >> BomberMain.shiftCount) << BomberMain.shiftCount; int _y = (y >> BomberMain.shiftCount) << BomberMain.shiftCount; bombGrid[_x >> BomberMain.shiftCount][_y >> BomberMain.shiftCount] = new BomberBomb(this, _x, _y, owner); bombs.addElement(new Bomb(_x, _y)); }

/** * Removes a bomb. * @param x x-coordinate * @param y y-coordinate */ public synchronized void removeBomb(int x, int y) {

Page 22: Bomber Man

int i = 0, k = bombs.size(); int r = (x >> BomberMain.shiftCount); int c = (y >> BomberMain.shiftCount); Bomb b = null; while (i < k) { b = (Bomb)bombs.elementAt(i); if (b.r == r & b.c == c) { bombs.removeElementAt(i); break; } i += 1; k = bombs.size(); } }

/** * Creates a fire. * @param x x-coordinate * @param y y-coordinate * @param owner owner * @param type fire type */ public void createFire(int x, int y, int owner, int type) { int _x = (x >> BomberMain.shiftCount) << BomberMain.shiftCount; int _y = (y >> BomberMain.shiftCount) << BomberMain.shiftCount; boolean createFire = false; /** if there's a bomb here */ if (grid[_x >> BomberMain.shiftCount][_y >> BomberMain.shiftCount] == BOMB) { /** then short the bomb */ if (bombGrid[_x >> BomberMain.shiftCount][_y >> BomberMain.shiftCount] != null) bombGrid[_x >> BomberMain.shiftCount][_y >> BomberMain.shiftCount].shortBomb(); } /** if there's no fire there already */ else if (!fireGrid[_x >> BomberMain.shiftCount][_y >> BomberMain.shiftCount]) { createFire = true; /** create a fire there */ BomberFire f = new BomberFire(this, _x, _y, type); } /** if this is a center */ if (createFire && type == FIRE_CENTER) { int shiftCount = BomberMain.shiftCount;

Page 23: Bomber Man

int size = BomberMain.size; /** then create a chain of fire */ int northStop = 0, southStop = 0, westStop = 0, eastStop = 0, northBlocks = 0, southBlocks = 0, westBlocks = 0, eastBlocks = 0; /** see how long the fire can be */ for (int i = 1; i <= BomberGame.players[owner].fireLength; i++) { /** if it can still go south */ if (southStop == 0) { if (((_y >> shiftCount) + i) < 17) { /** if there isnt't a wall there */ if (grid[_x >> shiftCount][(_y >> shiftCount) + i] != WALL) { /** if there's something there though */ if (grid[_x >> shiftCount][(_y >> shiftCount) + i] != NOTHING) /** then create a tail fire there */ { southStop = grid[_x >> shiftCount] [(_y >> shiftCount) + i]; } /** increase fire chain */ southBlocks += 1; } else southStop = -1; } } /** if it can still go north */ if (northStop == 0) { if (((_y >> shiftCount) - 1) >= 0) { /** if there isn't a wall there */ if (grid[_x >> shiftCount][(_y >> shiftCount) - i] != WALL) { /** if there's something there though */ if (grid[_x >> shiftCount][(_y >> shiftCount) - i] != NOTHING) /** then create a tail fire there */ { northStop = grid[_x >> shiftCount] [(_y >> shiftCount) - i]; } /** increaes fire chain */ northBlocks += 1; } else northStop = -1; } } /** if it can still go east */ if (eastStop == 0) { if (((_x >> shiftCount) + i) < 17) { /** if there isn't a wall there */ if (grid[(_x >> shiftCount) + i][_y >> shiftCount] != WALL) { /** if there's somethign there though */ if (grid[(_x >> shiftCount) + i][_y >> shiftCount] != NOTHING) /** then create a tail fire there */ { eastStop = grid[(_x >> shiftCount) + i] [_y >> shiftCount]; } /** increase fire chain */ eastBlocks += 1;

Page 24: Bomber Man

} else eastStop = -1; } } /** if it can still go west */ if (westStop == 0) { if (((_x >> shiftCount) - i) >= 0) { /** if there isn't a wall there */ if (grid[(_x >> shiftCount) - i][_y >> shiftCount] != WALL) { /** if there's something there through */ if (grid[(_x >> shiftCount) - i] [_y >> shiftCount] != NOTHING) /** then create a tail fire there */ { westStop = grid[(_x >> shiftCount) - i] [_y >> shiftCount]; } /** increase fire chain */ westBlocks += 1; } else westStop = -1; } } } /** create the north chain */ for (int i = 1; i <= northBlocks; i++) { /** if this is a tail */ if (i == northBlocks) { /** if there's a brick */ if (northStop == BRICK) /** then create a burning brick sprite */ createFire(_x, _y - (i * size), owner, FIRE_BRICK); /** if it's not a brick then create a tail */ else createFire(_x, _y - (i * size), owner, FIRE_NORTH); } /** if it's not a tail then create a normal fire */ else createFire(_x, _y - (i * size), owner, FIRE_VERTICAL); } for (int i = 1; i <= southBlocks; i++) { /** if this is a tail */ if (i == southBlocks) { /** if there's a brick */ if (southStop == BRICK) /** then create a burning brick sprite */ createFire(_x, _y + (i * size), owner, FIRE_BRICK); /** if it's not a brick then create a tail */ else createFire(_x, _y + (i * size), owner, FIRE_SOUTH); } /** if it's not a tail then create a normal fire */ else createFire(_x, _y + (i * size), owner, FIRE_VERTICAL); } for (int i = 1; i <= eastBlocks; i++) { /** if this is a tail */

Page 25: Bomber Man

if (i == eastBlocks) { /** if there's a brick */ if (eastStop == BRICK) /** then create a burning brick sprite */ createFire(_x + (i * size), _y, owner, FIRE_BRICK); /** if it's not a brick then create a tail */ else createFire(_x + (i * size), _y, owner, FIRE_EAST); } /** if it's not a tail then create a normal fire */ else createFire(_x + (i * size), _y, owner, FIRE_HORIZONTAL); } for (int i = 1; i <= westBlocks; i++) { /** if this is a tail */ if (i == westBlocks) { /** if there's a brick */ if (westStop == BRICK) /** then create a burning brick sprite */ createFire(_x - (i * size), _y, owner, FIRE_BRICK); /** if it's not a brick then create a tail */ else createFire(_x - (i * size), _y, owner, FIRE_WEST); } /** if it's not a tail then create a normal fire */ else createFire(_x - (i * size), _y, owner, FIRE_HORIZONTAL); } } }

/** * Drawing method. * @param graphics graphics handle */ public synchronized void paint(Graphics graphics) { Graphics g = graphics; /** if java runtime is Java 2 */ if (Main.J2) { paint2D(graphics); } /** if java runtime isn't Java 2 */ else { /** if game is over */ if (gameOver) { /** fill the screen with black color */ g.setColor(Color.black); g.fillRect(0, 0, 17 << BomberMain.shiftCount, 17 << BomberMain.shiftCount); } /** if game isn't over yet */ else {

Page 26: Bomber Man

/** fill window with background color */ g.setColor(backgroundColor); g.fillRect(0, 0, 17 << BomberMain.shiftCount, 17 << BomberMain.shiftCount); /** draw the map */ for (int r = 0; r < 17; r++) for (int c = 0; c < 17; c++) { /** if there's something in the block */ if (grid[r][c] > NOTHING && grid[r][c] != BOMB && grid[r][c] != FIRE_BRICK && mapImages[level][grid[r][c]] != null) { g.drawImage(mapImages[level][grid[r][c]], r << BomberMain.shiftCount, c << BomberMain.shiftCount, BomberMain.size, BomberMain.size, null); } /** if the block is empty */ else { if (mapImages[level][2] != null) { /** draw the floor */ g.drawImage(mapImages[level][2], r << BomberMain.shiftCount, c << BomberMain.shiftCount, BomberMain.size, BomberMain.size, null); } } } } } if (!gameOver) { /** draw the bonuses */ Bonus bb = null; int i = 0, k = bonuses.size(); while (i < k) { bb = (Bonus)bonuses.elementAt(i); if (bonusGrid[bb.r][bb.c] != null) bonusGrid[bb.r][bb.c].paint(g); i += 1; k = bonuses.size(); } /** draw the bombs */ Bomb b = null; i = 0; k = bombs.size(); while (i < k) { b = (Bomb)bombs.elementAt(i); if (bombGrid[b.r][b.c] != null) bombGrid[b.r][b.c].paint(g);

Page 27: Bomber Man

i += 1; k = bombs.size(); } } }

/** * Drawing method for Java 2's Graphics2D * @param graphics graphics handle */ public void paint2D(Graphics graphics) { Graphics2D g2 = (Graphics2D)graphics; /** set the rendering hints */ g2.setRenderingHints((RenderingHints)hints); /** if game is over */ if (gameOver) { /** fill the screen with black color */ g2.setColor(Color.black); g2.fillRect(0, 0, 17 << BomberMain.shiftCount, 17 << BomberMain.shiftCount); } /** if game isn't over yet */ else { /** fill window with background color */ g2.setColor(backgroundColor); g2.fillRect(0, 0, 17 << BomberMain.shiftCount, 17 << BomberMain.shiftCount); /** draw the map */ for (int r = 0; r < 17; r++) for (int c = 0; c < 17; c++) { /** if there's something in the block */ if (grid[r][c] > NOTHING && grid[r][c] != BOMB && grid[r][c] != FIRE_BRICK && mapImages[level][grid[r][c]] != null) { g2.drawImage(mapImages[level][grid[r][c]], r << BomberMain.shiftCount, c << BomberMain.shiftCount, BomberMain.size, BomberMain.size, null); } /** if the block is empty */ else { if (mapImages[level][2] != null) { /** draw the floor */ g2.drawImage(mapImages[level][2], r << BomberMain.shiftCount, c << BomberMain.shiftCount, BomberMain.size, BomberMain.size, null); }

Page 28: Bomber Man

} } } }}

BomberPlayer.javaimport java.awt.*;import java.awt.event.*;import javax.swing.*;import java.io.*;import java.lang.Integer;

public class BomberPlayer extends Thread { /** game object handle */ public BomberGame game = null; /** map object handle */ private BomberMap map = null; /** player's own bomb grid (must have for synchronization) */ public boolean[][] bombGrid = null; /** input key queue */ private BomberKeyQueue keyQueue = null; /** bomb key is down or not */ private boolean bombKeyDown = false; /** direction keys down */ private byte dirKeysDown = 0x00; /** current direction key down */ private byte currentDirKeyDown = 0x00; /** sprite width */ private final int width = BomberMain.size; /** sprite height */ private final int height = 44 / (32 / BomberMain.size); /** is exploding flag */ private boolean isExploding = false; /** is dead flag */ private boolean isDead = false; /** whether a key is pressed or not */ private boolean keyPressed = false; /** the player's input keys */ private int[] keys = null; /** total bombs the player has */ public int totalBombs = 1; /** total bombs the player used */ public int usedBombs = 0; /** the player's fire strength */ public int fireLength = 2;

Page 29: Bomber Man

/** if player is alive */ public boolean isActive = true; /** player position */ public int x = 0; public int y = 0; /** player's number */ private int playerNo = 0; /** user's state : default to face down */ private int state = DOWN; /** flag : whether the player is moving or not */ private boolean moving = false; /** sprite frame number */ private int frame = 0; /** clear mode flag */ private boolean clear = false;

/** byte enumerations */ private static final byte BUP = 0x01; private static final byte BDOWN = 0x02; private static final byte BLEFT = 0x04; private static final byte BRIGHT = 0x08; private static final byte BBOMB = 0x10; /** number enumerations */ private static final int UP = 0; private static final int DOWN = 1; private static final int LEFT = 2; private static final int RIGHT = 3; private static final int BOMB = 4; private static final int EXPLODING = 4; /** all player sprite images */ private static Image[][][] sprites = null; /** rendering hints */ private static Object hints = null;

static { /** if java runtime is Java 2 */ if (Main.J2) { /** create the rendering hints for better graphics output */ RenderingHints h = null; h = new RenderingHints(null); h.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); h.put(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); h.put(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);

Page 30: Bomber Man

h.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); h.put(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); hints = (RenderingHints)h; }

/** create the images */ sprites = new Image[4][5][5]; int[] states = { UP, DOWN, LEFT, RIGHT, EXPLODING }; Toolkit tk = Toolkit.getDefaultToolkit(); String path = new String(); /** open the files */ try { for (int p = 0; p < 4; p++) { for (int d = 0; d < 5; d++) { for (int f = 0; f < 5; f++) { /** generate file name */ path = BomberMain.RP + "Images/"; path += "Bombermans/Player " + (p + 1) + "/"; path += states[d] + "" + (f + 1) + ".gif"; /** open the file */ sprites[p][d][f] = tk.getImage( new File(path).getCanonicalPath()); } } } } catch (Exception e) { new ErrorDialog(e); } }

/** * Constructs a player. * @param game game object * @param map map object * @param playerNo player's number */ public BomberPlayer(BomberGame game, BomberMap map, int playerNo) { this.game = game; this.map = map; this.playerNo = playerNo;

/** create the bomb grid */ bombGrid = new boolean[17][17]; for (int i = 0; i < 17; i++) for (int j = 0; j < 17; j++) bombGrid[i][j] = false;

Page 31: Bomber Man

int r = 0, c = 0; /** find player's starting position */ switch (this.playerNo) { case 1: r = c = 1; break; case 2: r = c = 15; break; case 3: r = 15; c = 1; break; case 4: r = 1; c = 15; } /** calculate position */ x = r << BomberMain.shiftCount; y = c << BomberMain.shiftCount;

MediaTracker tracker = new MediaTracker(game); try { int counter = 0; /** load the images */ for (int p = 0; p < 4; p++) { for (int d = 0; d < 5; d++) { for (int f = 0; f < 5; f++) { tracker.addImage(sprites[p][d][f], counter++); } } } /** wait for images to finish loading */ tracker.waitForAll(); } catch (Exception e) { new ErrorDialog(e); }

/** create the key queue */ keyQueue = new BomberKeyQueue(); /** create the key configurations array */ keys = new int[5]; /** load the configurations */ for (int k = BomberKeyConfig.UP; k <= BomberKeyConfig.BOMB; k++) keys[k] = BomberKeyConfig.keys[playerNo - 1][k]; /** HOG THE CPU!!! */ setPriority(Thread.MAX_PRIORITY); /** start looping */ start(); }

/** * Key pressed event handler. * @param evt key event

Page 32: Bomber Man

*/ public void keyPressed(KeyEvent evt) { /** assume no new key is pressed */ byte newKey = 0x00; /** if player isn't exploding or dead and key pressed is in player's */ /** key list */ if (!isExploding && !isDead && evt.getKeyCode() == keys[UP] || evt.getKeyCode() == keys[DOWN] || evt.getKeyCode() == keys[LEFT] || evt.getKeyCode() == keys[RIGHT]) { /** if down key pressed */ if (evt.getKeyCode() == keys[DOWN]) { newKey = BDOWN; /** if only the up key is pressed */ if ((currentDirKeyDown & BUP) > 0 || ((currentDirKeyDown & BLEFT) == 0 && (currentDirKeyDown & BRIGHT) == 0)) currentDirKeyDown = BDOWN; } /** if up key is pressed */ else if (evt.getKeyCode() == keys[UP]) { newKey = BUP; /** if only the down key is pressed */ if ((currentDirKeyDown & BDOWN) > 0 || ((currentDirKeyDown & BLEFT) == 0 && (currentDirKeyDown & BRIGHT) == 0)) currentDirKeyDown = BUP; } /** if left key is pressed */ else if (evt.getKeyCode() == keys[LEFT]) { newKey = BLEFT; /** if only the right key is pressed */ if ((currentDirKeyDown & BRIGHT) > 0 || ((currentDirKeyDown & BUP) == 0 && (currentDirKeyDown & BDOWN) == 0)) currentDirKeyDown = BLEFT; } /** if right key is pressed */ else if (evt.getKeyCode() == keys[RIGHT]) { newKey = BRIGHT; /** if only the left is pressed */ if ((currentDirKeyDown & BLEFT) > 0 || ((currentDirKeyDown & BUP) == 0 &&

Page 33: Bomber Man

(currentDirKeyDown & BDOWN) == 0)) currentDirKeyDown = BRIGHT; } /** if new key isn't in the key queue */ if (!keyQueue.contains(newKey)) { /** then push it on top */ keyQueue.push(newKey); /** reset keys pressed buffer */ dirKeysDown |= newKey; keyPressed = true; /** if thread is sleeping, then wake it up */ interrupt(); } } /** if no direction key is pressed */ /** and bomb key is pressed */ if (!isExploding && !isDead && evt.getKeyCode() == keys[BOMB] && !bombKeyDown && isActive) { bombKeyDown = true; interrupt(); } }

/** * Key released handler. * @param evt key event */ public void keyReleased(KeyEvent evt) { /** if a direction key is released */ if (!isExploding && !isDead && ( evt.getKeyCode() == keys[UP] || evt.getKeyCode() == keys[DOWN] || evt.getKeyCode() == keys[LEFT] || evt.getKeyCode() == keys[RIGHT])) { /** if down key is released */ if (evt.getKeyCode() == keys[DOWN]) { /** remove key from the all keys down buffer */ dirKeysDown ^= BDOWN; /** reset current key down */ currentDirKeyDown ^= BDOWN; /** remove it from the key queue */ keyQueue.removeItems(BDOWN);

Page 34: Bomber Man

} /** if up key is released */ else if (evt.getKeyCode() == keys[UP]) { /** remove key from the all keys down buffer */ dirKeysDown ^= BUP; /** reset current key down */ currentDirKeyDown ^= BUP; /** remove it from the key queue */ keyQueue.removeItems(BUP); } /** if left key is released */ else if (evt.getKeyCode() == keys[LEFT]) { /** remove key from the all keys down buffer */ dirKeysDown ^= BLEFT; /** reset current key down */ currentDirKeyDown ^= BLEFT; /** remove it from the key queue */ keyQueue.removeItems(BLEFT); } /** if right key is released */ else if (evt.getKeyCode() == keys[RIGHT]) { /** remove key from the all keys down buffer */ dirKeysDown ^= BRIGHT; /** reset current key down */ currentDirKeyDown ^= BRIGHT; /** remove it from the key queue */ keyQueue.removeItems(BRIGHT); } /** if no key is currently down */ if (currentDirKeyDown == 0) { /** see if last key pressed is still pressed or not */ boolean keyFound = false; /** search for last key pressed */ while (!keyFound && keyQueue.size() > 0) { /** if key is found then exit the loop */ if ((keyQueue.getLastItem() & dirKeysDown) > 0) { currentDirKeyDown = keyQueue.getLastItem(); keyFound = true; } /** if key is not found then pop the current key */ /** and on to the next one */ else keyQueue.pop(); } /** if no key found */ if (!keyFound)

Page 35: Bomber Man

{ /** remove all keys from queue if not already removed */ keyQueue.removeAll(); /** reset key buffers */ currentDirKeyDown = 0x00; dirKeysDown = 0x00; keyPressed = false; interrupt(); } } } /** if the bomb key is released */ if (!isExploding && !isDead && evt.getKeyCode() == keys[BOMB]) { bombKeyDown = false; interrupt(); } }

/** * Deactivates the player so it can't be controlled. */ public void deactivate() { isActive = false; }

/** * Kills the player */ public void kill() { /** is player isn't dead or isn't dieing already */ if (!isDead && !isExploding) { /** lower players left */ BomberGame.playersLeft -= 1; /** reset frame counter */ frame = 0; /** set exploding mode */ state = EXPLODING; /** make it animate */ moving = true; /** prepare to explode! */ isExploding = true; /** release keys */

Page 36: Bomber Man

keyPressed = false; BomberMain.sndEffectPlayer.playSound("Die"); /** wake up and die */ interrupt(); } }

/** * @return x co-ordinate */ public int getX() { return x; }

/** * @return y co-ordinate */ public int getY() { return y; }

/** * @return whether player is (dead or dieing) or not */ public boolean isDead() { return (isDead | isExploding); }

/** * Main loop */ public void run() { /** can move flat */ boolean canMove; /** keeps track of last key state */ boolean lastState = false; /** shift count */ int shiftCount = BomberMain.shiftCount; /** offset size */ int offset = 1 << (BomberMain.shiftCount / 2); /** block size */ int size = BomberMain.size; /** half the block size */ int halfSize = BomberMain.size / 2; /** temporary variables */ int bx = 0, by = 0; /** unconditional loop */ while (true) { /** if bomb key is down */ if (!isExploding && !isDead && bombKeyDown && isActive) { /** if bombs are available */

Page 37: Bomber Man

if ((totalBombs - usedBombs) > 0 && /** and a bomb isn't placed there already */ map.grid[x >> shiftCount][y >> shiftCount] != BomberMap.BOMB && !bombGrid[(x + halfSize) >> BomberMain.shiftCount][(y + halfSize) >> BomberMain.shiftCount]) { usedBombs += 1; bombGrid[(x + halfSize) >> BomberMain.shiftCount] [(y + halfSize) >> BomberMain.shiftCount] = true; /** create bomb */ map.createBomb(x + halfSize, y + halfSize, playerNo); } } /** if other keys are down */ if (!isExploding && !isDead && keyPressed) { /** store last state */ lastState = keyPressed; /** increase frame */ frame = (frame + 1) % 5; /** set moving to true */ moving = true; /** assume can't move */ canMove = false; /** make sure a key is down */ if (dirKeysDown > 0) { /** if left key is down */ if ((currentDirKeyDown & BLEFT) > 0) { state = LEFT; /** if west slot is empty then it can move */ canMove = (x % size != 0 || (y % size == 0 && (map.grid[(x >> shiftCount) - 1][y >> shiftCount] <= BomberMap.NOTHING)));

/** if it can't move */ if (!canMove) { int oy = 0; /** if it's a little bit north */ for (oy = -offset; oy < 0; oy += (size / 4)) { /** and west slot is empty */ if ((y + oy) % size == 0 && map.grid[(x >> shiftCount) - 1] [(y + oy) >> shiftCount] <= BomberMap.NOTHING) { /** then move anyway */ canMove = true; break; } }

Page 38: Bomber Man

/** if it still can't move */ if (!canMove) { /** if it's a little bit south */ for (oy = (size / 4); oy <= offset; oy += (size / 4)) { /** and west slot is empty */ if ((y + oy) % size == 0 && map.grid[(x >> shiftCount) - 1] [(y + oy) >> shiftCount] <= BomberMap.NOTHING) { /** move anyway */ canMove = true; break; } } } /** if it can move now */ if (canMove) { /** clear original spot */ clear = true; game.paintImmediately(x, y - halfSize, width, height); /** move up or down */ y += oy; /** redraw the sprite */ clear = false; game.paintImmediately(x, y - halfSize, width, height); } } /** if it can move */ if (canMove) { /** clear original spot */ clear = true; game.paintImmediately(x, y - halfSize, width, height); /** move left */ x -= (size / 4); /** redraw the sprite */ clear = false; game.paintImmediately(x, y - halfSize, width, height); } /** if it can't move */ else { /** refresh the sprite */ moving = false; game.paintImmediately(x, y - halfSize, width, height); } } /** if the right key is down */

Page 39: Bomber Man

else if ((currentDirKeyDown & BRIGHT) > 0) { state = RIGHT; canMove = false; /** if east slot is empty */ canMove = (x % size != 0 || (y % size == 0 && (map.grid[(x >> shiftCount) + 1][y >> shiftCount] <= BomberMap.NOTHING)));

/** if it can't move */ if (!canMove) { int oy = 0; /** see if it's a bit south */ for (oy = -offset; oy < 0; oy += (size / 4)) { /** and the east slot is empty */ if ((y + oy) % size == 0 && map.grid[(x >> shiftCount) + 1] [(y + oy) >> shiftCount] <= BomberMap.NOTHING) { /** move it */ canMove = true; break; } } /** if it still can't move */ if (!canMove) { /** see if it's a bit north */ for (oy = (size / 4); oy <= offset; oy += (size / 4)) { /** and the east slot if empty */ if ((y + oy) % size == 0 && map.grid[(x >> shiftCount) + 1] [(y + oy) >> shiftCount] <= BomberMap.NOTHING) { /** move it */ canMove = true; break; } } } /** if it can move now */ if (canMove) { /** clear original spot */ clear = true; game.paintImmediately(x, y - halfSize, width, height); /** move up or down */ y += oy; /** refresh the sprite */ clear = false; game.paintImmediately(x, y - halfSize, width, height);

Page 40: Bomber Man

} } /** if it can move */ if (canMove) { /** clear original spot */ clear = true; game.paintImmediately(x, y - halfSize, width, height); /** move right */ x += (size / 4); /** refresh the sprite */ clear = false; game.paintImmediately(x, y - halfSize, width, height); } /** if it can't move */ else { moving = false; /** refresh the sprite */ game.paintImmediately(x, y - halfSize, width, height); } } /** if up key is down */ else if ((currentDirKeyDown & BUP) > 0) { state = UP; canMove = false; /** if north slot is empty */ canMove = (y % size != 0 || (x % size == 0 && (map.grid[x >> shiftCount][(y >> shiftCount) - 1] <= BomberMap.NOTHING)));

/** if it can't move */ if (!canMove) { int ox = 0; /** see if it's a bit to the left */ for (ox = -offset; ox < 0; ox += (size / 4)) { /** and the north slot is empty */ if ((x + ox) % size == 0 && map.grid[(x + ox) >> shiftCount] [(y >> shiftCount) - 1] <= BomberMap.NOTHING) { canMove = true; break; } } /** if it still can't move */ if (!canMove) { /** see if it's a bit to the right */ for (ox = (size / 4); ox <= offset; ox += (size / 4)) {

Page 41: Bomber Man

/** and the north block is empty */ if ((x + ox) % size == 0 && map.grid[(x + ox) >> shiftCount] [(y >> shiftCount) - 1] <= BomberMap.NOTHING) { canMove = true; break; } } } /** if it can move */ if (canMove) { /** clear original block */ clear = true; game.paintImmediately(x, y - halfSize, width, height); /** move right */ x += ox; /** refresh the sprite */ clear = false; game.paintImmediately(x, y - halfSize, width, height); } } /** if it can move */ if (canMove) { /** clear original block */ clear = true; game.paintImmediately(x, y - halfSize, width, height); /** move up */ y -= (size / 4); /** refresh the sprite */ clear = false; game.paintImmediately(x, y - halfSize, width, height); } /** if it can't move */ else { /** refresh the block */ moving = false; game.paintImmediately(x, y - halfSize, width, height); } } /** if the down is is down */ else if ((currentDirKeyDown & BDOWN) > 0) { state = DOWN; canMove = false; /** if the south block is empty */ canMove = (y % size != 0 || (x % size == 0 &&

Page 42: Bomber Man

(map.grid[x >> shiftCount][(y >> shiftCount) + 1] <= BomberMap.NOTHING)));

/** if it can't move */ if (!canMove) { int ox = 0; /** see if it's a bit to the west */ for (ox = -offset; ox < 0; ox += (size / 4)) { /** and the south block is empty */ if ((x + ox) % size == 0 && map.grid[(x + ox) >> shiftCount] [(y >> shiftCount) + 1] <= BomberMap.NOTHING) { canMove = true; break; } } /** if it still can't move */ if (!canMove) { /** see if it's a bit to the east */ for (ox = (size / 4); ox <= offset; ox += (size / 4)) { /** and the south block is empty */ if ((x + ox) % size == 0 && map.grid[(x + ox) >> shiftCount] [(y >> shiftCount) + 1] <= BomberMap.NOTHING) { canMove = true; break; } } } /** if it can move now */ if (canMove) { /** clear orignal block */ clear = true; game.paintImmediately(x, y - halfSize, width, height); /** move left or right */ x += ox; /** refresh the sprite */ clear = false; game.paintImmediately(x, y - halfSize, width, height); } } /** if it can move now */ if (canMove) { /** clear original spot */ clear = true; game.paintImmediately(x, y - halfSize, width, height);

Page 43: Bomber Man

/** move down */ y += (size / 4); /** refresh the sprite */ clear = false; game.paintImmediately(x, y - halfSize, width, height); } /** if it can't move */ else { /** refresh the sprite */ moving = false; game.paintImmediately(x, y - halfSize, width, height); } } } } /** if all keys are up */ else if (!isExploding && !isDead && lastState != keyPressed) { /** reset frame to 0 */ frame = 0; moving = false; /** refresh sprite */ game.paintImmediately(x, y - halfSize, width, height); lastState = keyPressed; } /** if it's exploding */ else if (!isDead && isExploding) { /** if frame reached 4 then it's dead */ if (frame >= 4) isDead = true; /** refresh sprite */ game.paintImmediately(x, y - halfSize, width, height); /** rotate frame count */ frame = (frame + 1) % 5; } /** if it's dead */ else if (isDead) { /** clear the block */ clear = true; game.paintImmediately(x, y - halfSize, width, height); /** exit the loop */ break; } /** see if the player stepped on any bonuses */ /** try normal position */

Page 44: Bomber Man

if (map.bonusGrid[x >> shiftCount][y >> shiftCount] != null) { bx = x; by = y; } /** try a bit to the north */ else if (map.bonusGrid[x >> shiftCount][(y + halfSize) >> shiftCount] != null) { bx = x; by = y + halfSize; } /** try a bit to the left */ else if (map.bonusGrid[(x + halfSize) >> shiftCount][y >> shiftCount] != null) { bx = x + halfSize; by = y; } /** if the player did step on a bonus */ if (bx != 0 && by != 0) { map.bonusGrid[bx >> shiftCount][by >> shiftCount].giveToPlayer(playerNo); bx = by = 0; } /** if it's dead, then exit the loop */ if (isDead) break; /** delay 65 milliseconds */ try { sleep(65); } catch (Exception e) { } } interrupt(); }

/** * Drawing method. */ public void paint(Graphics graphics) { Graphics g = graphics; /** if java runtime is Java 2 */ if (Main.J2) { paint2D(graphics); } /** if java runtime isn't Java 2 */ else { /** if player isn't dead and clear mode isn't on */ if (!isDead && !clear) { /** if moving */ if (moving) /** draw the animating image */ g.drawImage(sprites[playerNo - 1][state][frame], x, y - (BomberMain.size / 2), width, height, null); /** if not moving */ else /** draw the still image */ g.drawImage(sprites[playerNo - 1][state][0], x, y - (BomberMain.size / 2), width, height, null); }

Page 45: Bomber Man

} }

/** * Drawing method for Java 2's Graphics2D * @param graphics graphics handle */ public void paint2D(Graphics graphics) { Graphics2D g2 = (Graphics2D)graphics; /** set the rendering hints */ g2.setRenderingHints((RenderingHints)hints); /** if player isn't dead and clear mode isn't on */ if (!isDead && !clear) { /** if moving */ if (moving) /** draw the animating image */ g2.drawImage(sprites[playerNo - 1][state][frame], x, y - (BomberMain.size / 2), width, height, null); /** if not moving */ else /** draw the still image */ g2.drawImage(sprites[playerNo - 1][state][0], x, y - (BomberMain.size / 2), width, height, null); } }}

BomberSndEffect.javaimport java.io.*;

public class BomberSndEffect extends Thread { public BomberSndEffect() { start(); }

public void playSound(String str) { /** if Java 2 is available */ if (Main.J2) { SoundPlayer sound = null; try { /** create sound player */ sound = new SoundPlayer( new File(BomberMain.RP + "Sounds/BomberSndEffects/" + str + ".mid"). getCanonicalPath());

Page 46: Bomber Man

} catch (Exception e) { } /** open file */ ((SoundPlayer)sound).open(); /** then play sound */ sound.change(0, false); } }}

Main.java

import javax.swing.*;

public class Main{ public static BomberMain bomberMain = null;

/** relative path */ public static final String RP = "./"; /** flag: whether current machine's java runtime is version 2 or not */ public static boolean J2 = false;

static { /** get java runtime version */ String version = System.getProperty("java.version"); /** parse it */ int major = Integer.parseInt(version.substring(0, 1)); int minor = Integer.parseInt(version.substring(2, 3)); /** if major is greater than or equal to 1 and */ /** if minor is greater than or equal to 3 */ /** then it's Java 2 */ if (major >= 1 && minor >= 2) J2 = true; }

/** * Starts Bomberman */ public static void startBomberman() { bomberMain = new BomberMain(); }

/** * Starts the program by creating an instance of MainFrame. */ public static void main(String[] args)

Page 47: Bomber Man

{ boolean bombermanMode = false; boolean badArg = false; /** default look and feel: metal */ int lookAndFeel = 1; /** check supplied parameters (if any) */ for (int i = 0; i < args.length; i++) { /** if "bomberman" parameter is supplied */ if (args[i].equals("Bomberman") || args[i].equals("bomberman")) bombermanMode = true; /** if look and feel parameter is supplied */ if (args[i].startsWith("-l")) { if (args[i].substring(2).equals("System")) lookAndFeel = 0; else if (args[i].substring(2).equals("Metal")) lookAndFeel = 1; else if (args[i].substring(2).equals("Windows")) lookAndFeel = 2; else if (args[i].substring(2).equals("Mac")) lookAndFeel = 3; else if (args[i].substring(2).equals("Motif")) lookAndFeel = 4; } } /** if look and feel isn't default: metal */ if (lookAndFeel != 1) { try { /** * available look and feels: * ========================= * "javax.swing.plaf.metal.MetalLookAndFeel" * "com.sun.java.swing.plaf.windows.WindowsLookAndFeel" * "com.sun.java.swing.plaf.motif.MotifLookAndFeel" * "javax.swing.plaf.mac.MacLookAndFeel" */ String laf = "javax.swing.plaf.metal.MetalLookAndFeel"; if (lookAndFeel == 0) laf = UIManager.getSystemLookAndFeelClassName(); else if (lookAndFeel == 1) laf = "javax.swing.plaf.metal.MetalLookAndFeel"; else if (lookAndFeel == 2) laf = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel"; else if (lookAndFeel == 3) laf = "javax.swing.plaf.mac.MacLookAndFeel"; else if (lookAndFeel == 4) laf = "com.sun.java.swing.plaf.motif.MotifLookAndFeel"; UIManager.setLookAndFeel(laf); } catch (Exception e) { new ErrorDialog(e); }

Page 48: Bomber Man

}

startBomberman(); }}

BomberBomb.javaimport java.awt.*;import javax.swing.*;import java.io.*;

public class BomberBomb extends Thread { /** map object */ private BomberMap map = null; /** position */ private int x = 0; private int y = 0; /** frame count */ private int frame = 0; /** alive flag */ private boolean alive = true; /** owner */ private int owner = 0; /** count down : 3000 ms */ private int countDown = 3900; /** bomb sprite image handles */ private static Image[] images = null; /** rendering hints */ private static Object hints = null;

static { /** if java runtime is Java 2 */ if (Main.J2) { /** create the rendering hints for better graphics output */ RenderingHints h = null; h = new RenderingHints(null); h.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); h.put(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); h.put(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); h.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); h.put(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); hints = (RenderingHints)h;

Page 49: Bomber Man

} }

/** * Constructs a BOMB! * @param map game map * @param x x-coordinate * @param y y-coordinate * @param owner owner * @param images bomb images */ public BomberBomb(BomberMap map, int x, int y, int owner) { this.map = map; this.x = x; this.y = y; this.owner = owner - 1; this.images = BomberMap.bombImages;

map.grid[x >> BomberMain.shiftCount][y >> BomberMain.shiftCount] = BomberMap.BOMB; setPriority(Thread.MAX_PRIORITY); start(); }

/** * Main loop. */ public synchronized void run() { while (alive) { /** draw the bomb */ //paint(); map.paintImmediately(x, y, BomberMain.size, BomberMain.size); /** rotate frame */ frame = (frame + 1) % 2; /** sleep for 130 ms */ try { sleep(130); } catch (Exception e) {} if (!alive) break; /** decrease count down */ countDown -= 130; /** if count down reached 0 then exit */ /** the loop and short the bomb */ if (countDown <= 0) break; } /** remove it from the grid */ map.grid[x >> BomberMain.shiftCount][y >> BomberMain.shiftCount] = BomberMap.NOTHING;

Page 50: Bomber Man

/** give the bomb back to the player */ BomberGame.players[owner].usedBombs -= 1; map.bombGrid[x >> BomberMain.shiftCount][y >> BomberMain.shiftCount] = null; BomberGame.players[owner].bombGrid [x >> BomberMain.shiftCount][y >> BomberMain.shiftCount] = false; map.removeBomb(x, y); BomberMain.sndEffectPlayer.playSound("Explosion"); /** create the fire */ map.createFire(x, y, owner, BomberMap.FIRE_CENTER); }

/** * Explodes the bomb */ public void shortBomb() { alive = false; interrupt(); }

/** * Drawing method. */ public void paint(Graphics g) { /** if java runtime is Java 2 */ if (Main.J2) { paint2D(g); } /** if java runtime isn't Java 2 */ else { g.drawImage(images[frame], x, y, BomberMain.size, BomberMain.size, null); } }

/** * Drawing method for Java 2's Graphics2D * @param graphics graphics handle */ public void paint2D(Graphics graphics) { Graphics2D g2 = (Graphics2D)graphics; /** set the rendering hints */ g2.setRenderingHints((RenderingHints)hints); g2.drawImage(images[frame], x, y, BomberMain.size, BomberMain.size, null); }}

BomberConfigDialog.java

Page 51: Bomber Man

import java.awt.*;import java.awt.event.*;import javax.swing.*;

public class BomberConfigDialog extends JDialogimplements ActionListener { /** temporary key datas used for manipulation */ private int[][] keys = null; /** keys being set offset values */ private int[] keysBeingSet = { -1, -1 }; /** waiting for key flag */ private boolean waitingForKey = false; /** the buttons that allow the user to set the keys */ private JButton[][] buttons = null; /** the text fields that display the keys */ private JTextField[][] keyFields = null;

/** * Constructs the dialog. * @param owner the dialog's owner */ public BomberConfigDialog(JFrame owner) { /** call base class constructor */ super(owner, "Bomberman Keys Configuration", true);

/** create the temporary key objects */ keys = new int[4][5]; /** set the object's data from the currently configurations */ for (int i = 0; i < 4; i++) for (int j = 0; j < 5; j++) keys[i][j] = BomberKeyConfig.keys[i][j];

/** create the panel that holds the config. stuff */ JPanel centerPanel = new JPanel(new GridLayout(2, 2)); /** panel for each player's config. stuff */ JPanel[] panels = new JPanel[4]; /** create the text fields array of array */ keyFields = new JTextField[4][]; /** create the buttons array */ buttons = new JButton[4][5]; for (int i = 0; i < 4; i++) { /** create the key fields array */ keyFields[i] = new JTextField[5]; /** create the 4 panels */ setupPanel(i, centerPanel, panels[i], keyFields[i]); }

Page 52: Bomber Man

/** create the panel to display the help message */ JPanel helpPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); /** setup the border */ helpPanel.setBorder(BorderFactory.createEtchedBorder()); /** add a label to it */ helpPanel.add(new JLabel("Click on the buttons to edit the keys.", JLabel.CENTER)); /** add the help panel to the north side of the dialog */ getContentPane().add(helpPanel, "North"); /** add the key setup panels to the center */ getContentPane().add(centerPanel, "Center"); /** create the panel to hold the buttons */ JPanel buttonsP = new JPanel(new FlowLayout(FlowLayout.CENTER)); buttonsP.setBorder(BorderFactory.createEtchedBorder()); /** create the save configuration button */ JButton saveButton = new JButton("Save Configurations"); saveButton.addActionListener(this); buttonsP.add(saveButton); /** create the close button */ JButton closeButton = new JButton("Close"); closeButton.addActionListener(this); buttonsP.add(closeButton); /** add the buttons panel to the south side of the dialog */ getContentPane().add(buttonsP, "South");

/** set the dialog so user can't resize it */ setResizable(false); /** minimize the size of the dialog */ pack();

int x = owner.getLocation().x + (owner.getSize().width - getSize().width) / 2; int y = owner.getLocation().y + (owner.getSize().height - getSize().height) / 2;

/** center the dialog relative to the owner */ setLocation(x, y); /** finally, show the dialog */ show(); }

/** * Creates a panel for each player. * @param pn player number * @param m master panel * @param p player's panel

Page 53: Bomber Man

* @param fields key fields */ private void setupPanel(int pn, JPanel m, JPanel p, JTextField[] fields) { /** create the left and right panels, 5 rows each */ JPanel left = new JPanel(new GridLayout(5, 1)); JPanel right = new JPanel(new GridLayout(5, 1));

/** create the buttons and text fields */ for (int i = 0; i < 5; i++) { /** create the button */ buttons[pn][i] = new JButton(); /** create the text field */ fields[i] = new JTextField(10); /** setup the button */ switch (i) { case 0: buttons[pn][i].setText("Up"); break; case 1: buttons[pn][i].setText("Down"); break; case 2: buttons[pn][i].setText("Left"); break; case 3: buttons[pn][i].setText("Right"); break; case 4: buttons[pn][i].setText("Bomb"); break; } /** add action handler to the button */ buttons[pn][i].addActionListener(this); /** setup the text field from data */ fields[i].setText(KeyEvent.getKeyText(keys[pn][i])); /** user can't edit the text field */ fields[i].setEditable(false); /** add the button to the left side */ left.add(buttons[pn][i]); /** add the text field to the right side */ right.add(fields[i]); }

/** create the player's panel */ p = new JPanel(new GridLayout(1, 2)); /** set the border */ p.setBorder(BorderFactory.createTitledBorder(BorderFactory. createEtchedBorder(), "Player " + (pn + 1) + " Keys Configuration")); /** add the buttons and the keys to the panel */ p.add(left); p.add(right); /** add the panel to the master panel */ m.add(p); }

Page 54: Bomber Man

/** * Action event handler. * @param evt action event info. */ public void actionPerformed(ActionEvent evt) { /** if save configuration button is clicked */ if (evt.getActionCommand().equals("Save Configurations")) { /** copy new keys back to glocal variables */ for (int i = 0; i < 4; i++) for (int j = 0; j < 5; j++) BomberKeyConfig.keys[i][j] = keys[i][j]; /** write the file */ BomberKeyConfig.writeFile(); /** destroy this dialog */ dispose(); } /** if close button is clicked then destroy the dialog */ else if (evt.getActionCommand().equals("Close")) dispose(); /** if other buttons are clicked */ else { /** find which key setup button is clicked */ int i = 0, j = 0; boolean found = false; for (i = 0; i < 4; ++i) { for (j = 0; j < 5; ++j) { /** if key found then exit the loop */ if (evt.getSource().equals(buttons[i][j])) found = true; if (found) break; } if (found) break; } /** set keys being set indexes */ keysBeingSet[0] = i; keysBeingSet[1] = j; /** setup get key loop */ waitingForKey = true; /** create the get key dialog */ new GetKeyDialog(this, "Press a key to be assigned...", true); } }

/** * This class gets a new key from the user then set it. */ private class GetKeyDialog extends JDialog { /** points to itself */ private JDialog me = null;

Page 55: Bomber Man

/** * Constructs a new dialog. * @param owner dialog's owner * @param title dialog title * @param modal modal or not */ public GetKeyDialog(JDialog owner, String title, boolean modal) { /** call base class constructor */ setTitle(title); setModal(modal); /** setup pointer to point to itself */ me = this;

/** add keyboard event handler */ addKeyListener(new KeyAdapter() { /** * Handles key pressed events. * @param evt keyboard event */ public void keyPressed(KeyEvent evt) { /** if it's waiting for a key */ if (waitingForKey) { /** get index of key to set */ int i = keysBeingSet[0]; int j = keysBeingSet[1]; /** get the key pressed */ int newKey = evt.getKeyCode(); /** key used flag */ boolean keyUsed = false; /** see if the key is used already or not */ for (int p = 0; p < 4; ++p) { for (int k = 0; k < 5; ++k) { /** if key is used already */ if (keys[p][k] == newKey) { /** if it isn't the key being set */ if (!(p == i && j == k)) /** set key used flag to true */ keyUsed = true; } /** if key used flag is true, then exit loop */ if (keyUsed) break; } /** if key used flag is true, then exit loop */ if (keyUsed) break; } /** if key isn't used */

Page 56: Bomber Man

if (!keyUsed) { /** copy new key */ keys[i][j] = newKey; /** reset the key field */ keyFields[i][j].setText( KeyEvent.getKeyText(keys[i][j])); /** set waiting for key to false */ waitingForKey = false; /** destroy the dialog */ dispose(); } /** if key is used already */ else { /** then show an error dialog */ /** create the dialog content */ JOptionPane pane = new JOptionPane( "Key: [" + KeyEvent.getKeyText(newKey) + "] is used already. Pick a different key."); /** setup the dialog controls */ pane.setOptionType(-JOptionPane.NO_OPTION); pane.setMessageType(JOptionPane.ERROR_MESSAGE); /** create the dialog */ JDialog dialog = pane.createDialog(me, "Error"); /** set it so user can't resize the dialog */ dialog.setResizable(false); /** show the dialog */ dialog.show(); } } } });

/** set the dialog so the user can't resize it */ setResizable(false); /** set dialog size */ setSize(300, 0);

int x = owner.getLocation().x + (owner.getSize().width - getSize().width) / 2; int y = owner.getLocation().y + (owner.getSize().width - getSize().height) / 2; /** center the dialog relative to the owner */ setLocation(x, y);

/** finally show the dialog */ show();

Page 57: Bomber Man

} }}

BomberGame.javaimport java.awt.*;import java.awt.event.*;import javax.swing.*;import java.io.*;

public class BomberGame extends JPanelimplements ActionListener { /** main frame object */ private BomberMain main = null; /** game over flag */ private boolean gameOver = false; /** map object */ private BomberMap map = null; /** winner */ private int winner = -1; /** timer */ private Timer timer = null; /** elapsed seconds */ private int elapsedSec = 0;

/** rendering hints */ private static Object hints = null; /** end game images */ private static Image[] images = null; /** total number of players */ public static int totalPlayers = 4; /** players alive */ public static int playersLeft = totalPlayers; /** player objects */ public static BomberPlayer[] players = null;

static { /** if java runtime is Java 2 */ if (Main.J2) { /** create the rendering hints for better graphics output */ RenderingHints h = null; h = new RenderingHints(null); h.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); h.put(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);

Page 58: Bomber Man

h.put(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); h.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); h.put(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); hints = (RenderingHints)h; }

String path = BomberMain.RP + "Images/BomberEndGame/"; String str = null; /** create the images */ images = new Image[6]; /** open the image files */ try { for (int i = 0; i < 4; i++) { str = path + "Player " + (i + 1) + " Wins.jpg"; images[i] = Toolkit.getDefaultToolkit().getImage( new File(str).getCanonicalPath()); } str = path + "Draw.jpg"; images[4] = Toolkit.getDefaultToolkit().getImage( new File(str).getCanonicalPath()); str = path + "Enter to Continue.jpg"; images[5] = Toolkit.getDefaultToolkit().getImage( new File(str).getCanonicalPath()); } catch (Exception e) { new ErrorDialog(e); } }

/** * Constructs a game. * @param main main frame object * @param map map object * @param totalPlayers total number of players */ public BomberGame(BomberMain main, BomberMap map, int totalPlayers) { this.main = main; this.map = map; this.totalPlayers = this.playersLeft = totalPlayers;

/** load the images */ try { MediaTracker tracker = new MediaTracker(this); for (int i = 0; i < 6; i++) tracker.addImage(images[i], i); tracker.waitForAll();

Page 59: Bomber Man

} catch (Exception e) { new ErrorDialog(e); }

/** create the players array */ players = new BomberPlayer[totalPlayers]; /** create the players */ for (int i = 0; i < totalPlayers; i++) players[i] = new BomberPlayer(this, map, i + 1);

/** double buffer on */ setDoubleBuffered(true); setBounds(0, 0, 17 << main.shiftCount, 17 << main.shiftCount); /** set it to opaque */ setOpaque(false); /** add it to the top layer */ main.getLayeredPane().add(this, 0); }

/** * Key pressed handler * @param evt key event */ public void keyPressed(KeyEvent evt) { if (!gameOver) { for (int i = 0; i < totalPlayers; i++) players[i].keyPressed(evt); } else if (evt.getKeyCode() == KeyEvent.VK_ENTER) { timer.stop(); timer = null; main.dispose(); new BomberMain(); } }

/** * Key released handler * @param evt key event */ public void keyReleased(KeyEvent evt) { if (!gameOver) { for (int i = 0; i < totalPlayers; i++) players[i].keyReleased(evt);

Page 60: Bomber Man

} }

/** * Drawing handler. * @param graphics graphics handle */ public void paint(Graphics graphics) { Graphics g = graphics; /** if game is active */ if (!gameOver) { for (int i = 0; i < totalPlayers; i++) players[i].paint(graphics); } /** if java runtime is Java 2 */ if (Main.J2) { paint2D(graphics); } /** if java runtime isn't Java 2 */ else { /** if game is over */ if (gameOver) { /** draw end game image */ g.drawImage(images[winner], 0, BomberMain.size == 16 ? -25 : -50, 17 << BomberMain.shiftCount, 17 << BomberMain.shiftCount, this); /** if elapsed seconds % 2 == 0 */ /** then draw press enter to exit image */ if (elapsedSec == 0) g.drawImage(images[5], 0, (17 << BomberMain.shiftCount) - images[5].getHeight(this) / (BomberMain.size != 16 ? 1 : 2), images[5].getWidth(this) / (BomberMain.size != 16 ? 1 : 2), images[5].getHeight(this) / (BomberMain.size != 16 ? 1 : 2), this); /** if elapsed seconds % 2 == 1 then clear the area */ else g.fillRect(0, (17 << BomberMain.shiftCount) - images[5].getHeight(this) / (BomberMain.size != 16 ? 1 : 2), images[5].getWidth(this) / (BomberMain.size != 16 ? 1 : 2), images[5].getHeight(this) / (BomberMain.size != 16 ? 1 : 2)); } /** if 1 or less players left alive */ if (playersLeft <= 1 && timer == null)

Page 61: Bomber Man

{ /** deactiavte all the players */ for (int i = 0; i < totalPlayers; i++) players[i].deactivate(); timer = new Timer(1000, this); timer.start(); } } }

/** * Public accessor to paintImmediately(...). * @param x x-coordinate * @param y y-coordinate * @param w width * @param h height */ public void pPaintImmediately(int x, int y, int w, int h) { paintImmediately(x, y, w, h); }

/** * Drawing method for Java 2's Graphics2D * @param graphics graphics handle */ public void paint2D(Graphics graphics) { Graphics2D g2 = (Graphics2D)graphics; /** set the rendering hints */ g2.setRenderingHints((RenderingHints)hints); /** if game is over */ if (gameOver) { /** draw end game image */ g2.drawImage(images[winner], 0, BomberMain.size == 16 ? -25 : -50, 17 << BomberMain.shiftCount, 17 << BomberMain.shiftCount, this); /** if elapsed seconds % 2 == 0 */ /** then draw press enter to exit image */ if (elapsedSec == 0) g2.drawImage(images[5], 0, (17 << BomberMain.shiftCount) - images[5].getHeight(this) / (BomberMain.size != 16 ? 1 : 2), images[5].getWidth(this) / (BomberMain.size != 16 ? 1 : 2), images[5].getHeight(this) / (BomberMain.size != 16 ? 1 : 2), this); /** if elapsed seconds % 2 == 1 then clear the area */ else g2.fillRect(0, (17 << BomberMain.shiftCount) -

Page 62: Bomber Man

images[5].getHeight(this) / (BomberMain.size != 16 ? 1 : 2), images[5].getWidth(this) / (BomberMain.size != 16 ? 1 : 2), images[5].getHeight(this) / (BomberMain.size != 16 ? 1 : 2)); } /** if 1 or less players left alive */ if (playersLeft <= 1 && timer == null) { /** deactiavte all the players */ for (int i = 0; i < totalPlayers; i++) players[i].deactivate(); timer = new Timer(1000, this); timer.start(); } }

public void actionPerformed(ActionEvent evt) { /** increased elapsed time */ elapsedSec += 1; /** if elapsed 4 seconds */ if (elapsedSec >= 4) { /** if Java 2 available */ if (Main.J2) { /** stop background music */ BomberBGM.mute(); } /** set default game result = draw */ winner = 4; /** find winner */ for (int i = 0; i < totalPlayers; i++) { if (!players[i].isDead()) { winner = i; break; } } gameOver = true; map.setGameOver(); /** restart timer with new delay */ timer.stop(); timer = new Timer(500, this); timer.start(); } /** if game is over */ if (gameOver) { elapsedSec %= 2; paintImmediately(0, (17 << BomberMain.shiftCount) - images[5].getHeight(this) / (BomberMain.size != 16 ? 1 : 2),

Page 63: Bomber Man

images[5].getWidth(this) / (BomberMain.size != 16 ? 1 : 2), images[5].getHeight(this) / (BomberMain.size != 16 ? 1 : 2)); } }}

BomberKeyConfig.javaimport java.awt.event.KeyEvent;import java.io.*;

public abstract class BomberKeyConfig { /** the keys */ public static int[][] keys = null; /** player numbers enumerations */ public static final int P1 = 0; public static final int P2 = 1; public static final int P3 = 2; public static final int P4 = 3; /** key number enumerations */ public static final int UP = 0; public static final int DOWN = 1; public static final int LEFT = 2; public static final int RIGHT = 3; public static final int BOMB = 4;

/** open the key configuration file */ static { /** try to open the file and if can't open file then */ if (!openFile()) { /** create the default configuration file */ createDefaultFile(); /** then try to open it again */ openFile(); } }

/** * Opens the configuration file. */ public static boolean openFile() { /** setup result to be returned */ boolean result = true; /** try to open the file */ try { /** create the file stream object */ ObjectInputStream inputStream =

Page 64: Bomber Man

new ObjectInputStream(new FileInputStream("BomberKeyConfig.dat")); /** read the file into memory */ keys = (int[][])inputStream.readObject(); /** close the file */ inputStream.close(); } /** if anything goes wrong, set result to to false */ catch (Exception e) { result = false; } /** return the result */ return result; }

/** * Writes the file with current data in memory. */ public static void writeFile() { /** try to create the file */ try { /** create the file object, overwrite the file if needs to */ ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("BomberKeyConfig.dat")); /** write the file */ outputStream.writeObject((int[][])keys); /** close the file */ outputStream.close(); } catch (Exception e) { new ErrorDialog(e); } }

/** * Creates the configuration file with default configurations. */ public static void createDefaultFile() { /** create the data, if it doens't exist already */ if (keys == null) keys = new int[4][5];

/** player 1 default key configurations */ keys[P1][UP] = KeyEvent.VK_UP; keys[P1][DOWN] = KeyEvent.VK_DOWN; keys[P1][LEFT] = KeyEvent.VK_LEFT; keys[P1][RIGHT] = KeyEvent.VK_RIGHT; keys[P1][BOMB] = KeyEvent.VK_NUMPAD0;

/** player 2 default key configurations */

Page 65: Bomber Man

keys[P2][UP] = KeyEvent.VK_W; keys[P2][DOWN] = KeyEvent.VK_S; keys[P2][LEFT] = KeyEvent.VK_A; keys[P2][RIGHT] = KeyEvent.VK_D; keys[P2][BOMB] = KeyEvent.VK_SPACE;

/** player 3 default key configurations */ keys[P3][UP] = KeyEvent.VK_I; keys[P3][DOWN] = KeyEvent.VK_K; keys[P3][LEFT] = KeyEvent.VK_J; keys[P3][RIGHT] = KeyEvent.VK_L; keys[P3][BOMB] = KeyEvent.VK_BACK_SLASH;

/** player 4 default key configurations */ keys[P4][UP] = KeyEvent.VK_NUMPAD8; keys[P4][DOWN] = KeyEvent.VK_NUMPAD5; keys[P4][LEFT] = KeyEvent.VK_NUMPAD4; keys[P4][RIGHT] = KeyEvent.VK_NUMPAD6; keys[P4][BOMB] = KeyEvent.VK_NUMPAD9;

/** write the file */ writeFile(); }}

BomberMain.javaimport java.awt.*;import java.awt.event.*;import javax.swing.*;import java.lang.Integer;import java.io.*;

public class BomberMain extends JFrame { /** relative path for files */ public static String RP = "./"; /** menu object */ private BomberMenu menu = null; /** game object */ private BomberGame game = null;

/** sound effect player */ public static BomberSndEffect sndEffectPlayer = null; /** this is used to calculate the dimension of the game */ public static final int shiftCount = 4; /** this is the size of each square in the game */ public static final int size = 1 << shiftCount;

Page 66: Bomber Man

static { sndEffectPlayer = new BomberSndEffect(); }

/** * Constructs the main frame. */ public BomberMain() { /** add window event handler */ addWindowListener(new WindowAdapter() { /** * Handles window closing events. * @param evt window event */ public void windowClosing(WindowEvent evt) { /** terminate the program */ System.exit(0); } });

/** add keyboard event handler */ addKeyListener(new KeyAdapter() { /** * Handles key pressed events. * @param evt keyboard event */ public void keyPressed(KeyEvent evt) { if (menu != null) menu.keyPressed(evt); if (game != null) game.keyPressed(evt); }

/** * Handles key released events. * @param evt keyboard event */ public void keyReleased(KeyEvent evt) { if (game != null) game.keyReleased(evt); } });

/** set the window title */ setTitle("Bomberman 1.0 by Sammy Leong");

/** set the window icon */ try { setIconImage(Toolkit.getDefaultToolkit().getImage(

Page 67: Bomber Man

new File(RP + "Images/Bomberman.gif").getCanonicalPath())); } catch (Exception e) { new ErrorDialog(e); }

/** create and add the menu to the frame */ getContentPane().add(menu = new BomberMenu(this));

/** set the window so that the user can't resize it */ setResizable(false); /** minimize the size of the window */ pack();

/** get screen size */ Dimension d = Toolkit.getDefaultToolkit().getScreenSize();

int x = (d.width - getSize().width) / 2; int y = (d.height - getSize().height) / 2;

/** center the window on the screen */ setLocation(x, y); /** show the frame */ show(); /** make this window the top level window */ toFront(); }

/** * Creates a new game. * @param players total number of players */ public void newGame(int players) { JDialog dialog = new JDialog(this, "Loading Game...", false); dialog.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); dialog.setSize(new Dimension(200, 0)); dialog.setResizable(false); int x = getLocation().x + (getSize().width - 200) / 2; int y = getLocation().y + getSize().height / 2; dialog.setLocation(x, y); /** show the dialog */ dialog.show();

/** remove existing panels in the content pane */ getContentPane().removeAll(); getLayeredPane().removeAll(); /** get rid of the menu */

Page 68: Bomber Man

menu = null; /** create the map */ BomberMap map = new BomberMap(this);

/** create the game */ game = new BomberGame(this, map, players);

/** get rid of loading dialog */ dialog.dispose(); /** show the frame */ show(); /** if Java 2 available */ if (Main.J2) { BomberBGM.unmute(); /** player music */ BomberBGM.change("Battle"); } }

/** * Starting ponit of program. * @param args arguments */ public static void main(String[] args) { BomberMain bomberMain1 = new BomberMain(); }}

BomberMenu.javaimport java.awt.*;import java.awt.event.*;import javax.swing.*;import java.io.*;

public class BomberMenu extends JPanel { /** main frame pointer */ private BomberMain main = null; /** image button objects */ private BomberImageButton[] imageButtons = null; /** current selection */ private int selection = P2;

/** background image object */ private static Image backgroundImg = null; /** button images */ private static Image[] buttonImagesDown = null;

Page 69: Bomber Man

private static Image[] buttonImagesUp = null; /** rendering hints */ private static Object hints = null; /** options enumeration */ private static final int P2 = 0; private static final int P3 = 1; private static final int P4 = 2; private static final int CONTROL_SETUP = 3; private static final int EXIT = 4;

static { /** if java runtime is Java 2 */ if (Main.J2) { /** create the rendering hints for better graphics output */ RenderingHints h = null; h = new RenderingHints(null); h.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); h.put(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); h.put(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); h.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); h.put(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); hints = (RenderingHints)h; }

/** create the image objects */ buttonImagesDown = new Image[5]; buttonImagesUp = new Image[5];

/** setup path names */ Toolkit tk = Toolkit.getDefaultToolkit(); String path = BomberMain.RP + "Images/BomberMenu/"; String file = null; try { /** load background image */ file = path + "Background.jpg"; backgroundImg = tk.getImage(new File(file).getCanonicalPath());

/** load each button image */ for (int i = 0; i < 5; i++) { if (i <= P4) file = path + (i + 2) + " Player Game"; else if (i == CONTROL_SETUP) file = path + "Control Setup";

Page 70: Bomber Man

else if (i == EXIT) file = path + "Exit"; buttonImagesDown[i] = tk.getImage( new File(file + " Down.gif").getCanonicalPath()); buttonImagesUp[i] = tk.getImage( new File(file + " Up.gif").getCanonicalPath()); } } catch (Exception e) { new ErrorDialog(e); } }

/** * Constructs the menu. * @param main BomberMain object */ public BomberMenu(BomberMain main) { this.main = main; /** set the menu dimensions */ setPreferredSize(new Dimension(17 << main.shiftCount, 17 << main.shiftCount)); /** turn on double buffer */ setDoubleBuffered(true);

/** load the images */ MediaTracker mt = new MediaTracker(this); try { int counter = 0; /** load the background image */ mt.addImage(backgroundImg, counter++); /** load the button images */ for (int i = 0; i < 5; i++) { mt.addImage(buttonImagesDown[i], counter++); mt.addImage(buttonImagesUp[i], counter++); } /** wait for images to finish loading */ mt.waitForAll(); } catch (Exception e) { new ErrorDialog(e); } /** create the button objects array */ imageButtons = new BomberImageButton[5]; for (int i = 0; i < 5; i++) { /** setup the images */ Image[] images = { buttonImagesDown[i], buttonImagesUp[i] }; /** create each object */ imageButtons[i] = new BomberImageButton(this, images); } /** calculate distance between each button */

Page 71: Bomber Man

int dy = buttonImagesDown[0].getHeight(this) / (32 / main.size * 2); /** setup the buttons' positions */ for (int i = P2; i <= EXIT; i++) imageButtons[i].setInfo(0, (280 / (32 / main.size)) + (dy * i), i); /** set current selection to Player 2 */ imageButtons[P2].setBevel(true); }

/** * Handles key pressed events. * @param evt key event */ public void keyPressed(KeyEvent evt) { /** store old selection */ int newSelection = selection; switch (evt.getKeyCode()) { case KeyEvent.VK_UP: case KeyEvent.VK_LEFT: newSelection -= 1; break; case KeyEvent.VK_DOWN: case KeyEvent.VK_RIGHT: newSelection += 1; break; case KeyEvent.VK_ENTER: doCommand(selection); } /** if selection is new */ if (selection != newSelection) { /** if new selection is less than 0 then set it to exit button */ if (newSelection < 0) newSelection = EXIT; /** deselect old selection */ imageButtons[selection].setBevel(false); /** set up selection */ selection = newSelection; selection %= 5; /** select new selection */ imageButtons[selection].setBevel(true); } }

/** * Command handler. * @param command command */ public void doCommand(int command) { switch (command) { case P2: case P3: case P4: main.newGame(selection + 2);

Page 72: Bomber Man

break; case CONTROL_SETUP: new BomberConfigDialog(main); break; case EXIT: /** create the dialog content */ JOptionPane pane = new JOptionPane("Are you sure you want to exit Bomberman?"); /** setup the dialog content */ pane.setOptionType(JOptionPane.YES_NO_OPTION); pane.setMessageType(JOptionPane.WARNING_MESSAGE); /** create the dialog */ JDialog dialog = pane.createDialog(this, "Exit Bomberman?"); dialog.setResizable(false); /** show the dialog */ dialog.show(); Object selection = pane.getValue();

/** if user clicked on yes */ if (selection != null && selection.toString().equals("0")) /** terminate the program */ System.exit(0); } }

/** * Painting method. * @param g graphics handler */ public void paint(Graphics graphics) { Graphics g = graphics; /** if java runtime is Java 2 */ if (Main.J2) { paint2D(graphics); } /** if java runtime isn't Java 2 */ else { g.drawImage(backgroundImg, 0, 0, 17 << main.shiftCount, 17 << main.shiftCount, this); } for (int i = 0; i < 5; i++) if (imageButtons[i] != null) imageButtons[i].paint(g); }

/** * Drawing method for Java 2's Graphics2D * @param graphics graphics handle */

Page 73: Bomber Man

public void paint2D(Graphics graphics) { Graphics2D g2 = (Graphics2D)graphics; /** set the rendering hints */ g2.setRenderingHints((RenderingHints)hints); g2.drawImage(backgroundImg, 0, 0, 17 << main.shiftCount, 17 << main.shiftCount, this); }}

BomberRandInt.java

public class BomberRandInt { /** lowest integer in the range */ private int low = 0; /** highest integer in the range */ private int high = 0;

/** stack size */ private static final int BUFFER_SIZE = 101; /** stack to hold random doubles */ private static double[] buffer = new double[BUFFER_SIZE];

/** * Fill the stack with 101 random doubles using the built-in random double * generator. */ static { for (int i = 0; i < BUFFER_SIZE; i++) buffer[i] = java.lang.Math.random(); }

/** * Constructs an object that generates random integers in a given range. * @param low the lowest integer in the range * @param high the highest integer in the range */ public BomberRandInt(int low, int high) { this.low = low; this.high = high; }

/** * Get the next random double from the stack then generate an integer from * it. * @return a random integer */ public int draw() {

Page 74: Bomber Man

int result = low + (int)((high - low + 1) * nextRandom()); return result; }

/** * Pick a random element in the stack and store the value of it into a * variable to be returned then fill that element with a new random double. * @return a random double */ private static double nextRandom() { /** pick a random element in the stack */ int position = (int)(java.lang.Math.random() * BUFFER_SIZE); if (position == BUFFER_SIZE) position = BUFFER_SIZE - 1; /** store the value of that element */ double result = buffer[position]; /** fill that element with a new random double */ buffer[position] = java.lang.Math.random(); /** return the value */ return result; }}

ErrorDialog.java

public class ErrorDialog{ /** * Construct from an Exception object. * @param e exception object thrown */ public ErrorDialog(Exception e) { /** store the stack trace (error message) into a string variable */ CharArrayWriter writer = new CharArrayWriter(); e.printStackTrace(new PrintWriter(writer, true)); String result = new String(" " + writer.toString() + "\n" + " CLICK OK TO TERMINATE THE PROGRAM."); /** create a text field and put the error message into it */ JTextArea ta = new JTextArea(result); /** make it read only */ ta.setEditable(false); /** create a scrollpane to contain the text field */ JScrollPane scroller = new JScrollPane(ta); /** create a container to contain the scrollpane */

Page 75: Bomber Man

JOptionPane pane = new JOptionPane(scroller); /** setup the scrollpane */ pane.setOptionType(-JOptionPane.NO_OPTION); pane.setMessageType(JOptionPane.ERROR_MESSAGE); /** create and show the dialog */ JDialog dialog = pane.createDialog(null, "Exception Caught"); dialog.setResizable(false); dialog.show(); Object selection = pane.getValue(); /** exit the program */ System.exit(-1); } /** * Construct from an Exception object and a boolean flag of whether to * terminate the program or not. * @param e exception object thrown */ public ErrorDialog(Exception e, boolean terminate) { /** store the stack trace (error message) into a string variable */ CharArrayWriter writer = new CharArrayWriter(); e.printStackTrace(new PrintWriter(writer, true)); String result = new String(" " + writer.toString()); /** create a text field and put the error message into it */ JTextArea ta = new JTextArea(result); ta.setEditable(false); /** create a scrollpane to contain the text field */ JScrollPane scroller = new JScrollPane(ta); /** create a container to contain the scrollpane */ JOptionPane pane = new JOptionPane(scroller); /** setup the scrollpane */ pane.setOptionType(-JOptionPane.NO_OPTION); pane.setMessageType(JOptionPane.ERROR_MESSAGE); /** create and show the dialog */ JDialog dialog = pane.createDialog(null, "Exception Caught"); dialog.setResizable(false); dialog.show(); Object selection = pane.getValue(); /** exit the program if terminate is tree */

Page 76: Bomber Man

if (terminate) System.exit(-1); } }

SoundPlayer.java

import java.awt.*;import java.awt.event.*;import javax.swing.*;import javax.sound.midi.*;import javax.sound.sampled.*;import java.io.File;import java.io.FileInputStream;import java.io.BufferedInputStream;import java.util.Vector;import java.net.URL;

public class SoundPlayer extends JPanelimplements Runnable, LineListener, MetaEventListener, ActionListener{ /** sound object list */ public Vector sounds = new Vector(); /** thread used to play the sound */ private Thread thread; /** sound sequencer */ private Sequencer sequencer; /** flag: playing midi or audio file */ private boolean midiEOM, audioEOM; /** sound synthesizer */ private Synthesizer synthesizer; /** channel objects for playing midi */ private MidiChannel channels[]; /** current playing sound */ private Object currentSound; /** current sound name */ private String currentName; /** sound list offset */ private int num = -1; /** flag: change of sound */ private boolean bump; /** flag: paused or not */ private boolean paused = false; /** flag: loop or not */ public boolean loop = true; /** volumn */ private int volumn = 100;

Page 77: Bomber Man

/** control buttons */ JButton startB, pauseB, prevB, nextB;

/** * Construct a sound player with directory name of music files. * @param dirName directory with sound files */ public SoundPlayer(String dirName) { if (dirName != null) { /** load the sound files */ loadFile(dirName); }

/** create control buttons the panel */ JPanel jp = new JPanel(new GridLayout(4, 1)); /** create the buttons */ startB = addButton("Start", jp, sounds.size() != 0); pauseB = addButton("Pause", jp, false); prevB = addButton("<<", jp, false); nextB = addButton(">>", jp, false); }

/** * Create a button. * @param name name of button * @param panel container of button * @param state enabled or disabled */ private JButton addButton(String name, JPanel panel, boolean state) { /** create the button */ JButton b = new JButton(name); /** add action handler */ b.addActionListener(this); /** set state */ b.setEnabled(state); if (panel != null) /** add it to the container */ panel.add(b); /** return the button */ return b; }

/**

Page 78: Bomber Man

* Create and open the sequencer. */ public void open() { try { /** get the system sequencer */ sequencer = MidiSystem.getSequencer(); if (sequencer instanceof Synthesizer) { synthesizer = (Synthesizer)sequencer; /** get the system channels */ channels = synthesizer.getChannels(); } } catch (Exception e) { return; } /** add the meta event listener */ sequencer.addMetaEventListener(this); }

/** * Close the sequencer. */ public void close() { /** if a sound is playing */ if (thread != null && startB != null) { /** stop playing */ startB.doClick(0); } /** if the sequencer is opened */ if (sequencer != null) { /** close it */ sequencer.close(); } }

/** * Loads all sound files ina directory. * @param name directory name */

Page 79: Bomber Man

public void loadFile(String name) { try { /** create the file object */ File file = new File(name); /** if the object is a directory */ if (file != null && file.isDirectory()) { /** get the list of files in the directory */ String files[] = file.list(); /** iterate through the list */ for (int i = 0; i < files.length; i++) { /** get the path */ File leafFile = new File(file.getAbsolutePath(), files[i]); /** if it's a directory */ if (leafFile.isDirectory()) { /** recurse into the directory */ loadFile(leafFile.getAbsolutePath()); } /** if it's a file */ else { /** load the file */ addSound(leafFile); } } } /** if the object is a file and it exists */ else if (file != null && file.exists()) { /** load the file */ addSound(file); } } catch (Exception e) { } }

/** * Attemps to add a sound file. * @param file file object to add */

Page 80: Bomber Man

private void addSound(File file) { String s = file.getName(); /** if the file has right extension */ if (s.endsWith(".au") || s.endsWith(".rmf") || s.endsWith(".mid") || s.endsWith(".wav") || s.endsWith(".aif") || s.endsWith(".aiff")) { /** add the file */ sounds.add(file); } }

/** * Loads a sound object. * @param object sound object to load */ public boolean loadSound(Object object) { /** if the object is a URL object */ if (object instanceof URL) { /** get the file name */ currentName = ((URL) object).getFile(); try { /** try to create an audio sound object */ currentSound = AudioSystem.getAudioInputStream((URL) object); } /** if it's not an audio sound object */ catch(Exception e) { try { /** try to create a midi sound object */ currentSound = MidiSystem.getSequence((URL) object); } /** if it's not a midi sound object neither */ catch (InvalidMidiDataException e1) { } catch (Exception e2) { } } }

Page 81: Bomber Man

/** if the object is a File object */ else if (object instanceof File) { /** get the file name */ currentName = ((File) object).getName(); try { /** try to create an audio sound object */ currentSound = AudioSystem.getAudioInputStream((File) object); } /** if it's not an audio sound object */ catch(Exception e) { /** load midi & rmf as inputstreams for now */ //try { //currentSound = MidiSystem.getSequence((File) object); //} catch (Exception e2) { try { /** open the file */ FileInputStream is = new FileInputStream((File) object); /** try to create a midi sound object */ currentSound = new BufferedInputStream(is, 1024); } catch (Exception e1) { } //} } }

/** if no sequencer available */ if (sequencer == null) { /** set sound object to null */ currentSound = null; /** and otta here */ return false; }

/** if the sound object is an AudioInputStream object */ if (currentSound instanceof AudioInputStream) { try { /** create the stream */

Page 82: Bomber Man

AudioInputStream stream = (AudioInputStream) currentSound; /** create the file format object */ AudioFormat format = stream.getFormat();

/** * we can't yet open the device for ALAW/ULAW playback, * convert ALAW/ULAW to PCM */ if ((format.getEncoding() == AudioFormat.Encoding.ULAW) || (format.getEncoding() == AudioFormat.Encoding.ALAW)) { /** setup the format */ AudioFormat tmp = new AudioFormat( AudioFormat.Encoding.PCM_SIGNED, format.getSampleRate(), format.getSampleSizeInBits() * 2, format.getChannels(), format.getFrameSize() * 2, format.getFrameRate(), true); /** open the stream with specified format */ stream = AudioSystem.getAudioInputStream(tmp, stream); /** store the formst for later use */ format = tmp; } /** create the line to play the sound */ DataLine.Info info = new DataLine.Info( Clip.class, stream.getFormat(), ((int) stream.getFrameLength() * format.getFrameSize()));

/** convert the sound into a clip */ Clip clip = (Clip) AudioSystem.getLine(info); clip.addLineListener(this); clip.open(stream); /** store the clip */ currentSound = clip; } catch (Exception e) { } } /** if the sound object is a sequence */ else if (currentSound instanceof Sequence || currentSound instanceof BufferedInputStream) { try { /** open the sequencer */ sequencer.open();

Page 83: Bomber Man

/** if the object is a sequence */ if (currentSound instanceof Sequence) { /** set the sequence to the sequencer */ sequencer.setSequence((Sequence) currentSound); } /** if the object is a buffered input stream */ else { /** set the stream to the sequencer */ sequencer.setSequence((BufferedInputStream) currentSound); } } catch (InvalidMidiDataException imde) { return false; } catch (Exception ex) { return false; } } /** otta here */ return true; }

/** * Plays the current sound object. */ public void playSound() { /** set volumn */ setGain(volumn); /** set pan */ setPan(); /** reset flags to false */ midiEOM = audioEOM = bump = false; /** if object is a sequencer */ if (currentSound instanceof Sequence || currentSound instanceof BufferedInputStream && thread != null) { /** play the sound */ sequencer.start(); /** iterate */ while (!midiEOM && thread != null && !bump) { try

Page 84: Bomber Man

{ thread.sleep(99); } catch (Exception e) { break; } } /** stop playing */ sequencer.stop(); /** close the sequencer */ sequencer.close(); } /** if the current sound object is a clip */ else if (currentSound instanceof Clip && thread != null) { /** get the clip */ Clip clip = (Clip) currentSound; /** play the clip */ clip.start(); try { thread.sleep(99); } catch (Exception e) { } /** iterate */ while ((paused || clip.isActive()) && thread != null && !bump) { try { thread.sleep(99); } catch (Exception e) { break; } } /** stop playing */ clip.stop(); /** close the clip */ clip.close(); } currentSound = null; }

Page 85: Bomber Man

/** * Must have method. * @param event line event */ public void update(LineEvent event) { if (event.getType() == LineEvent.Type.STOP && !paused) { audioEOM = true; } }

/** * Must have method. * @param message meta message */ public void meta(MetaMessage message) { /** 47 is end of track */ if (message.getType() == 47) { midiEOM = true; } }

/** * @return current thread */ public Thread getThread() { return thread; }

/** * Creates the thread and start it. */ public void start() { /** create the thread */ thread = new Thread(this); /** name the thread */ thread.setName("SoundPlayer"); /** start the thread */ thread.start(); }

Page 86: Bomber Man

/** * Stops then destroys the thread. */ public void stop() { /** if thread is alive */ if (thread != null) { /** destroy it */ thread.interrupt(); } /** set it to null */ thread = null; }

/** * Thread method. */ public void run() { /** iterate */ do { /** if the sound object exists */ if( loadSound(sounds.elementAt(num)) == true ) { /** play the sound */ playSound(); } } /** while loop is on and the thread isn't killed */ while (loop && thread != null);

/** if the thread isn't dead */ if (thread != null) { /** kill it */ startB.doClick(); } /** reste everything */ thread = null; currentName = null; currentSound = null; }

/**

Page 87: Bomber Man

* Set pan. */ public void setPan() { /** default value of 0: pan left / right evenly */ int value = 0; /** if the sound object is a clip */ if (currentSound instanceof Clip) { try { /** get the clip */ Clip clip = (Clip) currentSound; /** get the current pane value */ FloatControl panControl = (FloatControl) clip.getControl(FloatControl.Type.PAN); /** set the pan value */ panControl.setValue(value/100.0f); } catch (Exception ex) { } } /** if the sound object is a sequence */ else if (currentSound instanceof Sequence || currentSound instanceof BufferedInputStream) { /** iterate through all the channels */ for (int i = 0; i < channels.length; i++) { /** and set the pan values */ channels[i].controlChange(10, (int)(((double)value + 100.0) / 200.0 * 127.0)); } } }

/** * Set gain (volumn). * @param value volumn value */ public void setGain(double value) { /** if current sound object is a clip */ if (currentSound instanceof Clip) { try

Page 88: Bomber Man

{ /** get the clip */ Clip clip = (Clip) currentSound; /** get the current gain */ FloatControl gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN); /** create and calculate the gain value */ float dB = (float) (Math.log(value==0.0?0.0001:value)/Math.log(10.0)*20.0); /** set the gain value */ gainControl.setValue(dB); } catch (Exception ex) { } } /** if current sound object is a sequence */ else if (currentSound instanceof Sequence || currentSound instanceof BufferedInputStream) { /** iterate through all the channels */ for (int i = 0; i < channels.length; i++) { /** set gain */ channels[i].controlChange(7, (int)(value * 127.0)); } } }

/** * Set gain to 0. */ public void mute() { volumn = 0; setGain(volumn); /** pause the sound for a mili second */ bump = true; }

/** * Set gainto 100. */ public void unmute() { volumn = 100;

Page 89: Bomber Man

setGain(volumn); /** pause the sound for a mili second */ bump = true; }

/** * Change to different sound. * @param n new sound offset * @param l loop or not */ public void change(int n, boolean l) { paused = false; /** change text of pause button */ pauseB.setText("Pause"); /** get loop and offset */ loop = l; num = n; /** pause the sound for a mili second */ bump = true; /** if no sound is playing */ if (startB.getText().equals("Start")) /** play the sound */ startB.doClick(); }

/** * Play the current sound. */ public void controlPlay() { startB.doClick(); }

/** * Stop the current sound. */ public void controlStop() { startB.doClick(); }

/** * Play the previous sound. */ public void controlBack()

Page 90: Bomber Man

{ prevB.doClick(); }

/** * Play the next sound. */ public void controlNext() { nextB.doClick(); }

/** * Set buttons states. * @param state enabl or disable */ public void setComponentsEnabled(boolean state) { pauseB.setEnabled(state); prevB.setEnabled(state); nextB.setEnabled(state); }

/** * @return whether something is playing or not */ public boolean isPlaying() { return (startB.getText().equals("Start") ? false : true); }

/** * Action listener. * @param e action event */ public void actionPerformed(ActionEvent e) { /** get source of event */ JButton button = (JButton) e.getSource(); /** if the start button is clicked */ if (button.getText().equals("Start")) { /** not paused */ paused = false; /** if offset is out of range than set it to 0 */ num = num == -1 ? 0 : num; /** start playing */

Page 91: Bomber Man

start(); /** change button text to "Stop" */ button.setText("Stop"); /** change buttons states */ setComponentsEnabled(true); } /** if the stop button is clicked */ else if (button.getText().equals("Stop")) { /** not paused */ paused = false; /** stop playing */ stop(); /** change texts of buttons */ button.setText("Start"); pauseB.setText("Pause"); /** change buttons states */ setComponentsEnabled(false); } /** if the pause button is clicked */ else if (button.getText().equals("Pause")) { /** paused */ paused = true; /** if the sound object is a clip */ if (currentSound instanceof Clip) { /** stop the clip */ ((Clip) currentSound).stop(); } /** if the sound object is a sequence */ else if (currentSound instanceof Sequence || currentSound instanceof BufferedInputStream) { /** stop the sequence */ sequencer.stop(); } /** change the button text */ pauseB.setText("Resume"); } else if (button.getText().equals("Resume")) { /** not paused anymore */ paused = false; /** if sound is a clip */ if (currentSound instanceof Clip)

Page 92: Bomber Man

{ /** start the clip */ ((Clip) currentSound).start(); } /** if sound is a sequence */ else if (currentSound instanceof Sequence || currentSound instanceof BufferedInputStream) { /** start the sequence */ sequencer.start(); } /** change the button text */ pauseB.setText("Pause"); } /** if the back button is clicked */ else if (button.getText().equals("<<")) { paused = false; /** change button text */ pauseB.setText("Pause"); /** go to previous sound */ num = num-1 < 0 ? sounds.size()-1 : num-2; /** change sound */ bump = true; } /** if the next button is clicked */ else if (button.getText().equals(">>")) { paused = false; /** change button text */ pauseB.setText("Pause"); /** go to next sound */ num = num+1 == sounds.size() ? -1 : num; /** change sound */ bump = true; } }}