作者:雷神QQ:38929568
QQ群:28048051(满)28047782(将满)

新建一个j2me midlet工程
在src里添加如下连个类
Minesweeper.java     
cGame.java

详尽注释,方便初学者!

工程文件如附件所示,地址如下:扫雷(不含线程)

程序运行如图

 

 
  
  1. ///////////////////////////////////////////////////////////////////////////////////////////////////  
  2. //  
  3. // Minesweeper.java  
  4. //  
  5. // Project: Minesweeper  
  6. // Author(s): Gao Lei  
  7. // Create: 2007-10-08  
  8. ///////////////////////////////////////////////////////////////////////////////////////////////////  
  9. import javax.microedition.midlet.*;    //j2me MIDlet程序必须继承MIDlet类,所以要引入此包  
  10. import javax.microedition.lcdui.*;    //Display这个类所在包  
  11.  
  12. ///////////////////////////////////////////////////////////////////////////////////////////////////  
  13.  
  14. public class Minesweeper extends MIDlet   
  15. ...{  
  16.     static Minesweeper s_midlet;    //MIDlet类的静态对象,方便实用 MIDlet类方法  
  17.     static Display s_display = null;//用来显示 Canvas  
  18.     static cGame s_game = null;        //Canvas类对象,主要实现游戏的类  
  19.       
  20.     public Minesweeper()  
  21.     ...{  
  22.         s_midlet = this;  
  23.     }  
  24.       
  25.     /** *//**  
  26.      * 程序开始 系统会调用这个函数  
  27.      * 也有些手机 可以把程序初始化部分放到构造函数里,这连个地方应视手机的不同而定!  
  28.      */ 
  29.     public void startApp()               
  30.     ...{  
  31.         if (s_display == null)   
  32.         ...{  
  33.             s_display = Display.getDisplay(this);//创建Display对象,参数是MIDlet类对象,也就是我们当前写的这个Minesweeper类  
  34.         }  
  35.  
  36.         if (s_game == null)   
  37.         ...{  
  38.             s_game = new cGame();                //创建 Canvas对象  
  39.             s_display.setCurrent(s_game);        //把Canvas对象设置成当前显示  
  40.         }   
  41.         else   
  42.         ...{  
  43.             s_display.setCurrent(s_game);  
  44.         }  
  45.     }  
  46.  
  47.     /** *//**  
  48.      * 程序暂停 系统会自动调用这个函数,不是所有手机都支持,  
  49.      * 手机在接到中断,如 来电,来短信时候会调用这个函数,这个函数 通常是空的!  
  50.      */ 
  51.     public void pauseApp()           
  52.     ...{  
  53.           
  54.     }  
  55.  
  56.     /** *//**  
  57.      * 程序关闭 系统会调用这个函数,如果希望关闭程序的时候保存数据,可在这个函数里添加保存数据的方法  
  58.      * 比如游戏进行中,按了关机键,程序就会调用这个函数,也可以在程序中调用这个函数来结束游戏!  
  59.      */ 
  60.     public void destroyApp(boolean unconditional)   
  61.     ...{  
  62.         notifyDestroyed();  
  63.     }  

cGame.java

代码如下

 
  
  1. ////////////////////////////////////////////////////////////////////////////////  
  2. //  
  3. // cGame.java  
  4. //  
  5. // Project: Minesweeper  
  6. // Author(s): Gao Lei  
  7. // Create: 2007-10-08  
  8. ////////////////////////////////////////////////////////////////////////////////  
  9. import java.util.Random;            //得到 随机函数  
  10. import javax.microedition.lcdui.*;    //写界面所需要的包  
  11.  
  12. ////////////////////////////////////////////////////////////////////////////////  
  13.  
  14. class cGame extends Canvas   
  15. ...{  
  16.     public static int      s_width = 0;    //屏幕尺寸 宽  
  17.     public static int      s_height= 0;    //屏幕尺寸 高  
  18.     public static Random rand;            //随机数对象  
  19.     private int UP         = 1;            //定义键值 上  
  20.     private int DOWN     = 2;            //定义键值 下  
  21.     private int LEFT     = 3;            //定义键值 左  
  22.     private int RIGHT     = 4;            //定义键值 右  
  23.     private int FILE     = 5;            //定义键值 中间确认键  
  24.     private int map_x     = 10;    // 15    //雷区的 行数  
  25.     private int map_y     = 10;    // 12    //雷区的 列数  
  26.     private int map_w     = 20;            //一个雷区的格子的宽度  
  27.     private int map_h     = 20;            //一个雷区的格子的高度  
  28.     private int key_x     = map_x / 2;    //游戏初始时 光标所在雷区的格子位置  
  29.     private int key_y     = map_y / 2;    //游戏初始时 光标所在雷区的格子位置  
  30.     private int mine_num= 10;            //雷区的雷数 不应该大于雷区的格子总数  
  31.     private int[][] map;                //雷区的地图数组 >=10 为雷, <10 为周围的雷数, 0位附近没有雷  
  32.     private boolean[][] map_show;        //雷区的地图数组 是否显示 该位置的雷数  
  33.     private boolean isGameOver = false;    //游戏是否结束  
  34.       
  35.     cGame()  
  36.     ...{  
  37.         setFullScreenMode(true);        //设置游戏为全屏幕模式,该函数只能在支持midp2.0的手机上使用  
  38.         s_width = getWidth();            //得到屏幕尺寸 宽  
  39.         s_height= getHeight();            //得到屏幕尺寸  高  
  40.         rePlay();                        //游戏初始化//重新游戏  
  41.     }  
  42.       
  43.     /** *//**  
  44.      * 系统自动调用该绘图函数,并传入绘图设备g,通过该设备,我们可以绘制如直线,矩形快,字符串,图片等,  
  45.      */ 
  46.     public void paint(Graphics g)  
  47.     ...{  
  48.         g.setClip(00, s_width, s_height);        //设置参数描述的区域为操作区  
  49.         g.setColor(0x000000);                    //设置颜色为 黑色, 三个16进制数表示,RGB,如0x00ff00 为绿色  
  50.         g.fillRect(00, s_width, s_height);    //绘制一个实心矩形区域  
  51.         g.setColor(0xFFFFFF);                    //设置颜色为 白色  
  52.         //绘制雷区  
  53.         forint i=0; i<=map_y; i++ )    // |||    //画 map_y+1条竖线  
  54.         ...{  
  55.             g.drawLine(i*map_w, 0, i*map_w, map_h*map_x);  
  56.         }  
  57.         forint i=0; i<=map_x; i++ )     // ---    //画 map_x+1条横线  
  58.         ...{  
  59.             g.drawLine(0, i*map_h, map_y*map_w, i*map_h);  
  60.         }  
  61.  
  62.         g.setColor(0xFF0000);                    //设置颜色 红  
  63.         g.drawRect(key_x*map_w+1, key_y*map_h+1, map_w-2, map_h-2);    //绘制一个空心矩形框  
  64.           
  65.         forint i=0; i<map_x; i++ )              
  66.         ...{  
  67.             forint j=0; j<map_y; j++ )  
  68.             ...{  
  69.                 if( map_show[i][j] )            //遍历地图数组 看该位置的雷数 是否应该显示  
  70.                     g.drawString(""+map[i][j], j*map_h+5, i*map_w+50);    //显示该位置的雷数  
  71.             }      
  72.         }  
  73.         if( isGameOver )                        //如果游戏 结束  
  74.             g.drawString("GAME OVER", s_width/2, s_height, g.HCENTER|g.BOTTOM);    //显示 GAME OVER  
  75.     }  
  76.  
  77.     /** *//**  
  78.      * 系统自动调用该函数,当有键盘事件发生为按下某键,参数key为按下键的键值  
  79.      */ 
  80.     public void keyPressed(int key)  
  81.     ...{  
  82.         key = Math.abs(key);  
  83.         System.out.println("key="+key);  
  84.         //上下左右 为移动光标事件,只需要调整光标位置即可,但需要做边界判断  
  85.         if( key == this.UP )  
  86.         ...{  
  87.             key_y--;  
  88.             if( key_y<0 )      
  89.                 key_y = 0;  
  90.         }  
  91.         else if( key == this.DOWN )  
  92.         ...{  
  93.             key_y++;  
  94.             if( key_y>=map_x-1 )  
  95.                 key_y =map_x-1;  
  96.         }  
  97.         else if( key == this.LEFT )  
  98.         ...{  
  99.             key_x--;  
  100.             if( key_x<0 )      
  101.                 key_x = 0;  
  102.         }  
  103.         else if( key == this.RIGHT )  
  104.         ...{  
  105.             key_x++;  
  106.             if( key_x>=map_y-1 )  
  107.                 key_x =map_y-1;  
  108.         }  
  109.         else if( key==FILE || key==KEY_NUM5)//按下的为确定键  
  110.         ...{  
  111.             if( !isGameOver )                //如果游戏没结束    //结束了就不做确认键操作了      
  112.             ...{  
  113.                 showMap( key_y, key_x );    //显示该位置的雷数  
  114.                 if( map[key_y][key_x] >=10 )//如果雷数>=10 该位置是雷,  
  115.                     isGameOver = true;        //游戏结束  
  116.             }  
  117.         }  
  118.         else if( key == this.KEY_NUM0 )        //当按下 数字键 0  
  119.         ...{  
  120.             rePlay();                        //重新开始游戏  
  121.         }  
  122.         /** *//**  
  123.          * 重新执行 paint() 但该函数是立刻返回,也就是说他不会等待paint()执行完毕就返回了,  
  124.          * 如果 需要 paint()执行完毕才返回,可以使用serviceRepaints(),也可以两个都是用,但  
  125.          * repaint()应该在serviceRepaints()之前.  
  126.          */ 
  127.         this.repaint();                        //本例为键盘事件驱动,刷新函数也就是每次按下键盘才作  
  128.     }  
  129.  
  130.     //该函数是一个递归函数,把当前位置设置成显示,并判断当前位置雷数是否为0个  
  131.     //如果是0个雷,那么它周围的8个格子都要再作一次showMap  
  132.     void showMap(int x, int y)  
  133.     ...{  
  134.         if( map_show[x][y] )  
  135.             return;  
  136.         else 
  137.             map_show[x][y] = true;  
  138.         if( map[x][y] == 0 )  
  139.         ...{  
  140.             if( x-1 >= 0 )  
  141.             ...{  
  142.                 showMap( x-1, y );  
  143.                 if( y-1 >= 0)        showMap( x-1, y-1 );  
  144.                 if( y+1 < map_y)    showMap( x-1, y+1 );  
  145.             }  
  146.             if( y-1 >= 0)            showMap( x  , y-1 );  
  147.             if( y+1 < map_y)        showMap( x  , y+1 );  
  148.             if( x+1 < map_x )  
  149.             ...{  
  150.                 showMap( x+1, y );  
  151.                 if( y-1 >= 0)        showMap( x+1, y-1 );  
  152.                 if( y+1 < map_y)    showMap( x+1, y+1 );  
  153.             }  
  154.         }  
  155.           
  156.     }  
  157.       
  158.     //重新 开始 游戏  
  159.     public void rePlay()  
  160.     ...{  
  161.         isGameOver    = false;  
  162.         map          = new int        [map_x][map_y];  
  163.         map_show     = new boolean    [map_x][map_y];  
  164.         rand        = new Random( System.currentTimeMillis() );    //用事件作随机数种子的随机数  
  165.         //布雷  
  166.         for(int i=0; i<mine_num; i++)    //随机mine_num个雷的位置  
  167.         ...{  
  168.             int x = rand.nextInt( map_x );    //得到 随机数 雷格子的x方向位置  
  169.             int y = rand.nextInt( map_y );    //得到 随机数 雷格子的y方向位置  
  170.             if( map[x][y] >= 10)            //如果该位置已经是雷了,就要重新布雷  
  171.             ...{      
  172.                 i--;  
  173.                 continue;  
  174.             }  
  175.             map[x][y] = 10;                    //否则 将该位置 设定为雷  
  176.             //并在该雷的周围 的雷数都作+1操作  
  177.             //以下判断为 边角判断,防止访问数组越界  
  178.             if( x-1 >= 0 )                      
  179.             ...{  
  180.                 map[x-1][y  ] += 1;  
  181.                 if( y-1 >= 0)        map[x-1][y-1] += 1;  
  182.                 if( y+1 < map_y)    map[x-1][y+1] += 1;  
  183.             }  
  184.             if( y-1 >= 0)        map[x  ][y-1] += 1;  
  185.             if( y+1 < map_y)    map[x  ][y+1] += 1;  
  186.             if( x+1 < map_x )  
  187.             ...{  
  188.                 map[x+1][y  ] += 1;  
  189.                 if( y-1 >= 0)        map[x+1][y-1] += 1;  
  190.                 if( y+1 < map_y)    map[x+1][y+1] += 1;  
  191.             }  
  192.         }  
  193.     }  

这样200行的小游戏就做好了!可以玩了, 不过,这个还没有完成,没有标志是雷,和全部找到雷的成功完成游戏界面,只是基本的布雷,挖雷,在下一篇,我们将完善这个小游戏!