svse吧 关注:17贴子:2,313
  • 4回复贴,共1

J2ME连连看基础功能源代码(含详细注释)

取消只看楼主收藏回复

J2ME连连看基础功能源代码(含详细注释)
作者:陈跃峰
出自: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(){
        //创建对象
        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;



1楼2008-05-07 23:07回复
        
        /**连线类型*/
        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);
    


    2楼2008-05-07 23:07
    回复
                  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++;
              //判别存储位置
      


      3楼2008-05-07 23:07
      回复
                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)) {
        


        4楼2008-05-07 23:07
        回复
                          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向右
          


          5楼2008-05-07 23:07
          回复