📄 boardcanvas.java
字号:
*/
public void updateCursor()
{
if (m_cursorAnimation != null)
{
m_cursorAnimation.stop();
m_cursorAnimation = null;
}
if (m_cursor >= 0 &&
BoardMediator.countPossibleMoves() > 0 &&
isUserMovable())
{
int src = BoardMediator.getPossibleMoves()[m_cursor][BoardState.PM_SOUR];
int dst = BoardMediator.getPossibleMoves()[m_cursor][BoardState.PM_DEST];
m_cursorAnimation = new CursorAnim(
src, dst,
BoardMediator.countStatePieces(src), BoardMediator.countStatePieces(dst),
BoardMediator.isCurrentPlayerWhite());
m_animationEngine.addAnimation(m_cursorAnimation);
}
}
/**
* Enables/disables the possibility for user to perform a undo,
* depending on game state.
*/
public void updateUndoCommand()
{
if (!BoardMediator.isGameFinished() && !m_undoOn &&
BoardMediator.countUndoableMoves() > 0)
{
m_undoOn = true;
}
else if (BoardMediator.isGameFinished() ||
m_undoOn && BoardMediator.countUndoableMoves() == 0)
{
m_undoOn = false;
}
m_softbuttons.enable(CMD_UNDO, m_undoOn);
}
/**
* Sets whether the canvas accepts any interaction or not.
* @param allow enable/disable interaction.
*/
public void allowInteraction(boolean allow)
{
m_allowInteraction = allow;
}
/**
* Sets the dice values to be drawn and
* resets consume status
* @param dice1 value of dice 1 (0-5)
* @param dice2 value of dice 2 (0-5)
*/
public void setDiceValues(int dice1, int dice2)
{
m_diceValues[0] = dice1;
m_diceValues[1] = dice2;
m_consumeStatuses[0] = 0;
m_consumeStatuses[1] = 0;
}
/**
* Enables/Disables drawing of dice values.
* @param enable True when dice values should be drawn,
* falsw when dice values should not be drawn.
*/
public void setDrawDiceValues(boolean enable)
{
m_drawDiceValues = enable;
repaint();
}
// Interaction
/**
* Handles user interaction.
* @param keyCode Representation of pressed key.
*/
protected void keyPressed(int keyCode)
{
try
{
// Do softbuttons
m_softbuttons.keyPressed(keyCode);
// Check if any popup is open
if (m_popup != null && m_popup.isActive())
{
getPopup().keyPressed(keyCode, getGameAction(keyCode));
repaint();
return;
}
// Report to current local player
boolean consumed = false;
int gameCode = getGameAction(keyCode);
if (m_player != null)
{
consumed = m_player.keyPressed(keyCode, gameCode);
}
if (keyCode == Canvas.KEY_POUND &&
Bluegammon.getGameType() != Bluegammon.GAME_TYPE_LOCAL)
{
LocalPlayer p = BoardMediator.getLocalPlayer();
Bluegammon.getStringInput(
Resources.getString(Resources.TXT_MESSAGE) + " " +
new String(BoardMediator.getOpponentPlayer().getName()),
null, 1024, TextField.ANY, p);
}
repaint();
}
catch (Throwable t)
{
System.err.println("Error in board interaction thread");
t.printStackTrace();
}
}
/**
* Handles command invokations from <code>SoftButtonControl</code>.
* @param c the command.
* @param d the displayable.
*/
public void commandAction(Command c, Displayable d)
{
boolean consumed = false;
// Report to current local player
if (!BoardMediator.isRemoteTurn())
{
consumed = BoardMediator.getLocalPlayer().commandAction(c);
}
if (!consumed && c == CMD_EXIT)
{
// Exit, can be invoked without being user's turn
consumed = BoardMediator.getLocalPlayer().commandAction(c);
}
repaint();
}
// Cursor interaction logic methods
/**
* Moves to nearest cursor index after a change in possible
* moves.
* @param oldIndex old index before change
* @param oldTarget old target index before change
*/
public void cursorNearestIndex(int oldIndex, int oldTarget)
{
int posMoves[][] = BoardMediator.getPossibleMoves();
int diffSource = Integer.MAX_VALUE, curDiffSource;
int diffTarget = Integer.MAX_VALUE, curDiffTarget;
int newIndex = -1;
for (int i = 0; i < BoardMediator.countPossibleMoves(); i++)
{
curDiffSource = Math.abs(posMoves[i][BoardState.PM_SOUR] - oldIndex);
if (curDiffSource <= diffSource)
{
curDiffTarget = Math.abs(posMoves[i][BoardState.PM_SOUR] - oldTarget);
if (diffSource == curDiffSource)
{
if (curDiffTarget < diffTarget)
{
diffSource = curDiffSource;
diffTarget = curDiffTarget;
newIndex = i;
}
}
else
{
diffSource = curDiffSource;
diffTarget = curDiffTarget;
newIndex = i;
}
}
}
m_cursor = newIndex;
}
/**
* Moves cursor to nearest matching cursor index on opposite
* side of board, given current cursor position.
*/
public void cursorSwapSide()
{
if (m_cursor < 0) return;
int posMoves[][] = BoardMediator.getPossibleMoves();
int diffSource = Integer.MAX_VALUE, curDiffSource;
int diffTarget = Integer.MAX_VALUE, curDiffTarget;
int newIndex = m_cursor;
int oldIndex = Board.POS_BOARD - posMoves[m_cursor][BoardState.PM_SOUR];
int oldTarget = Board.POS_BOARD - posMoves[m_cursor][BoardState.PM_DEST];
for (int i = 0; i < BoardMediator.countPossibleMoves(); i++)
{
if ((oldIndex < 12 && posMoves[i][BoardState.PM_SOUR] > 11 ||
oldIndex > 11 && posMoves[i][BoardState.PM_SOUR] < 12) &&
(oldTarget < 12 && posMoves[i][BoardState.PM_DEST] > 11 ||
oldTarget > 11 && posMoves[i][BoardState.PM_DEST] < 12))
{
continue;
}
curDiffSource = Math.abs(posMoves[i][BoardState.PM_SOUR] - oldIndex);
if (curDiffSource <= diffSource)
{
curDiffTarget = Math.abs(posMoves[i][BoardState.PM_SOUR] - oldTarget);
if (diffSource == curDiffSource)
{
if (curDiffTarget < diffTarget)
{
diffSource = curDiffSource;
diffTarget = curDiffTarget;
newIndex = i;
}
}
else
{
diffSource = curDiffSource;
diffTarget = curDiffTarget;
newIndex = i;
}
}
}
m_cursor = newIndex;
}
/**
* Steps forward amongst cursor indices.
*/
public void cursorNextIndex()
{
if (BoardMediator.countPossibleMoves() > 0)
m_cursor = (m_cursor + 1) % BoardMediator.countPossibleMoves();
else
m_cursor = -1;
}
/**
* Steps backward amongst cursor indices.
*/
public void cursorBackIndex()
{
int newIndex = m_cursor - 1;
if (newIndex < 0) newIndex = BoardMediator.countPossibleMoves() - 1;
m_cursor = newIndex;
}
/**
* Returns whether there is a valid cursor or not.
*
* @return True if there is a valid cursor, false otherwise.
*/
public boolean isCursorValid()
{
return m_cursor >= 0;
}
// Graphic methods
/**
* Paints the backgammon board, any surrounding
* graphics and all current animations.
*
* @param g Graphics context.
*/
protected void paint(Graphics g)
{
try
{
// Clear background
g.setColor(COL_BOARD_DK);
g.fillRect(0,m_boardH,m_width, m_height - m_boardH);
// Draw backgammon board
drawBoard(g);
// Draw dice values if necessary
if (!BoardMediator.isGameFinished() && m_drawDiceValues)
{
drawDiceValues(g,
BoardMediator.isCurrentPlayerWhite(),
m_diceValues, m_consumeStatuses);
}
// Draw animations
m_animationEngine.paint(g);
// Draw softbuttons
m_softbuttons.paint(g);
// Draw popup if necessary
if (m_popup != null && m_popup.isActive())
{
m_popup.paint(g);
}
}
catch (Throwable t)
{
System.err.println("Error in board paint thread");
t.printStackTrace();
}
}
/**
* Returns the actual height of the board in pixels
* @return the board height
*/
public int getBoardHeight()
{
return m_boardH;
}
/**
* Adds a piece animation when there is a winner. Selects
* among existing pieces on board.
* @param white True to animate white pieces, false for black.
* @param winAnim The comprising winning animation.
*/
public void addWinningPieceAnimation(boolean white, WinnerAnim winAnim)
{
// Find a piece to animate
int src = -1;
if (getPieces(white, Board.POS_GUARD) > 0)
{
src = Board.POS_GUARD;
}
else
{
for (int i = 0; src == -1 && i <= Board.POS_BOARD; i++)
{
if (getPieces(white, i) > 0)
{
src = i;
}
}
}
if (src >= 0)
{
int x = (src > Board.POS_BOARD / 2) ? 0 : getWidth();
m_animationEngine.addAnimation(
new WinnerPieceMoveAnim(winAnim, white, src, x, getHeight()/2, getPieces(white, src)-1)
);
}
}
/**
* Draws the backgammon game board. Does partial redraw depending on
* what is changed since last draw.
* @param g Graphics context to draw to or null if just
* updating static graphics.
*/
protected void drawBoard(Graphics g)
{
Graphics staticGraphics = m_pieceBoardImg.getGraphics();
for (int i = 0; i < Board.MAX_POS; i++)
{
if (m_dirtyRows[i])
{
// Repaint dirty region
staticGraphics.setClip(
m_boardRegions[i][0],
m_boardRegions[i][1],
m_boardRegions[i][2],
m_boardRegions[i][3]);
staticGraphics.drawImage(m_cleanBoardImg, 0, 0, Graphics.TOP | Graphics.LEFT);
staticGraphics.setClip(0,0,m_width, m_height);
drawPieces(staticGraphics, i);
}
}
if (g != null)
{
g.drawImage(m_pieceBoardImg, 0, 0, Graphics.TOP | Graphics.LEFT);
}
}
/**
* Draws both dice values.
* @param g Graphics context to draw to.
* @param white True for white dicevalues, false for vlack.
* @param diceVals Array for the actual dice values.
* @param consumeStatus Array of the consume status of each dice value.
*/
protected void drawDiceValues(Graphics g,
boolean white,
int[] diceVals,
int[] consumeStatus)
{
int totalW = 2 * (m_diceValueUnit * 8 ) - m_diceValueUnit;
int x = (m_width - totalW) / 2;
int y = m_boardH - m_diceValueUnit * 7 - 1;
for (int i = 0; i < 2; i++)
{
drawDiceValue(g, white, diceVals[i], consumeStatus[i], x, y);
x += m_diceValueUnit * 8;
}
}
/**
* Draws one dice value.
* @param g Graphics context to draw to.
* @param white True for white dicevalues, false for vlack.
* @param diceVal The actual dice value (0-5).
* @param consumeStatu The consume status of the dice value.
* @param x X-coordinate of the dicevalue.
* @param y Y-coordinate of the dicevalue.
*/
protected void drawDiceValue(
Graphics g, boolean white, int diceVal, int consumeStatus,
int x, int y)
{
int[] backCols = COL_WHITE_DICE_VAL, ptCols = COL_BLACK_DICE_VAL;
if (!white)
{
backCols = COL_BLACK_DICE_VAL; ptCols = COL_WHITE_DICE_VAL;
}
int backCol = backCols[consumeStatus];
int fxCol = backCols[3];
int ptCol = ptCols[consumeStatus];
g.setColor(fxCol);
g.fillRect(x+1,y+1,m_diceValueUnit * 7, m_diceValueUnit * 7);
g.setColor(backCol);
g.fillRect(x,y,m_diceValueUnit * 7, m_diceValueUnit * 7);
g.setColor(ptCol);
int[][] pts = m_diceValPts[diceVal-1];
for (int i = 0; i < pts.length; i++)
{
g.fillRect(x + pts[i][0], y + pts[i][1], m_diceValueUnit, m_diceValueUnit);
}
}
/**
* Returns an image of a clean backgammon board (without pieces).
* @return A backgammon board image.
*/
public synchronized Image getBoardImage()
{
if (m_cleanBoardImg == null)
{
m_cleanBoardImg = Image.createImage(m_width, m_boardH);
Graphics ig = m_cleanBoardImg.getGraphics();
ig.setColor(COL_BOARD);
ig.fillRect(0,0,m_width,m_boardH);
int diag = 0;
int index = 0;
int tmpCol, col1 = COL_WHITE_DIAG, col2 = COL_BLACK_DIAG;
for (int y = 0; y < m_height - m_diagH; y += m_diagH)
{
diag ++;
switch (diag)
{
// out
case 1:
// guard
case 8:
// bottom
case 15:
{
y++;
ig.setColor(COL_BOARD_LT);
ig.drawLine(0,y,m_width-1,y);
ig.drawLine(0,y,0,y+m_diagH);
ig.setColor(COL_BOARD_DK);
ig.drawLine(0,y+m_diagH,m_width-1,y+m_diagH);
ig.drawLine(m_width-1,y,m_width-1,y+m_diagH);
y++;
break;
}
default:
{
m_boardRegions[index][0] = 0;
m_boardRegions[index][1] = y;
m_boardRegions[index][2] = m_width/2;
m_boardRegions[index][3] = m_diagH;
m_boardRegions[Board.POS_BOARD - index][0] = m_width/2 + 1;
m_boardRegions[Board.POS_BOARD - index][1] = y;
m_boardRegions[Board.POS_BOARD - index][2] = m_width/2;
m_boardRegions[Board.POS_BOARD - index][3] = m_diagH;
index ++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -