J2ME連連看基礎(chǔ)功能源代碼(含詳細(xì)注釋)
作者:陳躍峰
出自:http://blog.csdn.net/mailbomb
//界面類代碼
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Graphics;
/**
* 連連看游戲界面
*/
public class LinkCanvas extends Canvas implements Runnable{
/**游戲邏輯類*/
GameEngine engine;
/**屏幕寬度*/
int width;
/**屏幕高度*/
int height;
public LinkCanvas(){
//創(chuàng)建對象
engine = new GameEngine();
//獲得屏幕的高度和寬度
width = getWidth();
height = getHeight();
//啟動(dòng)線程
Thread t = new Thread(this);
t.start();
}
/**
* 繪制方法
*/
protected void paint(Graphics g) {
//清屏
clearScreen(g);
//繪制地圖
engine.paintMap(g);
//繪制選擇框
engine.paintSelectArea(g);
//繪制連線
engine.paintLinkLine(g);
}
/**
* 清屏方法
* @param g 畫筆
*/
private void clearScreen(Graphics g){
g.setColor(0xffffff);
g.fillRect(0, 0, width, height);
g.setColor(0);
}
public void keyPressed(int keyCode){
int action = getGameAction(keyCode);
switch(action){
case UP:
engine.moveUP();
break;
case DOWN:
engine.moveDown();
break;
case LEFT:
engine.moveLeft();
break;
case RIGHT:
engine.moveRight();
break;
case FIRE:
engine.fire();//選擇塊
break;
}
}
public void run() {
try{
while(true){
//延時(shí)
Thread.sleep(100);
//每次判斷邏輯
engine.action();
repaint();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
//邏輯類源代碼
import java.util.*;
import javax.microedition.lcdui.*;
/**
* 游戲數(shù)據(jù)和邏輯類
*/
public class GameEngine {
/**選中塊的個(gè)數(shù)*/
private int selectTileNum = 0;
//第一個(gè)選擇塊的行號和列號
/**行號*/
private int firstRow;
/**列號*/
private int firstCol;
//第二個(gè)選擇塊的行號和列號
/**行號*/
private int secondRow;
/**列號*/
private int secondCol;
//當(dāng)前選擇框,默認(rèn)在左上角
/**當(dāng)前選擇框的行號*/
private int cRow;
/**當(dāng)前選擇框的列號*/
private int cCol;
/**最大行數(shù)*/
private final int MAX_ROW = 10;
/**最大列數(shù)*/
private final int MAX_COL = 10;
/**地圖數(shù)據(jù),0代表空,數(shù)據(jù)1-10分別代表十種不同的結(jié)構(gòu)*/
private int[][] map = new int[MAX_ROW][MAX_COL];
/**隨機(jī)數(shù)對象*/
private Random ran = new Random();
//地圖區(qū)域左上角的坐標(biāo)
private final int LEFTX = 20;
private final int LEFTY = 50;
/**每個(gè)單元格的寬度*/
private final int TILE_WIDTH = 20;
/**每個(gè)單元格的高度*/
private final int TILE_HEIGHT = 20;
/**連線類型*/
private int linkType;
/**無法連線*/
private final int NO_LINK = 0;
/**水平連線*/
private final int H_LINK = 1;
/**垂直聯(lián)系*/
private final int V_LINK = 2;
/**一個(gè)拐點(diǎn),先移動(dòng)x*/
private final int ONE_CORNER_FIRSTX = 3;
/**一個(gè)拐點(diǎn),先移動(dòng)y*/
private final int ONE_CORNER_FIRSTY = 4;
/**兩個(gè)拐點(diǎn),待完善*/
private final int TWO_CORNER = 5;
/**
* 兩次拐彎的行號和列號
* 數(shù)據(jù)格式為:
* 第一個(gè)拐點(diǎn)的行號,第一個(gè)拐點(diǎn)的列號,第二個(gè)拐點(diǎn)的行號,第二個(gè)拐點(diǎn)的列號
*/
int[] p = new int[4];
public GameEngine(){
//初始化地圖數(shù)據(jù)
initMap();
}
/**
* 初始化地圖數(shù)據(jù)
*/
private void initMap(){
for(int row = 0;row < map.length;row++){
for(int col = 0;col < map[row].length;col++){
map[row][col] = row + 1;
}
}
//循環(huán)打亂10次
int tempRow;
int tempCol;
int temp;
for(int i = 0;i < 10;i++){
for(int row = 0;row < map.length;row++){
for(int col = 0;col < map[row].length;col++){
//隨機(jī)行號
tempRow = Math.abs(ran.nextInt() % 10);
//隨機(jī)列號
tempCol = Math.abs(ran.nextInt() % 10);
//如果不是同一個(gè)單元格,則交換數(shù)據(jù)
if(!((tempRow == row) && (tempCol == col))){
temp = map[row][col];
map[row][col] = map[tempRow][tempCol];
map[tempRow][tempCol] = temp;
}
}
}
}
}
/**
* 繪制地圖數(shù)據(jù)
* @param g 畫筆
*/
public void paintMap(Graphics g){
for(int row = 0;row < map.length;row++){
for(int col = 0;col < map[row].length;col++){
//如果沒有數(shù)據(jù),則跳過
if(map[row][col] == 0){
continue;
}else{//繪制方塊
//繪制方框
g.drawRect(LEFTX + col * TILE_WIDTH, LEFTY + row * TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT);
//繪制數(shù)字
g.drawString(String.valueOf(map[row][col]), LEFTX + col * TILE_WIDTH + 5,
LEFTY + row * TILE_HEIGHT + 4,
Graphics.TOP | Graphics.LEFT);
}
}
}
}
/**
* 繪制選擇框
* @param g 畫筆
*/
public void paintSelectArea(Graphics g){
//繪制當(dāng)前選擇框
g.setColor(0xff00);
g.drawRect(LEFTX + cCol * TILE_WIDTH, LEFTY + cRow * TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT);
g.setColor(0);
//繪制選中項(xiàng)
switch(selectTileNum){
case 1: //選擇一個(gè)
g.setColor(0xff0000);
g.drawRect(LEFTX + firstCol * TILE_WIDTH, LEFTY + firstRow * TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT);
g.setColor(0);
break;
case 2: //選中兩個(gè)
g.setColor(0xff0000);
g.drawRect(LEFTX + firstCol * TILE_WIDTH, LEFTY + firstRow * TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT);
g.drawRect(LEFTX + secondCol * TILE_WIDTH, LEFTY + secondRow * TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT);
g.setColor(0);
break;
}
}
/**
* 繪制方塊連線
* @param g 畫筆
*/
public void paintLinkLine(Graphics g){
//如果無連線,則直接返回
if(linkType == NO_LINK){
return;
}
//根據(jù)連線類型實(shí)現(xiàn)繪制
//繪制到方塊的中心點(diǎn)
switch(linkType){
case H_LINK://水平
case V_LINK://垂直
paintLine(g,firstRow,firstCol,secondRow,secondCol);
break;
case ONE_CORNER_FIRSTX://一個(gè)拐彎,先移動(dòng)X
//水平線
paintLine(g,firstRow,firstCol,firstRow,secondCol);
//垂直線
paintLine(g,firstRow,secondCol,secondRow,secondCol);
break;
case ONE_CORNER_FIRSTY://一個(gè)拐彎,先移動(dòng)Y
//水平線
paintLine(g,firstRow,firstCol,secondRow,firstCol);
//垂直線
paintLine(g,secondRow,firstCol,secondRow,secondCol);
break;
case TWO_CORNER:
//塊1到第一個(gè)拐點(diǎn)的連線
paintLine(g,firstRow,firstCol,p[0],p[1]);
//兩個(gè)拐點(diǎn)之間的連線
paintLine(g,p[0],p[1],p[2],p[3]);
//第二個(gè)拐點(diǎn)到塊2的連線
paintLine(g,p[2],p[3],secondRow,secondCol);
break;
}
//邏輯代碼,清除連接類型
linkType = NO_LINK;
}
/**
* 繪制兩個(gè)方塊中心點(diǎn)的連線
* @param g 畫筆
* @param r1 方塊1的行號
* @param c1 方塊1的列號
* @param r2 方塊2的行號
* @param c2 方塊2的列號
*/
private void paintLine(Graphics g,int r1,int c1,int r2,int c2){
g.drawLine(LEFTX + c1 * TILE_WIDTH + TILE_WIDTH/2,
LEFTY + r1 * TILE_HEIGHT + TILE_HEIGHT/2,
LEFTX + c2 * TILE_WIDTH + TILE_WIDTH/2,
LEFTY + r2 * TILE_HEIGHT + TILE_HEIGHT/2);
}
/**
* 向左移動(dòng)選擇框
*/
public void moveLeft(){
if(cCol > 0){
cCol--;
}
}
/**
* 向右移動(dòng)選擇框
*/
public void moveRight(){
if(cCol < MAX_COL -1){
cCol++;
}
}
/**
* 向上移動(dòng)選擇框
*/
public void moveUP(){
if(cRow > 0){
cRow--;
}
}
/**
* 向下移動(dòng)選擇框
*/
public void moveDown(){
if(cRow < MAX_ROW - 1){
cRow++;
}
}
/**
* 確定鍵邏輯處理
*/
public void fire(){
//如果選擇的塊為空,則直接返回
if(map[cRow][cCol] == 0){
return;
}
//選中的塊的數(shù)量增加1
selectTileNum++;
//判別存儲(chǔ)位置
switch(selectTileNum){
case 1: //第一次選擇
firstRow = cRow;
firstCol = cCol;
break;
case 2: //第二次選擇
//選擇同一個(gè)塊,2個(gè)選擇塊都失去選中
if((firstRow == cRow) && (firstCol == cCol)){
selectTileNum = 0;
return;
}
secondRow = cRow;
secondCol = cCol;
break;
}
}
/**
* 判斷(r1,c1)塊和(r2,c2)塊中間是否為空行
* 不包含這兩個(gè)塊
* @param r1 塊1的行號
* @param c1 塊1的列號
* @param r2 塊2的行號
* @param c2 塊2的列號
* @return true代表為空,false代表不為空
*/
private boolean isEmptyRow(int r1,int c1,int r2,int c2){
//判斷是否位于同一行
if(r1 != r2){
return false;
}
//判斷兩個(gè)塊的相對位置
if(c1 > c2){ //第一塊位于右側(cè)
for(int col = c1 - 1;col > c2;col--){
//如果有非空塊
if(map[r1][col] != 0){
return false;
}
}
}else{ //第一塊位于左側(cè)
for(int col = c2 - 1;col > c1;col--){
//如果有非空塊
if(map[r1][col] != 0){
return false;
}
}
}
return true;
}
/**
* 判斷塊(r1,c1)和塊(r2,c2)之間是否是空列
* 不包含這兩個(gè)塊
* @param r1 塊1的行號
* @param c1 塊1的列號
* @param r2 塊2的行號
* @param c2 塊2的列號
* @return true代表為空,false代表不為空
*/
private boolean isEmptyCol(int r1,int c1,int r2,int c2){
//判斷是否位于同一列
if(c1 != c2){
return false;
}
//判斷兩個(gè)塊的相對位置
if(r2 > r1){//第一個(gè)塊在上方
for(int row = r1 + 1;row < r2;row++){
//如果有非空塊
if(map[row][c1] != 0){
return false;
}
}
}else{//第二個(gè)塊在上方
for(int row = r2 + 1;row < r1;row++){
//如果有非空塊
if(map[row][c1] != 0){
return false;
}
}
}
return true;
}
/**
* 判斷一個(gè)塊是否為空
* @param r 塊的行號
* @param c 塊的列號
* @return true代表為空,false代表不空
*/
private boolean isEmptyCell(int r,int c){
return map[r][c] == 0;
}
/**
* 是否是一次轉(zhuǎn)彎實(shí)現(xiàn)連線
* @return NO_LINK代表沒有連線,其他值代表對應(yīng)的連線類型
*/
private int isOneCornerLink(int r1,int c1,int r2,int c2){
//先移動(dòng)行,再移動(dòng)列
if(isEmptyCell(r1,c2)){ //轉(zhuǎn)折點(diǎn)為空
if(isEmptyRow(r1,c1,r1,c2) & isEmptyCol(r1,c2,r2,c2)){
return ONE_CORNER_FIRSTX;
}
}
//先移動(dòng)列,再移動(dòng)行
if(isEmptyCell(r2,c1)){//轉(zhuǎn)折點(diǎn)為空
if(isEmptyCol(r1,c1,r2,c1) & isEmptyRow(r2,c1,r2,c2)) {
return ONE_CORNER_FIRSTY;
}
}
//無連接
return NO_LINK;
}
/**
* 是否經(jīng)過2次轉(zhuǎn)折實(shí)現(xiàn)連接
* @param r1 塊1的行號
* @param c1 塊1的列號
* @param r2 塊2的行號
* @param c2 塊2的列號
* @return true代表可以連接,false代表不能
*/
private boolean isTwoCornerLink(int r1,int c1,int r2,int c2){
int result;
//正常情況,劃分成4個(gè)方向
//塊1向上
for(int row = r1 -1;row >= 0;row--){
//如果有數(shù)據(jù)不為空,則直接結(jié)束該方向的嘗試
if(map[row][c1] != 0){
break;
}
//存儲(chǔ)第一個(gè)拐點(diǎn)的坐標(biāo)
p[0] = row;
p[1] = c1;
//每次都嘗試轉(zhuǎn)折,則變成一個(gè)轉(zhuǎn)點(diǎn)的操作
result = isOneCornerLink(row,c1,r2,c2);
//如果可以連接
if(result != NO_LINK){
//存儲(chǔ)第二個(gè)拐點(diǎn)的位置
switch(result){
case ONE_CORNER_FIRSTX:
p[2] = row;
p[3] = c2;
break;
case ONE_CORNER_FIRSTY:
p[2] = r2;
p[3] = c1;
break;
}
return true;
}
}
//塊1向下
for(int row = r1 + 1;row < MAX_ROW;row++){
//如果有數(shù)據(jù)不為空,則直接結(jié)束該方向的嘗試
if(map[row][c1] != 0){
break;
}
//存儲(chǔ)第一個(gè)拐點(diǎn)的坐標(biāo)
p[0] = row;
p[1] = c1;
//每次都嘗試轉(zhuǎn)折,則變成一個(gè)轉(zhuǎn)點(diǎn)的操作
result = isOneCornerLink(row,c1,r2,c2);
//如果可以連接
if(result != NO_LINK){
//存儲(chǔ)第二個(gè)拐點(diǎn)的位置
switch(result){
case ONE_CORNER_FIRSTX:
p[2] = row;
p[3] = c2;
break;
case ONE_CORNER_FIRSTY:
p[2] = r2;
p[3] = c1;
break;
}
return true;
}
}
//塊1向左
for(int col = c1 -1;col >= 0;col--){
//如果有數(shù)據(jù)不為空,則直接結(jié)束該方向的嘗試
if(map[r1][col] != 0){
break;
}
//存儲(chǔ)第一個(gè)拐點(diǎn)的坐標(biāo)
p[0] = r1;
p[1] = col;
//每次都嘗試轉(zhuǎn)折,則變成一個(gè)轉(zhuǎn)點(diǎn)的操作
result = isOneCornerLink(r1,col,r2,c2);
//如果可以連接
if(result != NO_LINK){
//存儲(chǔ)第二個(gè)拐點(diǎn)的位置
switch(result){
case ONE_CORNER_FIRSTX:
p[2] = r1;
p[3] = c2;
break;
case ONE_CORNER_FIRSTY:
p[2] = r2;
p[3] = col;
break;
}
return true;
}
}
//塊1向右
for(int col = c1 + 1;col < MAX_COL;col++){
//如果有數(shù)據(jù)不為空,則直接結(jié)束該方向的嘗試
if(map[r1][col] != 0){
break;
}
//存儲(chǔ)第一個(gè)拐點(diǎn)的坐標(biāo)
p[0] = r1;
p[1] = col;
//每次都嘗試轉(zhuǎn)折,則變成一個(gè)轉(zhuǎn)點(diǎn)的操作
result = isOneCornerLink(r1,col,r2,c2);
//如果可以連接
if(result != NO_LINK){
//存儲(chǔ)第二個(gè)拐點(diǎn)的位置
switch(result){
case ONE_CORNER_FIRSTX:
p[2] = r1;
p[3] = c2;
break;
case ONE_CORNER_FIRSTY:
p[2] = r2;
p[3] = col;
break;
}
return true;
}
}
//四個(gè)特例,也就是超出地圖區(qū)域的連接
//實(shí)現(xiàn)地圖區(qū)域上側(cè)的連接,也就是到上側(cè)是一個(gè)空列
if((isEmptyCol(r1,c1,-1,c1)) & (isEmptyCol(r2,c2,-1,c2))){
p[0] = -1;
p[1] = c1;
p[2] = -1;
p[3] = c2;
return true;
}
//左側(cè)
if((isEmptyRow(r1,c1,r1,-1)) & (isEmptyRow(r2,c2,r2,-1))){
p[0] = r1;
p[1] = -1;
p[2] = r2;
p[3] = -1;
return true;
}
//下側(cè)
if((isEmptyCol(r1,c1,MAX_ROW,c1)) & (isEmptyCol(r2,c2,MAX_ROW,c2))){
p[0] = MAX_ROW;
p[1] = c1;
p[2] = MAX_ROW;
p[3] = c2;
return true;
}
//右側(cè)
if((isEmptyRow(r1,c1,r1,MAX_COL)) & (isEmptyRow(r2,c2,r2,MAX_COL))){
p[0] = r1;
p[1] = MAX_COL;
p[2] = r2;
p[3] = MAX_COL;
return true;
}
return false;
}
/**
* 邏輯判斷是否有連線
* @return NO_LINK代表無連線,其它數(shù)據(jù)代表有連線
*/
private int logic(){
//如果數(shù)值不同
if(map[firstRow][firstCol] != map[secondRow][secondCol]){
return NO_LINK;
}
//判斷連接方式
if(isEmptyRow(firstRow,firstCol,secondRow,secondCol)){ //水平連線
return H_LINK;
}
if(isEmptyCol(firstRow,firstCol,secondRow,secondCol)){//垂直連線
return V_LINK;
}
//一個(gè)轉(zhuǎn)點(diǎn)的連接
int result = isOneCornerLink(firstRow,firstCol,secondRow,secondCol);
if(result != NO_LINK){
return result;
}
//兩個(gè)轉(zhuǎn)點(diǎn)的連接
if(isTwoCornerLink(firstRow,firstCol,secondRow,secondCol)){
return TWO_CORNER;
}
//返回?zé)o連接
return NO_LINK;
}
/**
* 邏輯判別和邏輯處理
*/
public boolean action(){
//判斷是否選擇兩個(gè)方塊
if(selectTileNum != 2){
return false;
}
boolean b = false;
//判斷是否有連線
linkType = logic();
//如果有連線,則消失
if(linkType != NO_LINK){
map[firstRow][firstCol] = 0;
map[secondRow][secondCol] = 0;
b = true;
}
//選擇的塊數(shù)初始化
selectTileNum = 0;
return b;
}
}