广

Java编程

  • IOS开发
  • android开发
  • PHP编程
  • JavaScript
  • ASP.NET
  • ASP编程
  • JSP编程
  • Java编程
  • 易语言
  • Ruby编程
  • Perl编程
  • AJAX
  • 正则表达式
  • C语言
  • 编程开发

    J2ME-MIDP1.0小游戏入门-五子棋1.0

    2018-10-13 10:38:34 次阅读 稿源:互联网
    零七广告


       作者:yinowl
      2005年1月
      
      介绍
      这是我学习j2me入门后的第一个作品,当然这也是一个极其简单的作品(没有电脑AI,只能是两个人对战),现在我把当时的设计思路写成这篇文档,希望对想入门j2me的朋友在j2me的流程,按键响应,绘图等方面有所帮助,同时也希望大家指出错误和改进程序。
      
      注重
      代码列出解释的形式仿照《J2ME Game Programming》一书,按照程序功能思路给出相关代码,一个文件的代码会根据功能在不同的小节给出,文章结束了,代码也就完整了。这不同于通常书中的代码以文件为单位一次全部给出,我认为这样更有助于让大家了解一个程序从设计到最后完成的思路。
      
      设计
      数据结构:由于五子棋是一个二维棋类游戏,所有首先想到的是定义一个Chesses类来表示棋子,Chesses有一个boolean型的变量isPlayer1来区分该棋子是哪玩家下的,然后用一个Chess类型的二维数组来包含棋盘上的所有棋子。考虑到移动设备的资源有限,尽可能减少系统资源占用,我考虑不在数组建立后直接生成数组的每一个对象,而是把每一个棋子对象(Chesses)放在游戏的进行中生成,也就是说在游戏进行时,玩家每下一步棋,在数组相应位置生成该棋子的对象,这样可以避免还没有下的棋子在一开始就占用了系统内存
      流程:游戏按照棋子的二维数组进行绘制棋子,玩家下棋后,程序修改数组相应位置,设置isPlayer1值,然后重新绘制(repaint),就更新了棋盘界面。由于游戏的功能简单,也为了使游戏的操作尽可能的简便,我不在游戏进入时设计菜单,而是直接开始对战,在对战界面,设置了重新开始和退出的按钮。即运行即玩,一键开始,一键重来,一键退出。
      玩家切换:棋类游戏有一个问题需要注重,就是提示当前由哪方下棋,为了节省界面空间,简化游戏界面,我在棋盘外围加了一个3个像素宽的框,框的颜色就是当前下棋方的颜色,如图:
         
      
      应用程序类:Gobang.Java
      接下来就开始完成游戏中的每一个类,首先就是一个MIDlet类。Gobang类继续自MIDlet类,用于连接设备的应用程序治理器(Application Manager),通过方法startApp,pauseApp,destroyApp来通知游戏的开始,暂停和销毁结束。源代码如下:
      
      
      package com.occo.j2me.game.gobang;
      
      import javax.microedition.lcdui.Display;
      import javax.microedition.midlet.MIDlet;
      public class Gobang extends MIDlet {
          GobangCanvas gobang;//定义游戏界面的Canvas类GobangCanvas的对象gobang
          public Gobang() {
              super();
              gobang=new GobangCanvas(this);//生成GobangCanvas类的对象gobang
          }
          protected void startApp(){
              Display.getDisplay(this).setCurrent(gobang);
                //在屏幕上绘出游戏见面gobang
          }
          protected void pauseApp(){
          }
          protected void destroyApp(boolean arg0){
          }
      }
      
      
      游戏界面类:GobangCanvas.java
      GobangCanvas类是游戏的核心类,继续自Canvas,此类将完成游戏的逻辑、绘图、控制、互动等所有功能,此类的框架代码如下:
      
      package com.occo.j2me.game.gobang;
      import javax.microedition.lcdui.Canvas;
      import javax.microedition.lcdui.Command;
      import javax.microedition.lcdui.CommandListener;
      import javax.microedition.lcdui.Displayable;
      import javax.microedition.lcdui.Graphics;
      public class GobangCanvas extends Canvas implements CommandListener{
          protected Gobang gobang;
      
          public GobangCanvas(){
          }
          public GobangCanvas(Gobang gobang){
              this.gobang=gobang;
          }
          protected void paint(Graphics g) {
          }
      }
      
      
      棋子类:Chesses.java
      此类定义了一个棋子,棋盘上的每一个棋子都对应着一个Chesses的对象,整个棋盘是一个Chesses类型的二维数组,源代码如下:
      
      package com.occo.j2me.game.gobang;
          public class Chesses {
          boolean isPlayer1;
      
          public Chesses() {
          }
          public Chesses(boolean isPlayer1) {
              this.isPlayer1=isPlayer1;
          }
      }
      
      
      添加图形图像
      到现在,我们已经完成了游戏的一个基本框架,接下来,我们就可以来绘制游戏的每一个部件了
      首先是五子棋的一些初始设置,添加如下代码到GobangCanvas.java
      
          ...
          int empty;//游戏界面到屏幕边缘的留空
          int canvasW,canvasH;//画布的长和宽
          int chessLength;//棋子的直径
          int chessMapLength,chessMapGrid,chessGridLength;
              //棋盘的边长,棋盘一边格子数,每格宽度
          int chessMapX,chessMapY;//棋盘左上角x,y坐标
          int selectedX,selectedY;//选择框在棋盘格局上的x,y位置
          boolean isPlayer1;//是否是玩家1
          Chesses[][] chesses;//棋子数组
          boolean newGame;//是否是新的游戏
          public GobangCanvas(Gobang gobang){
              newGame=true;
              empty=10;
              canvasW=getWidth()-empty;canvasH=getHeight()-empty;
              chessMapGrid=15;
              chesses=new Chesses[chessMapGrid+1][chessMapGrid+1];
              if(canvasW>canvasH){
                  chessMapLength=canvasH-canvasH%chessMapGrid;
                  chessMapX=(canvasW-chessMapLength)/2+empty/2;
                  chessMapY=(canvasH%chessMapGrid)/2+empty/2;
              }
              else{
                  chessMapLength=canvasW-canvasW%chessMapGrid;
                  chessMapX=(canvasW%chessMapGrid)/2+empty/2;
                  chessMapY=(canvasH-chessMapLength)/2+empty/2;
              }
              chessGridLength=chessMapLength/chessMapGrid;
              chessLength=chessGridLength-1;
              selectedX=selectedY=chessMapGrid/2;
              isPlayer1=true;
          }
      
      
      最先要绘制的是棋盘,棋盘是正方形,但屏幕有矩形的,所以棋盘边长要按短边计,但短边未必是棋盘格子数的整数倍,因此
          棋盘边长 = 短边 - 短边 % 格子数
      因为棋盘要居中,所以在算左上角坐标时,记得也要把留空(empty)除以2,以下是画棋盘的代码:
      
          protected void paintMap(Graphics g){
              for(int i=0;i<chessMapGrid;i++){
                  for(int j=0;j<chessMapGrid;j++){
                      g.setColor(128,128,128);
                      g.drawRect(chessMapX+j*chessGridLength,
                                    chessMapY+i*chessGridLength,
                                    chessGridLength,chessGridLength);
                  }
              }
          }
      
      
      然后是绘制选择框,注重:选择框的selectedX,selectedY并不是在画布上的x,y坐标,而是在棋子数组(chesses)中的位置,源代码如下:
      
          protected void paintSelected(Graphics g){
              g.setColor(0,0,255);
              g.drawRect(chessMapX+selectedX*chessGridLength-chessGridLength/2,
                        chessMapY+selectedY*chessGridLength-chessGridLength/2,
                        chessGridLength,chessGridLength);
          }
      
      
      接着是按照棋子二维数组绘制已经下了的棋子。玩家每下一次棋,就修改数组,在重新绘图的时候就能绘出,源代码如下:
      
          protected void paintChesses(Graphics g){
              for(int i=0;i<=chessMapGrid;i++){
                  for(int j=0;j<=chessMapGrid;j++){
                      if(chesses[i][j]!=null){
                          if(chesses[i][j].isPlayer1)
                              g.setColor(255,255,255);
                          else
                              g.setColor(255,0,0);
                          g.fillArc(chessMapX+j*chessGridLength-chessLength/2,
                                  chessMapY+i*chessGridLength-chessLength/2,
                                  chessLength,chessLength,0,360);
                      }
                  }
              }
          }
      
      
      最后是绘制玩家提示框,并且把所有部件的绘制汇总在paint()方法中,注重绘制的顺序,显而易见,应该先绘制提示框-棋盘-选择框-棋子:
      
          protected void paintPlayer(Graphics g,boolean isPlayer1){
              if(isPlayer1)
                  g.setColor(255,255,255);
              else
                  g.setColor(255,0,0);
              g.drawRect(1,1,getWidth()-2,getHeight()-2);
              g.drawRect(2,2,getWidth()-4,getHeight()-4);
              g.drawRect(3,3,getWidth()-6,getHeight()-6);
          }
          protected void paint(Graphics g) {
              g.setColor(0x00000000);
              g.fillRect(0, 0, getWidth(), getHeight());
              paintPlayer(g,isPlayer1);
              paintMap(g);
              paintSelected(g);
              paintChesses(g);
          }
      
      
      响应玩家操作
      接下来应该添加命令按钮和游戏操作控制。我们在游戏中需要有两个按钮,重新开始和退出,此外还必须接收玩家控制选择框的操作上下左右和着棋,添加代码到GobangCanvas.java:
      
          Command exitCmd;
          Command restartCmd;
          public GobangCanvas(Gobang gobang){
              ...
              restartCmd = new Command("重新开始", Command.SCREEN, 0);
              exitCmd = new Command("退出", Command.EXIT, 0);
              addCommand(restartCmd);
              addCommand(exitCmd);
              setCommandListener(this);
          }
          private void init(){
              if(newGame){
                  chesses=new Chesses[chessMapGrid+1][chessMapGrid+1];
                  isPlayer1=true;
                  selectedX=selectedY=chessMapGrid/2;
              }
          }
          public void commandAction(Command c, Displayable d) {
              if (c == exitCmd) {
                  gobang.destroyApp(false);
                  gobang.notifyDestroyed();
              }else if(c==restartCmd){
                  init();//初始化棋盘,把棋盘清空,重新开始游戏
                  repaint();
              }
          }
          protected synchronized void keyPressed(int keyCode) {
              int action = getGameAction(keyCode);
              if (action == Canvas.LEFT ) {
                  selectedX=(--selectedX+chessMapGrid+1)%(chessMapGrid+1);     
              }
              else if (action == Canvas.RIGHT) {
                  selectedX=(++selectedX)%(chessMapGrid+1);
              }
              else if (action == Canvas.UP) {
                  selectedY=(--selectedY+chessMapGrid+1)%(chessMapGrid+1);
              }
              else if (action == Canvas.DOWN) {
                  selectedY=(++selectedY)%(chessMapGrid+1);
              }
              else if (action == Canvas.FIRE) {
                  if(chesses[selectedY][selectedX]==null){
                      chesses[selectedY][selectedX]=new Chesses(this.isPlayer1);
                      //checkWin();
                      this.isPlayer1=!this.isPlayer1;//切换下棋方
                  }
              }
              repaint();
          }
          private void checkWin(){
          }
      
      
      至此,游戏的所有绘图部分全都给出,有一点需要指出,双缓冲显示技术,由于现在有的手机已直接内置了双缓冲,这里我们就不在具体说明,有爱好可以查阅相关文档。
      
      游戏输赢
      最后要说的是判定游戏的输赢,在游戏的响应玩家操作部分,我留有一个方法checkWin(),大家可以自己思考设计算法来判定游戏的输赢,其实不要也无所谓,因为既然是两个人类在下棋,输赢一眼就看出来了。
      
      总结
      整个游戏已经全部完成,大家一定会觉得很简单吧,这个游戏其实只使用了j2me-midp1.0种很少的内容,但已经是一个完整的游戏了,希望对一些朋友有所帮助。当然我们完全可以进行一些扩展,比如加上片头动画,加上声音,加上电脑AI,加上蓝牙对战功能(已经完成,下次专门写一篇文档),这样游戏就慢慢的完善,并且具有商业价值,愿大家学J顺利,多多交流(MSN:yinowl@163.com QQ:47599318 E-mail:yinowl@163.com)。


     

    零七网部分新闻及文章转载自互联网,供读者交流和学习,若有涉及作者版权等问题请及时与我们联系,以便更正、删除或按规定办理。感谢所有提供资讯的网站,欢迎各类媒体与零七网进行文章共享合作。

    零七广告
    零七广告
    零七广告
    零七广告