package example7_2.game; import java.awt.Color; import java.awt.Font; import java.awt.Toolkit; import java.util.ArrayList; import java.util.List; import javax.swing.JFrame; import javax.swing.JLabel; /** * This class implements a gameboard that contains GameCharacter. * @author hornick */ public class GameBoard extends JFrame { private static final long serialVersionUID = 1L; // needed if this class will be serializable private static JLabel timeRemainingLabel; // used display the time remaining in the game private static GameBoard board = null; // reference to the GameBoard (single) instance // Note: each cell in the grid is BOARDSIZE/GRIDSIZE pixels in width and height /*package*/ static GameGrid grid; // the individual cell locations comprising the board /*package*/ static final List characters = new ArrayList(); // all GameCharacter on the board /** * static method - allows only a single game board to be created * @param title window title */ /*package*/ static void createBoard(String title) { if( board==null ) // allow creation only once! new GameBoard(title); } /** * constructor - can only be called from this class itself * @param title window title */ private GameBoard(String title) { board = this; board.createUI(title); // create the user interface board.setVisible(true); // make it visible grid = new GameGrid(Game.GRIDSIZE); } /** * main UI JFrame initialization - size, title, layout, etc * @param title window title */ private void createUI(String title) { // create the containing window and set its size etc board.setTitle(title); // get the sizes of the window borders and title bar int titleHeight = (Integer)Toolkit.getDefaultToolkit().getDesktopProperty("win.frame.captionHeight"); int borderWidth = (Integer)Toolkit.getDefaultToolkit().getDesktopProperty("win.frame.sizingBorderWidth"); // adjust the window size based on the border and title bar sizes board.setSize(Game.BOARDSIZE+2*borderWidth, Game.BOARDSIZE+titleHeight+3*borderWidth); // initial window size board.setResizable(false); // disallow resizing board.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // terminate program on window close // Configure the content pane for absolute layout board.getContentPane().setLayout(null); board.getContentPane().setBackground(Color.WHITE); timeRemainingLabel = new JLabel("Time remaining: "); Font f = new Font("Arial", Font.BOLD, 14); timeRemainingLabel.setFont(f); timeRemainingLabel.setForeground(Color.RED); timeRemainingLabel.setBounds(10, 10, 170, 25); board.add(timeRemainingLabel); board.setVisible(true); } /** * Adds a GameCharacter's contained GameCharacterImage (a JComponent) to the JFrame's content pane. * @param gc reference to a GameCharacter object to be added to the content pane. * @note JFrames maintain in internal List of JComponent-derived elements, * which are automatically displayed whenever the JFrame needs to refresh * itself. Since GameCharacterImage is a JComponent, the GameCharacterImage is automatically * painted in the window. */ /*package*/ static void addCharacter( GameCharacter gc, int row, int col ) { characters.add(gc); board.getContentPane().add(gc.getImage()); // adds a GameCharacterImage to the content pane of this JFrame grid.addAt(gc, row, col); board.repaint(); // update the JFrame after the new GameCharacterImage is added } /*package*/ static void removeCharacter( GameCharacter gc ) { grid.remove(gc); // remove the character from the grid board.getContentPane().remove(gc.getImage()); // remove the image from the content pane characters.remove(gc); // and finally, remove it from the board board.repaint(); } /*package*/ static void displayTime(int time) { timeRemainingLabel.setText("Time remaining: "+time); } /** * This private inner class represents the grid of cells on the board. Each grid cell * is implemented as a List of GameCharacter; thus any cell can "hold" 0 or more GameCharacter */ /*package*/ static class GameGrid { private List[][] cells; // the board grid // ctor; creates the grid data structure (a square array of List's) private GameGrid(int size) { cells = new List[size][size]; // each cell in the array will contain the List of GameCharacters at that location for(int i=0; i(); // create the initially empty grid } } // Returns a List of GameCharacter at the specified grid row and column. // @throw IndexOutOfBounds if the row and column are invalid /*package*/ List getCharactersAt(int row, int col) { if( row<0 || row>=cells.length || col<0 || col>=cells.length) throw new IndexOutOfBoundsException("grid index out of bounds"); return cells[row][col]; } // Add a GameCharacter at the specified grid row and column. // @throw IndexOutOfBounds if the row and column are invalid // @return true if the GameCharacter was added, false if the GameCharacter was already there /*package*/ boolean addAt(GameCharacter gc, int row, int col) { if( row<0 || row>=cells.length || col<0 || col>=cells.length) throw new IndexOutOfBoundsException("grid index out of bounds"); List list = cells[row][col]; if( list.contains(gc)) { // is the GameCharacter already in that location? return false; // ...then indicate an error } else { // add it to the grid list.add(gc); return true; } } // Remove a GameCharacter from the specified grid row and column. // @throw IndexOutOfBounds if the row and column are invalid // @return true if the GameCharacter was removed, false if the GameCharacter was not there /*package*/ boolean removeAt(GameCharacter gc, int row, int col) { if( row<0 || row>=cells.length || col<0 || col>=cells.length) throw new IndexOutOfBoundsException("grid index out of bounds"); List list = cells[row][col]; if( list.contains(gc)) { // is the GameCharacter already in that location? list.remove(gc); // ...then remove it return true; } else { // no such element in the grid at that location return false; } } // Removes a GameCharacter from the grid. // @return true if the GameCharacter was removed, false if the GameCharacter was not there // Note: searches all cells in the grid and removes the specified GameCharacter from the any // cell where found. If the GameCharacter is referenced in multiple cells, all instances // will be removed. /*package*/ boolean remove(GameCharacter gc) { boolean wasRemoved = false; // initialize status flag to false (not removed) for(int i=0; i list = cells[i][j]; if( list.contains(gc)) { // is the GameCharacter already in that location? list.remove(gc); // ...then remove it wasRemoved = true; // ...and mark it removed } } } return wasRemoved; } } }