|
|
//界面类代码 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(){ //创建对象 engine = new GameEngine(); //获得屏幕的高度和宽度 width = getWidth(); height = getHeight(); //启动线程 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){ //延时 Thread.sleep(100); //每次判断逻辑 engine.action(); repaint(); } }catch(Exception e){ e.printStackTrace(); } } }
//逻辑类源代码 import java.util.*; import javax.microedition.lcdui.*; /** * 游戏数据和逻辑类 */ public class GameEngine { /**选中块的个数*/ private int selectTileNum = 0; //第一个选择块的行号和列号 /**行号*/ private int firstRow; /**列号*/ private int firstCol; //第二个选择块的行号和列号 /**行号*/ private int secondRow; /**列号*/ private int secondCol; //当前选择框,默认在左上角 /**当前选择框的行号*/ private int cRow; /**当前选择框的列号*/ private int cCol; /**最大行数*/ private final int MAX_ROW = 10; /**最大列数*/ private final int MAX_COL = 10; /**地图数据,0代表空,数据1-10分别代表十种不同的结构*/ private int[][] map = new int[MAX_ROW][MAX_COL]; /**随机数对象*/ private Random ran = new Random(); //地图区域左上角的坐标 private final int LEFTX = 20; private final int LEFTY = 50; /**每个单元格的宽度*/ private final int TILE_WIDTH = 20; /**每个单元格的高度*/ private final int TILE_HEIGHT = 20; /**连线类型*/ private int linkType; /**无法连线*/ private final int NO_LINK = 0; /**水平连线*/ private final int H_LINK = 1; /**垂直联系*/ private final int V_LINK = 2; /**一个拐点,先移动x*/ private final int ONE_CORNER_FIRSTX = 3; /**一个拐点,先移动y*/ private final int ONE_CORNER_FIRSTY = 4; /**两个拐点,待完善*/ private final int TWO_CORNER = 5; /** * 两次拐弯的行号和列号 * 数据格式为: * 第一个拐点的行号,第一个拐点的列号,第二个拐点的行号,第二个拐点的列号 */ int[] p = new int[4]; public GameEngine(){ //初始化地图数据 initMap(); } /** * 初始化地图数据 */ 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; } } //循环打乱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++){ //随机行号 tempRow = Math.abs(ran.nextInt() % 10); //随机列号 tempCol = Math.abs(ran.nextInt() % 10); //如果不是同一个单元格,则交换数据 if(!((tempRow == row) && (tempCol == col))){ temp = map[row][col]; map[row][col] = map[tempRow][tempCol]; map[tempRow][tempCol] = temp; } } } } } /** * 绘制地图数据 * @param g 画笔 */ public void paintMap(Graphics g){ for(int row = 0;row < map.length;row++){ for(int col = 0;col < map[row].length;col++){ //如果没有数据,则跳过 if(map[row][col] == 0){ continue; }else{//绘制方块 //绘制方框 g.drawRect(LEFTX + col * TILE_WIDTH, LEFTY + row * TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT); //绘制数字 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){ //绘制当前选择框 g.setColor(0xff00); g.drawRect(LEFTX + cCol * TILE_WIDTH, LEFTY + cRow * TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT); g.setColor(0); //绘制选中项 switch(selectTileNum){ case 1: //选择一个 g.setColor(0xff0000); g.drawRect(LEFTX + firstCol * TILE_WIDTH, LEFTY + firstRow * TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT); g.setColor(0); break; case 2: //选中两个 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; } //根据连线类型实现绘制 //绘制到方块的中心点 switch(linkType){ case H_LINK://水平 case V_LINK://垂直 paintLine(g,firstRow,firstCol,secondRow,secondCol); break; case ONE_CORNER_FIRSTX://一个拐弯,先移动X //水平线 paintLine(g,firstRow,firstCol,firstRow,secondCol); //垂直线 paintLine(g,firstRow,secondCol,secondRow,secondCol); break; case ONE_CORNER_FIRSTY://一个拐弯,先移动Y //水平线 paintLine(g,firstRow,firstCol,secondRow,firstCol); //垂直线 paintLine(g,secondRow,firstCol,secondRow,secondCol); break; case TWO_CORNER: //块1到第一个拐点的连线 paintLine(g,firstRow,firstCol,p[0],p[1]); //两个拐点之间的连线 paintLine(g,p[0],p[1],p[2],p[3]); //第二个拐点到块2的连线 paintLine(g,p[2],p[3],secondRow,secondCol); break; } //逻辑代码,清除连接类型 linkType = NO_LINK; } /** * 绘制两个方块中心点的连线 * @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); } /** * 向左移动选择框 */ public void moveLeft(){ if(cCol > 0){ cCol--; } } /** * 向右移动选择框 */ public void moveRight(){ if(cCol < MAX_COL -1){ cCol++; } } /** * 向上移动选择框 */ public void moveUP(){ if(cRow > 0){ cRow--; } } /** * 向下移动选择框 */ public void moveDown(){ if(cRow < MAX_ROW - 1){ cRow++; } } /** * 确定键逻辑处理 */ public void fire(){ //如果选择的块为空,则直接返回 if(map[cRow][cCol] == 0){ return; } //选中的块的数量增加1 selectTileNum++; //判别存储位置 switch(selectTileNum){ case 1: //第一次选择 firstRow = cRow; firstCol = cCol; break; case 2: //第二次选择 //选择同一个块,2个选择块都失去选中 if((firstRow == cRow) && (firstCol == cCol)){ selectTileNum = 0; return; } secondRow = cRow; secondCol = cCol; break; } } /** * 判断(r1,c1)块和(r2,c2)块中间是否为空行 * 不包含这两个块 * @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; } //判断两个块的相对位置 if(c1 > c2){ //第一块位于右侧 for(int col = c1 - 1;col > c2;col--){ //如果有非空块 if(map[r1][col] != 0){ return false; } } }else{ //第一块位于左侧 for(int col = c2 - 1;col > c1;col--){ //如果有非空块 if(map[r1][col] != 0){ return false; } } } return true; } /** * 判断块(r1,c1)和块(r2,c2)之间是否是空列 * 不包含这两个块 * @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; } //判断两个块的相对位置 if(r2 > r1){//第一个块在上方 for(int row = r1 + 1;row < r2;row++){ //如果有非空块 if(map[row][c1] != 0){ return false; } } }else{//第二个块在上方 for(int row = r2 + 1;row < r1;row++){ //如果有非空块 if(map[row][c1] != 0){ return false; } } } return true; } /** * 判断一个块是否为空 * @param r 块的行号 * @param c 块的列号 * @return true代表为空,false代表不空 */ private boolean isEmptyCell(int r,int c){ return map[r][c] == 0; } /** * 是否是一次转弯实现连线 * @return NO_LINK代表没有连线,其他值代表对应的连线类型 */ private int isOneCornerLink(int r1,int c1,int r2,int c2){ //先移动行,再移动列 if(isEmptyCell(r1,c2)){ //转折点为空 if(isEmptyRow(r1,c1,r1,c2) & isEmptyCol(r1,c2,r2,c2)){ return ONE_CORNER_FIRSTX; } } //先移动列,再移动行 if(isEmptyCell(r2,c1)){//转折点为空 if(isEmptyCol(r1,c1,r2,c1) & isEmptyRow(r2,c1,r2,c2)) { return ONE_CORNER_FIRSTY; } } //无连接 return NO_LINK; } /** * 是否经过2次转折实现连接 * @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个方向 //块1向上 for(int row = r1 -1;row >= 0;row--){ //如果有数据不为空,则直接结束该方向的尝试 if(map[row][c1] != 0){ break; } //存储第一个拐点的坐标 p[0] = row; p[1] = c1; //每次都尝试转折,则变成一个转点的操作 result = isOneCornerLink(row,c1,r2,c2); //如果可以连接 if(result != NO_LINK){ //存储第二个拐点的位置 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++){ //如果有数据不为空,则直接结束该方向的尝试 if(map[row][c1] != 0){ break; } //存储第一个拐点的坐标 p[0] = row; p[1] = c1; //每次都尝试转折,则变成一个转点的操作 result = isOneCornerLink(row,c1,r2,c2); //如果可以连接 if(result != NO_LINK){ //存储第二个拐点的位置 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--){ //如果有数据不为空,则直接结束该方向的尝试 if(map[r1][col] != 0){ break; } //存储第一个拐点的坐标 p[0] = r1; p[1] = col; //每次都尝试转折,则变成一个转点的操作 result = isOneCornerLink(r1,col,r2,c2); //如果可以连接 if(result != NO_LINK){ //存储第二个拐点的位置 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++){ //如果有数据不为空,则直接结束该方向的尝试 if(map[r1][col] != 0){ break; } //存储第一个拐点的坐标 p[0] = r1; p[1] = col; //每次都尝试转折,则变成一个转点的操作 result = isOneCornerLink(r1,col,r2,c2); //如果可以连接 if(result != NO_LINK){ //存储第二个拐点的位置 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; } } //四个特例,也就是超出地图区域的连接 //实现地图区域上侧的连接,也就是到上侧是一个空列 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; } //左侧 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; } //下侧 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; } //右侧 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代表无连线,其它数据代表有连线 */ private int logic(){ //如果数值不同 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; } //一个转点的连接 int result = isOneCornerLink(firstRow,firstCol,secondRow,secondCol); if(result != NO_LINK){ return result; } //两个转点的连接 if(isTwoCornerLink(firstRow,firstCol,secondRow,secondCol)){ return TWO_CORNER; } //返回无连接 return NO_LINK; } /** * 逻辑判别和逻辑处理 */ public boolean action(){ //判断是否选择两个方块 if(selectTileNum != 2){ return false; } boolean b = false; //判断是否有连线 linkType = logic(); //如果有连线,则消失 if(linkType != NO_LINK){ map[firstRow][firstCol] = 0; map[secondRow][secondCol] = 0; b = true; } //选择的块数初始化 selectTileNum = 0; return b; } } |
|
|
|
|
|