diff options
Diffstat (limited to 'src/tetris/gui')
-rw-r--r-- | src/tetris/gui/BoardUI.java | 110 | ||||
-rw-r--r-- | src/tetris/gui/ImagePanel.java | 70 | ||||
-rw-r--r-- | src/tetris/gui/InfoPanel.java | 212 | ||||
-rw-r--r-- | src/tetris/gui/NextPieceDisplay.java | 124 | ||||
-rw-r--r-- | src/tetris/gui/TetrisGUI.java | 252 | ||||
-rw-r--r-- | src/tetris/gui/TetrisPieceDisplay.java | 85 | ||||
-rw-r--r-- | src/tetris/gui/WrittenButton.java | 155 | ||||
-rw-r--r-- | src/tetris/gui/animations/Animation.java | 193 | ||||
-rw-r--r-- | src/tetris/gui/animations/TetrisPieceAnimation.java | 86 | ||||
-rw-r--r-- | src/tetris/gui/events/TetrisKeyListener.java | 69 | ||||
-rwxr-xr-x | src/tetris/gui/handwriting.ttf | bin | 0 -> 95576 bytes | |||
-rw-r--r-- | src/tetris/gui/images/ImageRes.java | 73 | ||||
-rw-r--r-- | src/tetris/gui/images/background.png | bin | 0 -> 386891 bytes | |||
-rw-r--r-- | src/tetris/gui/images/gameover.png | bin | 0 -> 9655 bytes | |||
-rw-r--r-- | src/tetris/gui/images/gameover_background.png | bin | 0 -> 537717 bytes | |||
-rw-r--r-- | src/tetris/gui/images/paused.png | bin | 0 -> 6142 bytes | |||
-rw-r--r-- | src/tetris/gui/images/square.png | bin | 0 -> 3689 bytes | |||
-rw-r--r-- | src/tetris/gui/images/writing_pencil.png | bin | 0 -> 20101 bytes |
18 files changed, 1429 insertions, 0 deletions
diff --git a/src/tetris/gui/BoardUI.java b/src/tetris/gui/BoardUI.java new file mode 100644 index 0000000..2bdfb6f --- /dev/null +++ b/src/tetris/gui/BoardUI.java @@ -0,0 +1,110 @@ +/* + * Jesse Morgan <jesterpm@u.washington.edu> + * + * TCSS 305 � Autumn 2009 + * Tetris Project + * 17 November 2009 + */ + +package tetris.gui; + +import java.awt.Graphics; +import java.awt.Image; +import java.util.Observable; + +import tetris.board.TetrisBoard; +import tetris.gui.images.ImageRes; + +/** + * Panel that draws the tetris board. + * + * @author Jesse Morgan <jesterpm@u.washington.edu> + * @version 1.0 23 November 2009 + */ +@SuppressWarnings("serial") +public class BoardUI extends TetrisPieceDisplay { + /** + * Flag to indicate game over. + */ + private boolean my_game_over; + + /** + * Flag to indicate game paused. + */ + private boolean my_game_paused; + + /** + * The Game Over graphic. + */ + private final Image my_gameover_graphic; + + /** + * The Paused graphic. + */ + private final Image my_paused_graphic; + + /** + * Constructor. + * + * @param the_width Number of columns. + * @param the_height Number of rows. + * + */ + public BoardUI(final int the_width, final int the_height) { + // Call parent + super(the_width, the_height); + + my_game_over = false; + my_game_paused = false; + + my_gameover_graphic = ImageRes.loadImage(ImageRes.GAME_OVER_LABEL); + + my_paused_graphic = ImageRes.loadImage(ImageRes.PAUSED_LABEL); + + } + + /** + * Update the board. + * + * @param the_observable The tetris board we receive updates for. + * @param the_argument Unused argument. + */ + public void update(final Observable the_observable, final Object the_argument) { + if (the_observable instanceof TetrisBoard) { + final TetrisBoard tb = (TetrisBoard) the_observable; + + my_bricks = tb.getTetrisBlocks(); + my_game_over = tb.isGameOver(); + my_game_paused = tb.isPaused(); + + repaint(); + } + + + } + + /** + * Paint Game Over or Paused if needed. + * + * @param the_graphics The Graphics to draw on (expected to be a Graphics2D). + */ + protected void paintComponent(final Graphics the_graphics) { + super.paintComponent(the_graphics); + + if (my_game_over) { + the_graphics.drawImage(my_gameover_graphic, + 0, + (getHeight() - my_gameover_graphic.getHeight(null)) / 2, + null); + + } else if (my_game_paused) { + the_graphics.drawImage(my_paused_graphic, + 0, + (getHeight() - my_paused_graphic.getHeight(null)) / 2, + null); + } + } + + + +} diff --git a/src/tetris/gui/ImagePanel.java b/src/tetris/gui/ImagePanel.java new file mode 100644 index 0000000..d558788 --- /dev/null +++ b/src/tetris/gui/ImagePanel.java @@ -0,0 +1,70 @@ +/* + * Jesse Morgan <jesterpm@u.washington.edu> + * + * TCSS 305 � Autumn 2009 + * Tetris Project + * 17 November 2009 + */ + +package tetris.gui; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Image; + +import javax.swing.JPanel; + +/** + * Custom panel that displays an image in the background. + * @author Jesse Morgan <jesterpm@u.washington.edu> + * @version 1.0 4 Dec 2009 + */ +@SuppressWarnings("serial") +public class ImagePanel extends JPanel { + /** + * The image that contains the background. + */ + private Image my_image; + + /** + * Constructor. Defaults to BorderLayout. + * @param the_image The background Image. + */ + public ImagePanel(final Image the_image) { + super(); + + setLayout(new BorderLayout()); + + my_image = the_image; + setPreferredSize(new Dimension(the_image.getWidth(null), the_image.getHeight(null))); + } + + /** + * @return the current background Image. + */ + public Image getBackgroundImage() { + return my_image; + } + + /** + * Set a new background Image. + * + * @param the_image the new Image. + */ + public void setBackgroundImage(final Image the_image) { + my_image = the_image; + setPreferredSize(new Dimension(the_image.getWidth(null), the_image.getHeight(null))); + } + + /** + * Draws the background image. + * + * @param the_graphics The Graphics Context. + */ + public void paintComponent(final Graphics the_graphics) { + setOpaque(false); + the_graphics.drawImage(my_image, 0, 0, null); + super.paintComponent(the_graphics); + } +}
\ No newline at end of file diff --git a/src/tetris/gui/InfoPanel.java b/src/tetris/gui/InfoPanel.java new file mode 100644 index 0000000..a3bdd8f --- /dev/null +++ b/src/tetris/gui/InfoPanel.java @@ -0,0 +1,212 @@ +/* + * Jesse Morgan <jesterpm@u.washington.edu> + * + * TCSS 305 - Autumn 2009 + * Tetris Project + * 17 November 2009 + */ + +package tetris.gui; + +import java.awt.Font; +import java.awt.FontFormatException; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.IOException; +import java.io.InputStream; +import java.util.Observable; +import java.util.Observer; + +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JLabel; +import javax.swing.JPanel; + +import tetris.board.TetrisBoard; + +/** + * JPanel of info about the game. + * + * @author Jesse Morgan <jesterpm@u.washington.edu> + * @version 1.0 11 December 2009 + */ +@SuppressWarnings("serial") +public class InfoPanel extends JPanel implements Observer { + // Private Constants + /** + * The wording of the new game button. + */ + private static final String NEWGAME_LABEL = "New Game"; + + /** + * The wording of the pause button. + */ + private static final String PAUSE_LABEL = "Pause"; + + /** + * The wording of the unpause button. + */ + private static final String UNPAUSE_LABEL = "Unpause"; + + // Obnoxious UI layout constants follow + /** + * Space between the top of the panel and the Score. + */ + private static final int UPPER_SPACING = 18; + + /** + * Space between the level and the next piece. + */ + private static final int MIDDLE_SPACING = 38; + + /** + * Size of the score. + */ + private static final float SCORE_FONT_SIZE = 32f; + + /** + * Size of the level. + */ + private static final float LEVEL_FONT_SIZE = 35f; + + /** + * The TetrisBoard we're displaying info for. + */ + private final TetrisBoard my_board; + + /** + * The score label. + */ + private final JLabel my_score_label; + + /** + * The level label. + */ + private final JLabel my_level_label; + + /** + * Construct the Info Panel. + * + * @param the_board The tetris board we belong to. + */ + public InfoPanel(final TetrisBoard the_board) { + super(); + + my_board = the_board; + the_board.addObserver(this); + + // Setup Panel + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + setOpaque(false); + + // Create Components + my_score_label = new JLabel("0"); + my_level_label = new JLabel("Level 1"); + + setupPanel(); + } + + /** + * Handle notifications. + * + * @param the_observable The TetrisBoard. + * @param the_arg Unused argument. + */ + public void update(final Observable the_observable, final Object the_arg) { + if (the_observable instanceof TetrisBoard) { + final TetrisBoard tb = (TetrisBoard) the_observable; + + my_score_label.setText(String.valueOf(tb.getScore())); + + my_level_label.setText("Level " + tb.getLevel()); + } + } + + + /** + * Helper method to setup the east side. + */ + private void setupPanel() { + Font base_font; + + // Load the font. + try { + final InputStream fis = getClass().getResourceAsStream("/tetris/gui/handwriting.ttf"); + base_font = Font.createFont(Font.TRUETYPE_FONT, fis); + fis.close(); + + } catch (final FontFormatException the_exception) { + base_font = Font.getFont(Font.SANS_SERIF); + + } catch (final IOException the_exception) { + base_font = Font.getFont(Font.SANS_SERIF); + } + + // Add a Strut to move everything onto a line. + add(Box.createVerticalStrut(UPPER_SPACING)); + + // Display the Score + my_score_label.setFont(base_font.deriveFont(SCORE_FONT_SIZE)); + my_score_label.setAlignmentX(CENTER_ALIGNMENT); + add(my_score_label); + + + // Display the level + my_level_label.setFont(base_font.deriveFont(LEVEL_FONT_SIZE)); + my_level_label.setAlignmentX(CENTER_ALIGNMENT); + add(my_level_label); + + // Add a bit of space between the level and the next piece display. + add(Box.createVerticalStrut(MIDDLE_SPACING)); + + // Add the next piece component + final NextPieceDisplay nextpiece = new NextPieceDisplay(); + add(nextpiece); + nextpiece.setAlignmentX(CENTER_ALIGNMENT); + my_board.addObserver(nextpiece); + + + + // New Game Button + final WrittenButton new_game = new WrittenButton(); + new_game.setText(NEWGAME_LABEL); + new_game.setAlignmentX(CENTER_ALIGNMENT); + add(new_game); + + // Pause Game Button + final WrittenButton pause_game = new WrittenButton(); + pause_game.setText(PAUSE_LABEL); + pause_game.setAlignmentX(CENTER_ALIGNMENT); + add(pause_game); + + // Setup Action Listeners + + // New Game + new_game.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent the_event) { + my_board.newGame(); + } + }); + + // Pause Game + pause_game.addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent the_event) { + final WrittenButton b = (WrittenButton) the_event.getSource(); + + // Do nothing if the game is over. + if (my_board.isGameOver()) { + return; + } + + if (b.getText().equals(PAUSE_LABEL)) { + my_board.setPaused(true); + b.setText(UNPAUSE_LABEL); + + } else { + my_board.setPaused(false); + b.setText(PAUSE_LABEL); + } + } + }); + } +} diff --git a/src/tetris/gui/NextPieceDisplay.java b/src/tetris/gui/NextPieceDisplay.java new file mode 100644 index 0000000..4f0f543 --- /dev/null +++ b/src/tetris/gui/NextPieceDisplay.java @@ -0,0 +1,124 @@ +/* + * Jesse Morgan <jesterpm@u.washington.edu> + * + * TCSS 305 � Autumn 2009 + * Tetris Project + * 17 November 2009 + */ + +package tetris.gui; + +import java.awt.Graphics; +import java.awt.Image; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.Observable; + +import javax.swing.Timer; + +import tetris.board.TetrisBoard; +import tetris.gui.animations.TetrisPieceAnimation; +import tetris.gui.images.ImageRes; +import tetris.model.IntPoint; +import tetris.piece.TPiece; +import tetris.piece.TetrisPiece; + +/** + * Panel that draws the tetris board. + * + * @author Jesse Morgan <jesterpm@u.washington.edu> + * @version 1.0 1 Dec 2009 + */ +@SuppressWarnings("serial") +public class NextPieceDisplay extends TetrisPieceDisplay { + /** + * The Pencil Graphic. + */ + private static final Image PENCIL = ImageRes.loadImage(ImageRes.WRITING_PENCIL); + + + /** + * The next piece. + */ + private TetrisPiece my_next_piece; + + /** + * Our animator. + */ + private TetrisPieceAnimation my_animation; + + /** + * Animation timer. + */ + private final Timer my_timer; + + + /** + * Constructor. + */ + public NextPieceDisplay() { + // Call parent + super(TetrisPiece.TETRIS_PIECE_SIZE, TetrisPiece.TETRIS_PIECE_SIZE); + + my_animation = new TetrisPieceAnimation(new TPiece(0, 0)); + + my_timer = new Timer(TetrisPieceAnimation.FRAME_RATE, new ActionListener() { + public void actionPerformed(final ActionEvent the_event) { + my_animation.stepAnimation(); + repaint(); + } + }); + } + + /** + * Update the next piece display. + * + * @param the_observable The tetris board we receive updates for. + * @param the_argument Unused argument. + */ + public void update(final Observable the_observable, final Object the_argument) { + if (the_observable instanceof TetrisBoard) { + final TetrisBoard tb = (TetrisBoard) the_observable; + + // If the next piece we know about is not the same next piece... + if (tb.getNextPiece() != my_next_piece) { + my_next_piece = tb.getNextPiece(); + my_bricks.clear(); + + for (IntPoint p : my_next_piece.getBoardCoordinates()) { + my_bricks.add(new IntPoint(p.getX() - my_next_piece.getX(), + p.getY() - my_next_piece.getY() + + TetrisBoard.NEW_PIECE_BUFFER)); + } + + my_animation = new TetrisPieceAnimation(my_next_piece); + startAnimation(); + } + + repaint(); + } + } + + @Override + protected void paintComponent(final Graphics the_graphics) { + super.paintComponent(the_graphics); + + if (my_animation.isRunning()) { + final int x = my_animation.getX(); + final int y = my_animation.getY() - PENCIL.getHeight(null); + the_graphics.drawImage(PENCIL, x, y, null); + // Normally you'd draw the animation image here, but we just want the pencil to move. + } + } + + /** + * Start the animation and timer. + */ + private void startAnimation() { + my_animation.start(); + my_timer.start(); + } + + + +} diff --git a/src/tetris/gui/TetrisGUI.java b/src/tetris/gui/TetrisGUI.java new file mode 100644 index 0000000..fd463a8 --- /dev/null +++ b/src/tetris/gui/TetrisGUI.java @@ -0,0 +1,252 @@ +/* + * Jesse Morgan <jesterpm@u.washington.edu> + * + * TCSS 305 - Autumn 2009 + * Tetris Project + * 17 November 2009 + */ + +package tetris.gui; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.Observable; +import java.util.Observer; + +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.Timer; + +import tetris.audio.TetrisSounds; +import tetris.board.TetrisBoard; +import tetris.board.TetrisBoardEvent; +import tetris.gui.events.TetrisKeyListener; +import tetris.gui.images.ImageRes; + +/** + * Tetris UI Main Frame. + * + * @author Jesse Morgan <jesterpm@u.washington.edu> + * @version 1.0 23 November 2009 + */ +@SuppressWarnings("serial") +public class TetrisGUI extends JFrame implements Observer { + /** + * UI Padding at the top of the frame. + */ + private static final int NORTH_PADDING = 100; + + /** + * UI Padding on the west side of the frame. + */ + private static final int WEST_PADDING = 75; + + /** + * The TetrisBoard we're playing on. + */ + private final TetrisBoard my_board; + + /** + * The gameplay timer. + */ + private Timer my_timer; + + /** + * Stores the background image panel. + */ + private final ImagePanel my_background_panel; + + /** + * Constructor for the tetris UI. + */ + public TetrisGUI() { + super("TCSS 305 Tetris"); + + // Setup Global UI Elements + my_background_panel = new ImagePanel(ImageRes.loadImage(ImageRes.GAME_BACKGROUND)); + add(my_background_panel); + + // Create the board. + my_board = new TetrisBoard(TetrisBoard.STANDARD_BOARD_WIDTH, + TetrisBoard.STANDARD_BOARD_HEIGHT); + + // We Observe the Board. + my_board.addObserver(this); + + // Add a board UI + final BoardUI board_ui = new BoardUI(TetrisBoard.STANDARD_BOARD_WIDTH, + TetrisBoard.STANDARD_BOARD_HEIGHT); + my_background_panel.add(board_ui, BorderLayout.CENTER); + + my_board.addObserver(board_ui); + + // Add an InfoPanel + final InfoPanel info = new InfoPanel(my_board); + my_background_panel.add(info, BorderLayout.EAST); + + // Create a tetris sound player + final TetrisSounds ts = new TetrisSounds(); + my_board.addObserver(ts); + + setupFrame(); + setupUIPadding(); + setupListeners(); + } + + /** + * Start the game. + */ + public void start() { + my_board.setPaused(false); + my_timer.start(); + } + + /** + * Pause the game. + */ + public void pause() { + my_board.setPaused(true); + my_timer.stop(); + } + + /** + * Update the level and score. + * + * @param the_observable Should be an instance of TetrisBoard + * @param the_arg Unused by this method. + */ + public void update(final Observable the_observable, final Object the_arg) { + if (the_observable instanceof TetrisBoard) { + final TetrisBoard tb = (TetrisBoard) the_observable; + final TetrisBoardEvent event = (TetrisBoardEvent) the_arg; + + switch (event.getType()) { + case NEW_GAME: + my_background_panel.setBackgroundImage(ImageRes.loadImage(ImageRes.GAME_BACKGROUND)); + repaint(); + start(); + // Purposefully falling through.... + + case SCORE_CHANGED: + my_timer.setDelay(tb.getSpeed()); + break; + + case GAME_OVER: + my_background_panel.setBackgroundImage(ImageRes. + loadImage(ImageRes.GAMEOVER_BACKGROUND)); + repaint(); + break; + + default: + } + } + } + + /** + * Game Entry Point. + * + * @param the_args Unused command line arguments. + */ + public static void main(final String[] the_args) { + final TetrisGUI ui = new TetrisGUI(); + + ui.setVisible(true); + } + + /** + * Helper method to setup various frame attributes. + */ + private void setupFrame() { + // Set frame attributes + setSize(my_background_panel.getPreferredSize()); + setResizable(false); + setDefaultCloseOperation(EXIT_ON_CLOSE); + } + + /** + * Helper method to setup the padding on the UI. + */ + private void setupUIPadding() { + // North Side + final JPanel north_panel = new JPanel(); + north_panel.setOpaque(false); + north_panel.setPreferredSize(new Dimension(0, NORTH_PADDING)); + + // West Side + final JPanel west_panel = new JPanel(); + west_panel.setOpaque(false); + west_panel.setPreferredSize(new Dimension(WEST_PADDING, 0)); + + my_background_panel.add(north_panel, BorderLayout.NORTH); + my_background_panel.add(west_panel, BorderLayout.WEST); + } + + /** + * Helper methods to setup event listeners. + */ + private void setupListeners() { + // Add Key Listener + addKeyListener(new TetrisKeyListener(my_board)); + + // Add Window Listener + addWindowListener(new TetrisWindowListener()); + + // Add a timer + my_timer = new Timer(my_board.getSpeed(), new ActionListener() { + public void actionPerformed(final ActionEvent the_event) { + my_board.progressBoard(); + } + }); + } + + /** + * Starts and stops the timer based off of WindowEvents. + * + * @author Jesse Morgan <jesterpm@u.washington.edu> + * @version 1.0 1 Dec 2009 + */ + private class TetrisWindowListener extends WindowAdapter { + /** + * Flag to store if we lost focus. + */ + private boolean my_lost_focus_flag; + + /** + * Create the TetrisWindowListener. + */ + public TetrisWindowListener() { + super(); + my_lost_focus_flag = false; + } + + @Override + public void windowActivated(final WindowEvent the_event) { + super.windowActivated(the_event); + if (my_lost_focus_flag && my_board.isPaused()) { + start(); + my_lost_focus_flag = false; + } + } + + @Override + public void windowClosed(final WindowEvent the_event) { + super.windowClosed(the_event); + pause(); + } + + @Override + public void windowDeactivated(final WindowEvent the_event) { + super.windowDeactivated(the_event); + + // Don't pause if we're already paused. + if (!my_board.isPaused()) { + my_lost_focus_flag = true; + pause(); + } + } + } +} diff --git a/src/tetris/gui/TetrisPieceDisplay.java b/src/tetris/gui/TetrisPieceDisplay.java new file mode 100644 index 0000000..409942c --- /dev/null +++ b/src/tetris/gui/TetrisPieceDisplay.java @@ -0,0 +1,85 @@ +/* + * Jesse Morgan <jesterpm@u.washington.edu> + * + * TCSS 305 � Autumn 2009 + * Tetris Project + * 17 November 2009 + */ + +package tetris.gui; + +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Image; +import java.util.ArrayList; +import java.util.List; +import java.util.Observer; + +import javax.swing.JPanel; + +import tetris.board.TetrisBoard; +import tetris.gui.images.ImageRes; +import tetris.model.IntPoint; + +/** + * Abstract component capable of drawing out tetris pieces. + * + * @author Jesse Morgan <jesse@jesterpm.net> + * @version 1.0 1 Dec 2009 + */ +@SuppressWarnings("serial") +public abstract class TetrisPieceDisplay extends JPanel implements Observer { + // Private contants + /** + * Pixel size of one tetris piece. + */ + private static final int BRICK_SIZE = 27; + + //Private fields + /** + * List of the bricks on the screen. + */ + protected List<IntPoint> my_bricks; + + /** + * Storage for the brick image. + */ + private final Image my_brick_image; + + /** + * Constructor. + * + * @param the_width Number of columns. + * @param the_height Number of rows. + */ + public TetrisPieceDisplay(final int the_width, final int the_height) { + // Call parent + super(); + + // Load brick image + my_brick_image = ImageRes.loadImage(ImageRes.TETRIS_BLOCK); + + // Create our brick list + my_bricks = new ArrayList<IntPoint>(); + + // Set some hints for the layout manager + final Dimension d = new Dimension(the_width * my_brick_image.getWidth(null), + the_height * my_brick_image.getHeight(null)); + setPreferredSize(d); + setMinimumSize(d); + setMaximumSize(d); + setOpaque(false); + } + + @Override + protected void paintComponent(final Graphics the_graphics) { + super.paintComponent(the_graphics); + + for (IntPoint brick : my_bricks) { + the_graphics.drawImage(my_brick_image, + brick.getX() * BRICK_SIZE, + (brick.getY() - TetrisBoard.NEW_PIECE_BUFFER) * BRICK_SIZE, + null); + } + } +} diff --git a/src/tetris/gui/WrittenButton.java b/src/tetris/gui/WrittenButton.java new file mode 100644 index 0000000..2a0e55f --- /dev/null +++ b/src/tetris/gui/WrittenButton.java @@ -0,0 +1,155 @@ +package tetris.gui; + +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontFormatException; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.event.ActionEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.IOException; +import java.io.InputStream; + +import javax.swing.AbstractButton; +import javax.swing.JLabel; + +import tetris.gui.images.ImageRes; + +/** + * WrittenButton is a button with a handwritten font and a pencil roll-over. + * + * @author Jesse Morgan <jesterpm@u.washington.edu> + * @version 1.0 8 December 2009. + */ +@SuppressWarnings("serial") +public class WrittenButton extends AbstractButton { + /** + * The pencil icon used in the roll-over. + */ + private static final Image PENCIL = ImageRes.loadImage(ImageRes.WRITING_PENCIL); + + /** + * Default font size. + */ + private static final float DEFAULT_FONT_SIZE = 36; + + /** + * How much pencil to show. + */ + private static final int PENCIL_WIDTH = 50; + + /** + * An adjustment to the Y of the pencil. + */ + private static final int PENCIL_ADJUSTMENT = 10; + + /** + * The button label. + */ + private final JLabel my_label; + + /** + * Is the mouse over the button? + */ + private boolean my_rolledover; + + /** + * Default constrcutor. + */ + public WrittenButton() { + super(); + + my_rolledover = false; + + // Setup Button + addMouseListener(new MouseHandler()); + setOpaque(false); + + // Setup Label + my_label = new JLabel(); + add(my_label); + } + + @Override + public void setText(final String the_label) { + super.setText(the_label); + + Font base_font; + + try { + final InputStream fis = getClass().getResourceAsStream("/tetris/gui/handwriting.ttf"); + base_font = Font.createFont(Font.TRUETYPE_FONT, fis); + fis.close(); + + } catch (final FontFormatException the_exception) { + base_font = Font.getFont(Font.SANS_SERIF); + + } catch (final IOException the_exception) { + base_font = Font.getFont(Font.SANS_SERIF); + } + + my_label.setText(the_label); + my_label.setFont(base_font.deriveFont(DEFAULT_FONT_SIZE)); + + // Set some hints for the layout manager. + final Dimension ls = my_label.getPreferredSize(); + ls.width += PENCIL_WIDTH; + setPreferredSize(ls); + setMinimumSize(ls); + setMaximumSize(ls); + } + + @Override + public String getText() { + return my_label.getText(); + } + + @Override + protected void paintComponent(final Graphics the_graphics) { + super.paintComponent(the_graphics); + + if (my_rolledover) { + final int x = my_label.getX() + my_label.getWidth(); + final int y = my_label.getY() + my_label.getHeight() - + PENCIL.getHeight(null) - PENCIL_ADJUSTMENT; + + the_graphics.drawImage(PENCIL, x, y, null); + } + } + + /** + * Mouse handler for the button. + * + * @author Jesse Morgan <jesterpm@u.washington.edu> + * @version 1.0 8 Dec 2009 + */ + private class MouseHandler extends MouseAdapter { + @Override + public void mouseEntered(final MouseEvent the_event) { + super.mouseEntered(the_event); + + my_rolledover = true; + repaint(); + } + + @Override + public void mouseExited(final MouseEvent the_event) { + super.mouseExited(the_event); + + my_rolledover = false; + repaint(); + } + + @Override + public void mouseClicked(final MouseEvent the_event) { + super.mouseClicked(the_event); + + final ActionEvent e = new ActionEvent(WrittenButton.this, + ActionEvent.ACTION_PERFORMED, + getText()); + + WrittenButton.this.fireActionPerformed(e); + } + } +} diff --git a/src/tetris/gui/animations/Animation.java b/src/tetris/gui/animations/Animation.java new file mode 100644 index 0000000..899459d --- /dev/null +++ b/src/tetris/gui/animations/Animation.java @@ -0,0 +1,193 @@ +/* + * Jesse Morgan <jesterpm@u.washington.edu> + * + * TCSS 305 - Autumn 2009 + * Tetris Project + * 17 November 2009 + */ + +package tetris.gui.animations; + +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.image.BufferedImage; + +import tetris.model.IntPoint; + + +/** + * Abstract class that processes animations. + * + * @author Jesse Morgan <jesterpm@u.washington.edu> + * @version 1.0 11 Dec 2009 + */ +public abstract class Animation { + // Public Constants + /** + * How quickly animation should be updated. + */ + public static final int FRAME_RATE = 60; + + // Private Constants + /** + * How much we show in each step. + */ + private static final int R = 5; + + /** + * The current step in the animation. + */ + private int my_step; + + /** + * The current position in the animation. + */ + private IntPoint my_current_pos; + + /** + * Current Step Point. + */ + private IntPoint my_step_point; + + /** + * Animation Running Flag. + */ + private boolean my_animation_running; + + /** + * What the animation presently looks like. + */ + private final BufferedImage my_image; + + /** + * What the animation will look like. + */ + private final Image my_end_image; + + /** + * Create a new animation. + * + * @param the_end_image End result. + * @param the_width Animation width. + * @param the_height Animation height. + */ + public Animation(final Image the_end_image, final int the_width, final int the_height) { + my_step = 0; + my_animation_running = false; + + my_current_pos = new IntPoint(0, 0); + my_step_point = new IntPoint(0, 0); + + my_end_image = the_end_image; + my_image = new BufferedImage(the_width, the_height, + BufferedImage.TYPE_INT_ARGB); + + } + + /** + * Start the animation. + */ + public void start() { + my_step = 0; + + my_current_pos = getStep(0); + my_step_point = getStep(0); + + my_animation_running = true; + } + + /** + * Stop the animation. + */ + public void stop() { + my_animation_running = false; + } + + /** + * @return true if the animation is running. + */ + public boolean isRunning() { + return my_animation_running; + } + + /** + * Draw the next increment of the animation. + */ + public void stepAnimation() { + // If we're near our destination, move to the next step. + if ( + Math.abs(my_current_pos.getX() - my_step_point.getX()) < R && + Math.abs(my_current_pos.getY() - my_step_point.getY()) < R + ) { + // If we're out of steps, stop. + if (my_step >= stepCount() - 1) { + my_animation_running = false; + return; + } + + my_step++; + my_step_point = getStep(my_step); + } + + // Draw! + final Graphics2D g2d = my_image.createGraphics(); + + g2d.drawImage(my_end_image, + my_current_pos.getX(), my_current_pos.getY(), + my_current_pos.getX() + R, my_current_pos.getY() + R, + + my_current_pos.getX() % my_end_image.getWidth(null), + my_current_pos.getY() % my_end_image.getHeight(null), + (my_current_pos.getX() + R) % my_end_image.getWidth(null), + (my_current_pos.getY() + R) % my_end_image.getHeight(null), + null); + + // Some math to draw in the correct "direction" + final int x = my_step_point.getX() - my_current_pos.getX(); + final int y = my_step_point.getY() - my_current_pos.getY(); + double theta = Math.asin(y / Math.sqrt(x * x + y * y)); + + // Correction if we're moving toward the Y axis. + if (x < 0) { + theta = -theta + Math.PI; + } + + // Calculate the next point + my_current_pos = new IntPoint((int) (my_current_pos.getX() + R * Math.cos(theta)), + (int) (my_current_pos.getY() + R * Math.sin(theta))); + + } + + /** + * @return the image of the current animation. + */ + public Image getImage() { + return my_image; + } + + /** + * @return the current X in the animation. + */ + public int getX() { + return my_current_pos.getX(); + } + + /** + * @return the current Y in the animation. + */ + public int getY() { + return my_current_pos.getY(); + } + + /** + * Returns the point at the given step. + * @param the_step The Step. + * @return the Point. + */ + protected abstract IntPoint getStep(final int the_step); + + /** + * @return the number of steps in the animation. + */ + protected abstract int stepCount(); +} diff --git a/src/tetris/gui/animations/TetrisPieceAnimation.java b/src/tetris/gui/animations/TetrisPieceAnimation.java new file mode 100644 index 0000000..b503c88 --- /dev/null +++ b/src/tetris/gui/animations/TetrisPieceAnimation.java @@ -0,0 +1,86 @@ +/* + * Jesse Morgan <jesterpm@u.washington.edu> + * + * TCSS 305 - Autumn 2009 + * Tetris Project + * 17 November 2009 + */ + +package tetris.gui.animations; + +import tetris.gui.images.ImageRes; +import tetris.model.IntPoint; +import tetris.piece.TetrisPiece; + +/** + * Animation that knows how to animate a tetris piece. + * + * @author Jesse Morgan <jesterpm@u.washington.edu> + * @version 1.0 11 December 2009 + */ +public class TetrisPieceAnimation extends Animation { + /** + * Size of a brick. + */ + private static final int BRICK_SIZE = 30; + + + /** + * Size of the animation area. + */ + private static final int ANIMATION_SIZE = BRICK_SIZE * 4; + + /** + * The steps of a brick animation. + */ + private static final IntPoint[] STEPS = { + new IntPoint(0, 0), + new IntPoint(26, 0), + new IntPoint(26, 26), + new IntPoint(0, 26), + new IntPoint(0, 0), + + new IntPoint(8, 0), + new IntPoint(0, 8), + new IntPoint(3, 8), + new IntPoint(16, 2), + new IntPoint(4, 20), + new IntPoint(20, 4), + new IntPoint(12, 20), + new IntPoint(24, 14), + new IntPoint(24, 20), + new IntPoint(20, 26), + }; + + /** + * A list of tetris piece points. + */ + private final IntPoint[] my_bricks; + + /** + * Animate the drawing of a tetris piece. + * + * @param the_piece the piece to draw. + */ + public TetrisPieceAnimation(final TetrisPiece the_piece) { + super(ImageRes.loadImage(ImageRes.TETRIS_BLOCK), ANIMATION_SIZE, ANIMATION_SIZE); + + my_bricks = the_piece.translate(-the_piece.getX(), + -the_piece.getY()).getBoardCoordinates(); + } + + @Override + protected IntPoint getStep(final int the_step) { + final IntPoint ani_step = STEPS[the_step % STEPS.length]; + final int brick = the_step / STEPS.length; + + return new IntPoint(ani_step.getX() + my_bricks[brick].getX() * BRICK_SIZE, + ani_step.getY() + my_bricks[brick].getY() * BRICK_SIZE); + } + + @Override + protected int stepCount() { + return my_bricks.length * STEPS.length; + } + +} diff --git a/src/tetris/gui/events/TetrisKeyListener.java b/src/tetris/gui/events/TetrisKeyListener.java new file mode 100644 index 0000000..10b999e --- /dev/null +++ b/src/tetris/gui/events/TetrisKeyListener.java @@ -0,0 +1,69 @@ +/* + * Jesse Morgan <jesterpm@u.washington.edu> + * + * TCSS 305 � Autumn 2009 + * Tetris Project + * 17 November 2009 + */ + +package tetris.gui.events; + +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; + +import tetris.board.TetrisBoard; + +/** + * Keyboard Input handler for Tetris board. + * + * @author Jesse Morgan <jesterpm@u.washington.edu> + * @version 1.0 30 Nov 2009 + */ +public class TetrisKeyListener extends KeyAdapter { + /** + * The tetris board we update. + */ + + private final TetrisBoard my_board; + + /** + * Constructor. + * + * @param the_board The board to update. + */ + public TetrisKeyListener(final TetrisBoard the_board) { + super(); + + my_board = the_board; + } + + @Override + public void keyPressed(final KeyEvent the_event) { + super.keyPressed(the_event); + + switch (the_event.getKeyCode()) { + case KeyEvent.VK_LEFT: + my_board.moveLeft(); + break; + + case KeyEvent.VK_RIGHT: + my_board.moveRight(); + break; + + case KeyEvent.VK_UP: + my_board.rotateRight(); + break; + + case KeyEvent.VK_DOWN: + my_board.moveDown(); + break; + + case KeyEvent.VK_SPACE: + my_board.dropPiece(); + break; + + default: + } + } + +} diff --git a/src/tetris/gui/handwriting.ttf b/src/tetris/gui/handwriting.ttf Binary files differnew file mode 100755 index 0000000..a70b0fc --- /dev/null +++ b/src/tetris/gui/handwriting.ttf diff --git a/src/tetris/gui/images/ImageRes.java b/src/tetris/gui/images/ImageRes.java new file mode 100644 index 0000000..ba44104 --- /dev/null +++ b/src/tetris/gui/images/ImageRes.java @@ -0,0 +1,73 @@ +/* + * Jesse Morgan <jesterpm@u.washington.edu> + * + * TCSS 305 - Autumn 2009 + * Tetris Project + * 17 November 2009 + */ + +package tetris.gui.images; + +import java.awt.Image; +import java.io.IOException; + +import javax.imageio.ImageIO; + +/** + * Enumeration of the various image resources. + * + * @author Jesse Morgan <jesterpm@u.washington.edu> + * @version 1.0 23 November 2009 + */ +public final class ImageRes { + /** + * Game board background image. + */ + public static final String GAME_BACKGROUND = "background.png"; + + /** + * Game over board background image. + */ + public static final String GAMEOVER_BACKGROUND = "gameover_background.png"; + + /** + * Tetris block. + */ + public static final String TETRIS_BLOCK = "square.png"; + + /** + * Game Over wording. + */ + public static final String GAME_OVER_LABEL = "gameover.png"; + + /** + * Game Over wording. + */ + public static final String PAUSED_LABEL = "paused.png"; + + /** + * Writing Pencil. + */ + public static final String WRITING_PENCIL = "writing_pencil.png"; + + /** + * You're not allowed to create an instance of this class. + */ + private ImageRes() { } + + /** + * Utility to handle loading an image. + * + * @param the_file The filename we need to load. + * @return The loaded Image or null if the image can't be loaded. + */ + public static Image loadImage(final String the_file) { + try { + return ImageIO.read(ImageRes.class. + getResourceAsStream(the_file)); + + } catch (final IOException the_exception) { + return null; + } + } +} diff --git a/src/tetris/gui/images/background.png b/src/tetris/gui/images/background.png Binary files differnew file mode 100644 index 0000000..39b58bf --- /dev/null +++ b/src/tetris/gui/images/background.png diff --git a/src/tetris/gui/images/gameover.png b/src/tetris/gui/images/gameover.png Binary files differnew file mode 100644 index 0000000..f8c6c48 --- /dev/null +++ b/src/tetris/gui/images/gameover.png diff --git a/src/tetris/gui/images/gameover_background.png b/src/tetris/gui/images/gameover_background.png Binary files differnew file mode 100644 index 0000000..25b7cd5 --- /dev/null +++ b/src/tetris/gui/images/gameover_background.png diff --git a/src/tetris/gui/images/paused.png b/src/tetris/gui/images/paused.png Binary files differnew file mode 100644 index 0000000..3d26abe --- /dev/null +++ b/src/tetris/gui/images/paused.png diff --git a/src/tetris/gui/images/square.png b/src/tetris/gui/images/square.png Binary files differnew file mode 100644 index 0000000..75fc613 --- /dev/null +++ b/src/tetris/gui/images/square.png diff --git a/src/tetris/gui/images/writing_pencil.png b/src/tetris/gui/images/writing_pencil.png Binary files differnew file mode 100644 index 0000000..f4250de --- /dev/null +++ b/src/tetris/gui/images/writing_pencil.png |