📄 boardcanvas.java
字号:
// Copyright (c) 2005 Sony Ericsson Mobile Communications AB
//
// This software is provided "AS IS," without a warranty of any kind.
// ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
// INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
//
// THIS SOFTWARE IS COMPLEMENTARY OF JAYWAY AB (www.jayway.se)
package bluegammon.gui;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Font;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.TextField;
import javax.microedition.m3g.Graphics3D;
import javax.microedition.m3g.Transform;
import bluegammon.Bluegammon;
import bluegammon.Resources;
import bluegammon.gui.animation.Animation;
import bluegammon.gui.animation.AnimationEngine;
import bluegammon.gui.animation.CommitMoveAnim;
import bluegammon.gui.animation.CursorAnim;
import bluegammon.gui.animation.DicesNewTurnAnim;
import bluegammon.gui.animation.DicesSelectTurnAnim;
import bluegammon.gui.animation.PieceMoveAnim;
import bluegammon.gui.animation.RepaintRequestable;
import bluegammon.gui.animation.WinnerAnim;
import bluegammon.gui.animation.WinnerPieceMoveAnim;
import bluegammon.logic.Board;
import bluegammon.logic.BoardMediator;
import bluegammon.logic.BoardState;
import bluegammon.logic.LocalPlayer;
/**
</p><p>
* Singleton class handling all graphical details of a backgammon view.
* There can only be one <code>BoardCanvas</code> per device, thus
* the singleton pattern.</p><p>
* <code>BoardCanvas</code> handles the BackGammon board gui view.
* Contains functionality for signalling gui changes on
* user interaction. Uses a <code>Board</code> instance for
* representation of gui state of the backgammon board.
* </p><p>
* The <code>BoardCanvas</code> also contains drawing primitives for
* the backgammon board.
* </p>
*
* @see bluegammon.logic.BoardMediator
* @see bluegammon.logic.BoardState
* @author Peter Andersson
*/
public class BoardCanvas extends PopupCanvas
implements CommandListener, RepaintRequestable
{
/** The 3d z depth of a piece lying on backgammon board */
public static final float PIECE_Z = -55f;
/** Singleton instance */
protected static BoardCanvas m_inst;
// Gui colors
protected static final int COL_BOARD = 0x008800;
protected static final int COL_BOARD_LT = 0x00aa00;
protected static final int COL_BOARD_DK = 0x006600;
protected static final int COL_WHITE_DIAG = 0xdddddd;
protected static final int COL_BLACK_DIAG = 0x222222;
protected static final int COL_WHITE_PIECE = 0xffffff;
protected static final int COL_BLACK_PIECE = 0x000000;
protected static final int COL_WHITE_PIECE_DK = 0xbbbbbb;
protected static final int COL_BLACK_PIECE_DK = 0x444444;
protected static final int[] COL_BLACK_DICE_VAL =
{0x000000, 0x333333, 0x666666, 0x000000};
protected static final int[] COL_WHITE_DICE_VAL =
{0xffffff, 0xcccccc, 0x999999, 0x666666};
/** Dice value unit, will be set depending on screen size */
protected static int m_diceValueUnit = 1;
/** Undo command */
public static final Command CMD_UNDO =
new Command(Resources.getString(Resources.TXT_C_UNDO), Command.CANCEL, 1);
/** Exit command */
public static final Command CMD_EXIT =
new Command(Resources.getString(Resources.TXT_C_QUIT), Command.BACK, 1);
/** Represents the gui state of backgammon board */
protected Board m_board = new Board();
/** Board's softbutton control */
protected SoftButtonControl m_softbuttons = new SoftButtonControl();
/** Canvas width in pixels */
protected int m_width;
/** Canvas height in pixels */
protected int m_height;
/** Backgammon diagonal width in pixels */
protected int m_diagW;
/** Backgammon diagonal height in pixels */
protected int m_diagH;
/** Backgammon diagonal deltaX/deltaY value */
protected int m_triangK;
/** Backgammon board height in pixels */
protected int m_boardH;
/** Backgammon piece size in pixels */
protected int m_pieceDiameter;
/**
* Cache of backgammon board regions per index,
* defined by [index][x = 0, y = 1, width = 2, height = 3]
*/
protected int[][] m_boardRegions = new int[Board.MAX_POS][4];
/**
* Point coordinates for dicevalue graphics, specified in an array
* as [diceValue][Xn][Yn], where n can be 0..diceValue, and diceValue
* is 0..5 representing different faces of a dice.
*/
protected int[][][] m_diceValPts = new int[6][][];
// The board graphics consists of a two level buffer
/** First buffer level of board graphics, a clean board without pieces */
protected Image m_cleanBoardImg;
/**
* Second buffer level of board graphics, the board with pieces of
* current state, i.e. all static pieces.
*/
protected Image m_pieceBoardImg;
/** Flags indicating what backgammon board indices needs to be repainted */
protected boolean[] m_dirtyRows = new boolean[Board.MAX_POS];
protected boolean m_undoOn = false;
/** The animation engine */
protected AnimationEngine m_animationEngine;
/** Current local player */
protected LocalPlayer m_player;
/**
* Current index in possible movement vector of
* user piece movement cursor
*/
protected int m_cursor = 0;
/** User piece movement cursor animation */
protected CursorAnim m_cursorAnimation;
/** Dice value vector, one value for each dice */
protected int[] m_diceValues = new int[2];
/**
* Dice consume status vector, one status for each dicevalue
* in m_diceValues. 0 indicates unconsumed, 1 indicates semiconsumed
* (used for double throws), 2 means consumed.
*/
protected int[] m_consumeStatuses = new int[2];
/** Flag indicating if user can interact */
protected boolean m_allowInteraction = false;
/** Flag indicating if user is queried of committing moves */
protected boolean m_queryCommit = false;
/** Dice animation */
protected Animation m_diceAnimation = null;
/** Flag indicating if dicevalues should be drawn */
protected boolean m_drawDiceValues = false;
/** Request repaint flag */
protected volatile boolean m_repaint = false;
/** 3d transform cache instance */
protected Transform m_transform = new Transform();
// Control methods
/**
* Sets up start positions for white and black player
*/
public void setStartPositions()
{
m_board.setStartPositions();
for (int i = 0; i < Board.MAX_POS; i++)
{
m_dirtyRows[i] = true;
}
}
/**
* Called from logic on a new game, when
* players toss one dice each and the one with
* highest value starts.
* @param wDice value of white dice
* @param bDice value of black dice
*/
public void selectTurns(int wDice, int bDice)
{
m_animationEngine.addAnimation(
new DicesSelectTurnAnim(wDice, bDice, getWidth(), getBoardHeight()));
}
/**
* Called from logic when dices are thrown on a new turn,
* starts the dice animation.
* @param white the color of dices
*/
public void throwDices(boolean white)
{
if (m_diceAnimation != null)
m_animationEngine.remove(m_diceAnimation);
m_diceAnimation =
new DicesNewTurnAnim(
white,
BoardMediator.getDiceValue(0),
BoardMediator.getDiceValue(1));
m_animationEngine.addAnimation(m_diceAnimation);
setDiceValues(
BoardMediator.getDiceValue(0),
BoardMediator.getDiceValue(1));
updateCursor();
}
/**
* Called from logic when a piece is moved.
* @param white Color of piece
* @param from From index.
* @param to To index.
* @param piecesOnSrc Number of pieces on source index
* @param piecesOnDst Number of pieces on dest index
*/
public void movePiece(boolean white, int from, int to, int piecesOnSrc, int piecesOnDst)
{
m_animationEngine.addAnimation(new PieceMoveAnim(white, from, to, piecesOnSrc, piecesOnDst));
}
/**
* Called from logic when user has made a move
* using specified dice value. Updates consume status.
* @param diceVal The dice value used
*/
public void consumeDiceValue(int diceVal)
{
if (m_diceValues[0] == m_diceValues[1])
{
if (m_consumeStatuses[0] == 2)
m_consumeStatuses[1]++;
else
m_consumeStatuses[0]++;
}
else
{
if (m_diceValues[0] == diceVal)
m_consumeStatuses[0] = 2;
else
m_consumeStatuses[1] = 2;
}
}
/**
* Called from logic when user has undoed a
* move based on specified dice value. Updates
* specified dicevalue consume status.
* @param diceVal The dice value being undoed
*/
public void undoConsumedDiceValue(int diceVal)
{
if (m_diceValues[0] == m_diceValues[1])
{
if (m_consumeStatuses[1] == 0)
m_consumeStatuses[0]--;
else
m_consumeStatuses[1]--;
}
else
{
if (m_diceValues[0] == diceVal)
m_consumeStatuses[0] = 0;
else
m_consumeStatuses[1] = 0;
}
}
/**
* Called from logic when the user should commit his/her moves
* or when the user has commited.
* @param commit True if user should commit, false if user has commited.
*/
public void setQueryCommit(boolean commit)
{
m_queryCommit = commit;
if (commit)
{
m_cursor = -1;
m_animationEngine.addAnimation(new CommitMoveAnim(!BoardMediator.isCurrentPlayerWhite()));
}
else
{
m_cursor = 0;
updateUndoCommand();
}
}
/**
* Setups gui when there is a winner.
* @param white The color of the winner.
* @param pieces Pieces left for loser.
* @param pts Points per piece,
*/
public void finishGame(boolean white, int pieces, int pts)
{
m_animationEngine.addAnimation(new WinnerAnim(white, pieces, pts));
}
/**
* Invalidates this canvas, forcing a full repaint on
* next call to paint()
*/
public void invalidate()
{
m_pieceBoardImg.getGraphics().drawImage(
getBoardImage(), 0, 0, Graphics.TOP | Graphics.LEFT);
// repaint all rows
for (int i = 0; i < Board.MAX_POS; i++)
{
m_dirtyRows[i] = true;
}
drawBoard(null);
// clean up animation engine
if (m_cursorAnimation != null) m_cursorAnimation.stop();
m_cursorAnimation = null;
m_diceAnimation = null;
m_animationEngine.removeAll();
updateUndoCommand();
if (BoardMediator.countPossibleMoves() > 0)
{
cursorNearestIndex(0, 0);
}
else
{
m_cursor = -1;
}
updateCursor();
}
/**
* Shuts down the canvas logic.
*/
public void shutdown()
{
m_inst = null;
m_animationEngine.shutdown();
}
// BoardCanvas state manipulation methods
/**
* Set the local player that will receive interaction
* calls made on this canvas.
* @param player The local player, or null if current player is not local.
*/
public void setCurrentLocalPlayer(LocalPlayer player)
{
m_player = player;
updateCursor();
}
/**
* Adds a new piece to the canvas
* @param white true if white piece, false if black
* @param index where to place the piece
*/
public void addPiece(boolean white, int index)
{
m_board.addPiece(white, index);
m_dirtyRows[index] = true;
requestRepaint();
}
/**
* Removes a piece from the canvas
* @param white true if white piece, false if black
* @param index where from to remove the piece
*/
public void removePiece(boolean white, int index)
{
m_board.removePiece(white, index);
m_dirtyRows[index] = true;
requestRepaint();
}
/**
* Sets number of pieces on specified index
* @param white true if white piece, false if black
* @param index The board index
* @param pieces Number of pieces
*/
public void setPieces(boolean white, int index, int pieces)
{
m_board.setPieces(white, index, pieces);
m_dirtyRows[index] = true;
requestRepaint();
}
/**
* Returns number pieces on specified index
* @param index The board index
* @return Number of pieces
*/
public int getPieces(int index)
{
return m_board.countPieces(index);
}
/**
* Returns number of pieces on specified index of specified color
* @param white true if white piece, false if black
* @param index The board index
* @return Number of pieces
*/
public int getPieces(boolean white, int index)
{
return m_board.countPieces(white, index);
}
/**
* Returns true if there are white pieces on specified index,
* returns false if there are black or no pieces.
* @param index The board index
* @return true if white, false if black.
*/
public boolean isWhite(int index)
{
return m_board.isWhite(index);
}
// Low level canvas state methods
/**
* Returns whether the player can move any pieces or not.
* @return true if user can move pieces, false if not.
*/
public boolean isUserMovable()
{
return m_allowInteraction && !BoardMediator.isRemoteTurn();
}
/**
* Returns current cursor index of possible moves.
* @return the cursor index.
*/
public int getCurrentCursorIndex()
{
return m_cursor;
}
/**
* Returns whether the canvas is waiting for the user
* to commit his/her moves.
* @return true if waiting for commit, false if not.
*/
public boolean waitingForCommit()
{
return m_queryCommit;
}
/**
* Updates the cursor. Called when possible moves has been altered.
* Stops any current cursor animation and creates a new
* one if there are possible moves.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -