Package gwt.g2d.client.demo.tetris

Source Code of gwt.g2d.client.demo.tetris.Tetris$TetrisRenderer

/*
* Copyright 2009 Hao Nguyen
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package gwt.g2d.client.demo.tetris;

import gwt.g2d.client.graphics.KnownColor;
import gwt.g2d.client.graphics.LinearGradient;
import gwt.g2d.client.graphics.Surface;
import gwt.g2d.client.math.Rectangle;
import gwt.g2d.client.math.Vector2;
import gwt.g2d.client.util.Cycle;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DockPanel;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.Widget;

/**
* A game of tetris.
*
* @author hao1300@gmail.com
*/
public class Tetris {
  private static final int DEFAULT_NUM_ROWS = 20, DEFAULT_NUM_COLS = 10;
  private static final int BLOCK_PIXEL_SIZE = 24;
  private static final int DEFAULT_START_ROW = 0,
      DEFAULT_START_COL = DEFAULT_NUM_COLS / 2 - Piece.PIECE_SIZE / 2;
  private static final int ROWS_CLEARED_PER_LEVEL = 30;
 
  private final TetrisRenderer renderer = new TetrisRenderer();
  private final Surface nextPieceSurface = new Surface(Piece.PIECE_SIZE * BLOCK_PIXEL_SIZE,
      Piece.PIECE_SIZE * BLOCK_PIXEL_SIZE);
  private final Label levelLabel = new Label();
  private final Label rowsClearedLabel = new Label();
  private final Panel parentContainer;
 
  private Surface surface;
  private int currRow, currCol;
  private Piece currPiece, nextPiece;
  private TetrisMatrix matrix;
  private Cycle cycle;
  private int level;
  private int totalRowsCleared;
  private int levelOffset = 0;
  private boolean needRedraw = true, needRedrawNextPiece = true;
 
  public Tetris(int startingLevel, Panel parentContainer) {
    surface = new Surface(DEFAULT_NUM_COLS * BLOCK_PIXEL_SIZE,
        DEFAULT_NUM_ROWS * BLOCK_PIXEL_SIZE);
    this.parentContainer = parentContainer;
    matrix = new TetrisMatrix(DEFAULT_NUM_ROWS, DEFAULT_NUM_COLS);
    this.levelOffset = startingLevel;
    setLevel(startingLevel);
    setTotalRowsCleared(0);
    nextPiece = new Piece();
  }
 
  public void initialize() {   
    DockPanel panel = new DockPanel();
    parentContainer.add(panel);
    panel.add(surface, DockPanel.LINE_START);
    final Button resetButton = new Button("Reset", new ClickHandler() {
      @Override
      public void onClick(ClickEvent event) {
        currPiece = null;
        nextPiece = new Piece();
        matrix = new TetrisMatrix(DEFAULT_NUM_ROWS, DEFAULT_NUM_COLS);
        setLevel(getLevelFromRowsCleared());
        setTotalRowsCleared(0);
        surface.setFocus(true);
      }
    });
    Button previousLevelButton = new Button("Previous level", new ClickHandler() {
      @Override
      public void onClick(ClickEvent event) {
        levelOffset = Math.max(1, levelOffset - 1);
        resetButton.click();
      }
    });
    Button nextLevelButton = new Button("Next level", new ClickHandler() {
      @Override
      public void onClick(ClickEvent event) {
        levelOffset++;
        resetButton.click();
      }
    });
   
    Panel nextPiecePanel = createPanel(
        createPanel(createHeaderLabel("Next Piece"), nextPieceSurface),
        createPanel(createHeaderLabel("Lines Cleared"), rowsClearedLabel),
        createPanel(createHeaderLabel("Level"), levelLabel),
        createPanel(resetButton),
        createPanel(previousLevelButton),
        createPanel(nextLevelButton));
    nextPiecePanel.setStyleName("sidePanel");
    nextPiecePanel.setHeight(surface.getHeight() + "px");
    panel.add(nextPiecePanel, DockPanel.LINE_END);
   
    nextPieceSurface.fillBackground(KnownColor.BLACK);
   
    surface.setFocus(true);
    surface.fillBackground(KnownColor.BLACK);
   
    initializeKeyHandlers();
  }

  public void update() {
    if (currPiece == null) {
      currPiece = nextPiece;
      nextPiece = new Piece();
      drawNextPiece();
      currRow = DEFAULT_START_ROW;
      currCol = DEFAULT_START_COL;
      cycle = new Cycle(getCountDownTick());
      matrix.setPiece(currRow, currCol, currPiece);
      needRedrawNextPiece = true;
      needRedraw = true;
    }
   
    if (cycle.cycleTick()) {
      matrix.removePiece(currRow, currCol, currPiece);
      currRow++;
      if (matrix.isValidPiece(currRow, currCol, currPiece)) {
        matrix.setPiece(currRow, currCol, currPiece);
        needRedraw = true;
      } else {
        // Hits the ground, stopping.
        currRow--;
        matrix.setPiece(currRow, currCol, currPiece);
        int rowsCleared = matrix.checkAndClear(currRow + Piece.PIECE_SIZE);
        if (rowsCleared > 0) {
          setTotalRowsCleared(totalRowsCleared + rowsCleared);
          if (level < getLevelFromRowsCleared()) {
            setLevel(getLevelFromRowsCleared());
          }
        }
        currPiece = null;
      }
    }
    draw();
  }

  /**
   * Draws the tetris game.
   */
  private void draw() {
    if (!needRedraw) {
      return;
    }
    surface.clear().fillBackground(KnownColor.BLACK);
   
    // Draw the blocks.
    for (int r = 0; r < matrix.getNumRows(); r++) {
      for (int c = 0; c < matrix.getNumCols(); c++) {
        renderer.drawBlock(surface, r, c, matrix.getBlock(r, c));       
      }
    }
    needRedraw = false;
  }
 
  /**
   * Creates a panel that contains the given array of widgets in it.
   *
   * @param widgets the widgets to add to the panel.
   * @return a new panel that contains the given widgets.
   */
  private Panel createPanel(Widget... widgets) {
    Panel panel = new FlowPanel();
    for (Widget w : widgets) {
      panel.add(w);
    }
    return panel;
  }
 
  /**
   * Creates a header label.
   *
   * @param text
   * @return the label wrapped in a h2 tag.
   */
  private Label createHeaderLabel(String text) {
    Label label = Label.wrap(DOM.createElement("h2"));
    label.setText(text);
    return label;
  }
 
  /**
   * Draws the next piece.
   */
  private void drawNextPiece() {
    if (!needRedrawNextPiece) {
      return;
    }
    nextPieceSurface.clear();
    for (int r = 0; r < Piece.PIECE_SIZE; r++) {
      for (int c = 0; c < Piece.PIECE_SIZE; c++) {
        renderer.drawBlock(nextPieceSurface, r, c, nextPiece.getBlock(r, c));
      }
    }
    needRedrawNextPiece = false;
  }

  /**
   * Gets the tick for the count down cycle.
   */
  private int getCountDownTick() {
    return Math.max(1, 60 - level * 3);
  }
 
  /**
   * Gets the level as calculated from the number of rows cleared.
   */
  private int getLevelFromRowsCleared() {
    return totalRowsCleared / ROWS_CLEARED_PER_LEVEL + levelOffset;
  }
 
  /**
   * Initializes the keyboard handlers for the game.
   */
  private void initializeKeyHandlers() {
    surface.addKeyPressHandler(new KeyPressHandler() {
      @Override
      public void onKeyPress(KeyPressEvent event) {
        if ((currPiece == null) || (event.getCharCode() != 32)) {
          return;
        }
        // Rotates the piece.
        matrix.removePiece(currRow, currCol, currPiece);
        currPiece.rotateRight();
        if (!matrix.isValidPiece(currRow, currCol, currPiece)) {
          currPiece.rotateLeft();
        } else {
          needRedraw = true;
        }
        matrix.setPiece(currRow, currCol, currPiece);
      }
    });
   
    surface.addKeyDownHandler(new KeyDownHandler() {
      @Override
      public void onKeyDown(KeyDownEvent event) {
        if (currPiece == null) {
          return;
        }
        // Moves left or right.
        int newCol = currCol;
        int newRow = currRow;
        if (event.isLeftArrow()) {
          newCol--;
        } else if (event.isRightArrow()) {
          newCol++;
        } else if (event.isDownArrow()) {
          newRow++;
        } else {
          return;
        }
        matrix.removePiece(currRow, currCol, currPiece);
        if (matrix.isValidPiece(newRow, newCol, currPiece)) {
          currRow = newRow;
          currCol = newCol;
          needRedraw = true;
        }
        matrix.setPiece(currRow, currCol, currPiece);
      }
    });
  }
 
  /**
   * Sets the current level.
   */
  private void setLevel(int level) {
    this.level  = level;
    levelLabel.setText(((Integer) level).toString());
  }
 
  /**
   * Sets the total number of rows cleared.
   */
  private void setTotalRowsCleared(int totalRowsCleared) {
    this.totalRowsCleared = totalRowsCleared;
    rowsClearedLabel.setText(((Integer) totalRowsCleared).toString());
  }
 
  /**
   * Helper class for rendering a block.
   */
  private static class TetrisRenderer {
    private static final Vector2 STROKE_OFFSET = new Vector2(1);
    private static final Vector2 FILL_OFFSET = new Vector2(.5);
    private static final Vector2 GRADIENT_POINT1_OFFSET = new Vector2(0, BLOCK_PIXEL_SIZE);
    private static final Vector2 GRADIENT_POINT2_OFFSET = new Vector2(BLOCK_PIXEL_SIZE, 0);

    // Temporary variables that are promoted to class variables to avoid
    // reconstruction.
    private Rectangle strokeRectangle = new Rectangle(0, 0,
        BLOCK_PIXEL_SIZE - 2, BLOCK_PIXEL_SIZE - 2);
    private Rectangle fillRectangle = new Rectangle(0, 0,
        BLOCK_PIXEL_SIZE - 2, BLOCK_PIXEL_SIZE - 2);
    private Vector2 position = new Vector2();
       
    public void drawBlock(Surface surface, int row, int col, BlockType type) {
      if (type == null) {
        return;
      }
      position.set(col * BLOCK_PIXEL_SIZE, row * BLOCK_PIXEL_SIZE);
      strokeRectangle.move(position.add(STROKE_OFFSET));
      surface.setStrokeStyle(new LinearGradient(
          position.add(GRADIENT_POINT1_OFFSET),
          position.add(GRADIENT_POINT2_OFFSET))
              .addColorStop(0, KnownColor.WHITE)
              .addColorStop(1, KnownColor.GRAY))
          .strokeRectangle(strokeRectangle);
     
      fillRectangle.move(position.add(FILL_OFFSET));
      surface.setFillStyle(new LinearGradient(
          position.add(GRADIENT_POINT1_OFFSET),
          position.add(GRADIENT_POINT2_OFFSET))
              .addColorStop(0, type.getColor())
              .addColorStop(1, KnownColor.WHITE))             
          .fillRectangle(fillRectangle);
    }
  }
}
TOP

Related Classes of gwt.g2d.client.demo.tetris.Tetris$TetrisRenderer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.