📄 gamecanvas.java
字号:
/*
* GameCanvas.java
*
* Copyright 2001 SkyArts. All Rights Reserved.
*/
import javax.microedition.lcdui.*;
import java.util.*;
/**
* 游戏的操作与画面描绘使用的Canvas类
*
* @author Hideki Yonekawa
* @version 1.0
*/
class GameCanvas extends Canvas implements Runnable, CommandListener {
/** 构造函数 */
private int screenWidth;
/** 储存横向长度的变量 */
private int screenHeight;
/** 储存纵向长度的变量 */
private Cube cube;
/** 代表标题显示状态的常量 */
private static final short TITLE = 0;
/** 代表游戏开始显示状态的常量 */
private static final short GAME_START = 1;
/** 代表游戏中显示状态的常量 */
private static final short GAME_PLAYING = 2;
/** 代表游戏结束显示状态的常量 */
private static final short GAME_END = 5;
/** 储存现在显示状态的变量 */
private short gameState;
/** 显示暂停状态的标志 */
private boolean isPaused;
/** 储存使用在标题的图像的变量 */
private Image titleImg;
/** Start指令变量 */
private Command startCmd = new Command("Start", Command.SCREEN, 5);
/** Exit指令变量 */
private Command exitCmd = new Command("Exit", Command.SCREEN, 1);
/** Pause指令变量 */
private Command pauseCmd = new Command("Pause", Command.SCREEN, 5);
/** Resume指令变量 */
private Command resumeCmd = new Command("Resume", Command.SCREEN, 5);
/** Quit指令变量 */
private Command quitCmd = new Command("Quit", Command.SCREEN, 1);
/** 成为方块的置入物的Piece数组变量 */
private Piece[] pieces;
/** 储存方块的列(纵向)数目的常量 */
private static final int COLUMN_LENGTH = 8;
/** 储存方块的行(横向)数目的常量 */
private static final int ROW_LENGTH = 6;
/** 储存了落下方块组的中心点Index的变量 */
private int centerPoint;
/** 储存了落下方块组的左侧Index的变量 */
private static final short FALL_START_INDEX1 = 2;
/** 储存了落下方块组的右侧Index的变量 */
private static final short FALL_START_INDEX2 = 3;
//落下方块的方向常量
/** 代表落下方块组的方向为上的常量 */
private static final short DIRECTION_UP = 0;
/** 代表落下方块组的方向为右的常量 */
private static final short DIRECTION_RIGHT = 1;
/** 代表落下方块组的方向为下的常量 */
private static final short DIRECTION_DOWN = 2;
/** 代表落下方块组的方向为左的常量 */
private static final short DIRECTION_LEFT = 3;
/** 代表落下方块组之默认方向的常量 */
private static final short DIRECTION_DEFAULT= DIRECTION_RIGHT;
/** 储存了落下方块组现在方向的变量 */
private short currentDirection;
/** 储存下一个方块资讯的Piece数组变量 */
private Piece[] nextPieces;
/** 在制作下一个方块组时所使用的Random变量 */
private Random random = new Random();
/** 代表按键输入是否有效的标志变量 */
private boolean isKeyEnable;
private static final int DEFAULT_FALL_TICK_COUNT=10;
/** 储存用来调整方块组落下速度用的Tick计数的变量 */
private int tickCount4Speed;
/** 储存用来计算落下方块组时机的Tick计数的变量 */
private int tickCount4Fall;
/** 储存方块组落下次数的变量 */
private int fallCount;
/** 代表游戏循环是否停止的变量 */
private boolean isStopped;
/** 判断是否要落下下一个方块组的标志变量 */
private boolean isNextFall;
/** 存放描绘间隔(INTERVAL)的常量 */
private static final long DRAW_INTERVAL = 100;
/** 存放默认分数增加值的常量 */
private static final int DEFAULT_SCORE_VALUE = 100;
/** 存放分数的变量 */
private long score;
/** 存放最高分数的变量 */
private long highScore = 0;
/** 存放默认字体的变量 */
private Font defFont = Font.getDefaultFont();
/** 构造函数 */
GameCanvas(Cube cube) {
this.cube = cube;
//取得画面的可描绘范围
screenWidth = getWidth();
screenHeight = getHeight();
//取得标题图像
try {
titleImg = Image.createImage("/title.png");
}catch(java.io.IOException e) {}
//登录指令监听
setCommandListener(this);
//将游戏的状态变成显示标题
gameState = TITLE;
}
/** 进行游戏初始化的方法 */
private void doGameInit() {
//清除分数
score = 0;
//取得下一个方块组
nextPieces = getNextPieces();
//清除方块置入数组
pieces = new Piece[COLUMN_LENGTH * ROW_LENGTH];
//将调整方块组速度用的Tick计数设为默认值
tickCount4Speed = DEFAULT_FALL_TICK_COUNT;
//清除用来计算落下方块组时机的Tick计数
tickCount4Fall = 0;
//清除落下方块组的数目
fallCount = 0;
//清除停止循环标志
isStopped = false;
//清除暂停标志
isPaused = false;
//建立是否落下下一个方块组的标志
isNextFall = true;
//让按键有效
isKeyEnable = true;
}
/** 指令的事件发生时被调用出来的方法 */
public void commandAction(Command c, Displayable s) {
if(c == startCmd) {//Start指令
//初始化游戏以开始游戏
doGameInit();
gameState = GAME_START;
doThreadStart();
}else if(c == exitCmd) {//EXIT指令
//调用出Cube类的doExit方法以结束MIDlet本身
cube.doExit();
}else if(c == pauseCmd) {//Pause指令
//交换Pause指令与Resume指令,调用出Pause、Resume处理方法
removeCommand(pauseCmd);
addCommand(resumeCmd);
doPauseOrResume();
}else if(c == resumeCmd) {//Resume指令
//交换Resume指令与Pause指令,调用出Pause、Resume处理方法
removeCommand(resumeCmd);
addCommand(pauseCmd);
doPauseOrResume();
}else if(c == quitCmd) {//Quit指令
//调用出游戏结束方法
doGameStop();
//删除指令
removeCommand(pauseCmd);
removeCommand(resumeCmd);
removeCommand(quitCmd);
//显示标题
doTitle();
}
}
/** MIDlet的startApp()被调用出来时所调用的方法 */
void doStartApp() {
//根据现在的状态来操作运作
switch(gameState) {
case TITLE: //显示标题时
doTitle();
break;
case GAME_START: //游戏开始时
case GAME_PLAYING: //游戏中
//进行暂停
isPaused = true;
//停止游戏循环
isStopped = true;
//以防万一先删除关卡中的指令
removeCommand(pauseCmd);
removeCommand(resumeCmd);
//新增Resume指令
addCommand(resumeCmd);
break;
default: //上述情形以外时
//解除暂停
isPaused = false;
break;
}
}
/** 进行标题显示的方法 */
private void doTitle() {
//将游戏的状态设为显示标题
gameState = TITLE;
//以防万一先将关卡中的指令删除
removeCommand(pauseCmd);
removeCommand(resumeCmd);
removeCommand(quitCmd);
//显示标题画面
repaint();
//新增指令
addCommand(exitCmd);
addCommand(startCmd);
}
/** MIDlet的pauseApp()方法被调用出来时所调用的方法 */
void doPauseApp() {
switch(gameState) {
case TITLE: //显示标题时
break;
default: //上述情形以外时
//暂停
isPaused = true;
//停止游戏循环
isStopped = true;
break;
}
}
/**
*产生下一个落下方块组并传回的方法
*在@return Piece[] 之后落下的Piece数组
*/
private Piece[] getNextPieces() {
//以Random所产生的值为基础决定种类
int kindNo= random.nextInt() % 10;
//负数的时候就将其变为正数
if(kindNo < 0) kindNo = kindNo * (-1);
Piece[] retPieces = new Piece[] {
new Piece(),
new Piece()
};
switch(kindNo) {
case 0://红红
retPieces[0].currentColor = Piece.RED;
retPieces[1].currentColor = Piece.RED;
break;
case 1://红绿
retPieces[0].currentColor = Piece.RED;
retPieces[1].currentColor = Piece.GREEN;
break;
case 2://红蓝
retPieces[0].currentColor = Piece.RED;
retPieces[1].currentColor = Piece.BLUE;
break;
case 3://红黄
retPieces[0].currentColor = Piece.RED;
retPieces[1].currentColor = Piece.YELLOW;
break;
case 4://绿绿
retPieces[0].currentColor = Piece.GREEN;
retPieces[1].currentColor = Piece.GREEN;
break;
case 5://绿蓝
retPieces[0].currentColor = Piece.GREEN;
retPieces[1].currentColor = Piece.BLUE;
break;
case 6://绿黄
retPieces[0].currentColor = Piece.GREEN;
retPieces[1].currentColor = Piece.YELLOW;
break;
case 7://蓝蓝
retPieces[0].currentColor = Piece.BLUE;
retPieces[1].currentColor = Piece.BLUE;
break;
case 8://蓝黄
retPieces[0].currentColor = Piece.BLUE;
retPieces[1].currentColor = Piece.YELLOW;
break;
case 9://黄黄
retPieces[0].currentColor = Piece.YELLOW;
retPieces[1].currentColor = Piece.YELLOW;
break;
}
return retPieces;
}
/** 按键按下事件发生时被调用出来的方法 */
protected synchronized void keyPressed(int keyCode) {
if( ! isKeyEnable || gameState != GAME_PLAYING ||
(gameState == GAME_PLAYING && isPaused)) {
//按键为无效、或是不在游戏中、在游戏中暂停时为return
return;
}
//为清除按键时不处理
if(keyCode == 0) return; //for KDDI
int gameCode = getGameAction(keyCode);
switch(gameCode) {
case UP: //按下上按键时
case FIRE: //按下Fire键时
doRotat();
break;
case LEFT: //按下左按键时
doLeft();
break;
case DOWN: //按下下按键时
doFall();
break;
case RIGHT: //按下右按键时
doRight();
break;
}
}
/** 压下按键状态时被重复调用的方法 */
protected void keyRepeated(int keyCode) {
keyPressed(keyCode);
}
/** 压下上按键、决定按键时所调用出来的方法 */
private void doRotat() {
switch(currentDirection) {
case DIRECTION_UP: //方向为上时
//因为要作顺时钟旋转,所以要检查右边
if(centerPoint % ROW_LENGTH != ROW_LENGTH -1) {
//当不是在最右边时
if( pieces[centerPoint +1] == null &&
pieces[centerPoint -ROW_LENGTH +1] == null )
{
//若在右边以及右边上面都没有东西的话就向右转动
pieces[centerPoint +1] = pieces[centerPoint -ROW_LENGTH];
pieces[centerPoint -ROW_LENGTH] = null;
//方向转向右
currentDirection = DIRECTION_RIGHT;
}
}
break;
case DIRECTION_RIGHT: //方向为右时
//因为要作顺时钟旋转,所以要检查下方
if(centerPoint < (COLUMN_LENGTH -1) * ROW_LENGTH) {
//当不是在最下面时
if( pieces[centerPoint +ROW_LENGTH] == null &&
pieces[centerPoint +1 +ROW_LENGTH] == null)
{
//当右下与正下方什么都没有时向下移动
pieces[centerPoint +ROW_LENGTH] = pieces[centerPoint +1];
pieces[centerPoint +1] = null;
//将方向变为向下
currentDirection = DIRECTION_DOWN;
}
}
break;
case DIRECTION_DOWN: //方向为向下时
//因为要作顺时钟旋转,所以要检查左边
if(centerPoint % ROW_LENGTH != 0) {
//当不在最左边的时候
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -