`
CnXiaowei
  • 浏览: 49796 次
社区版块
存档分类
最新评论

J2ME手机编程心得(三)

阅读更多

   上一次已经做完了第一个简单的J2ME程序,但是可能大家最关心的还是如何用J2ME制作手机游戏吧!不要急,一步一步来,现在就开始做我们的第一个J2ME小游戏吧!

    很多人应该都玩过贪吃蛇的游戏吧,那么现在我们就要做一个贪吃蛇的手机游戏了!OK,准备好工具,建立工程,名字就叫做SnakeGame,再建立一个Midlet,名字也是SnakeGame,还要建一个游戏的Screen.起名叫做GameScreen。

    首先我们考虑一下游戏中会出现的算法,首先,贪吃蛇应该是可以在屏幕上运动的(好像是废话?),而它的身体长度又是随着游戏的进行而变化的,因此,这里我们用一个数组来保存贪吃蛇每个身体单元(可以理解为身体的一小段)在屏幕中的位置,为什么采用数组而不采用Vector呢,因为Vector效率没有直接用数组高,J2ME程序由于资源的限制是要把效率放在首位的。数组定义好了,接下来就是如何控制贪吃蛇运动。首先贪吃蛇始终要有一个运动方向,或上或下或左或右,而四个方向对于屏幕的坐标变化是各不相同的,但我们可以找出些规律来利用。我们用direction表示贪吃蛇运动的方向,比如向上,direction=0,向下direction=1,左direction=2,右direction=3,然后定义两个对应坐标变化的数组,

dirX[] = { 0, 0, -1, 1};

dirY[] = {  -1, 1, 0, 0};

这样,贪吃蛇的头部的下一个坐标就可以用(dirX[direction],dirY[direction])来表示。

每次运动,头部都会获得一个新的坐标,而后面的身体依次前进,第i+1块身体对应于运动之前的第i块身体。运动的过程可以如下表示:

        int newX, newY;
        newX = posX + dirX[direction];
        newY = posY + dirY[direction];
        for (int i = count - 1; i > 0; i--) {
          snakeData[i].x = snakeData[i - 1].x;
          snakeData[i].y = snakeData[i - 1].y;
        }
        snakeData[0].x = newX;
        snakeData[0].y = newY;
        posX = newX;
        posY = newY;

这样,贪吃蛇的运动就可以很简单的实现了。

接下来就是遇到它喜欢吃的东西的时候的处理了,也很简单,就是相当于加了一个头部(其实是数组多了一个数据)。

为了提高游戏的难度,这里的规则是每次吃掉一个食物,就会随机出现一个新的食物和障碍物。因此在游戏进行当中,食物是只有一个(当然也可以修改程序让贪吃蛇有更多的食物),而障碍物是一直增加的。

还有就是按键的处理,这里并没有用Cavans的事件处理,而是用了一个专门为游戏设计的GameCavans类,在一个线程中来获取按键的状态和处理贪吃蛇的位置以及其他游戏的信息。

有了这些准备,做一个类似的小游戏还是比较简单的。下边是程序源代码:

package snakegame;

import javax.microedition.lcdui.*;
import javax.microedition.lcdui.game.GameCanvas;
import java.util.Random;
import java.io.*;

import javax.microedition.rms.RecordStore;
import javax.microedition.rms.*;
/**
 *
 * <p>Title: 贪吃蛇坐标的类</p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2005</p>
 * <p>Company: </p>
 * @author not attributable
 * @version 1.0
 */
class SnakePos {
  int x, y;
  public SnakePos(int x, int y) {
    this.x = x;
    this.y = y;
  }
}
/**
 *
 * <p>Title: 游戏屏幕</p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2005</p>
 * <p>Company: </p>
 * @author 大糊涂
 * @version 1.0
 */
public class GameScreen
    extends GameCanvas
    implements Runnable, CommandListener {
  private int DIR_UP = 0;//定义方向,上
  private int DIR_DOWN = 1;//下
  private int DIR_LEFT = 2;//左
  private int DIR_RIGHT = 3;//右
  private int dirX[] = {
      0, 0, -1, 1};//X方向变化数据
  private int dirY[] = {
      -1, 1, 0, 0};//Y方向变化数据
  private int direction = DIR_RIGHT;//贪吃蛇的行走方向
  private int posX, posY;//贪吃蛇当前头的位置
  private int gameWidth, gameHeight;//游戏画面的宽度和高度
  private SnakePos[] snakeData;//贪吃蛇身体的坐标数组
  private int count = 4;//初始贪吃蛇身体的长度
  private int width = 4, height = 4;//每个身体段的长度和高度
  private int time = 100;//延迟
  private SnakePos block;//食物的坐标
  private SnakePos cannot[];//障碍物的坐标数组
  private int cannotCount = 0;//障碍物数量
  private Thread thread;//游戏进程
  private int level = 1;//游戏登记
  private int score = 0;//游戏分数
  private Command exit;//退出按钮
  private Command ok;//开始按钮
  private int status = 0;//游戏状态,0:未开始 1:游戏中 2:暂停中
  private Image img,bgimg;//开始画面和背景图
  private Graphics g;

  /**
   * 构造函数
   * @param suppressKeyEvents boolean
   */
  GameScreen(boolean suppressKeyEvents) {
    super(suppressKeyEvents);
    ok = new Command("开始", Command.OK, 2);
    exit = new Command("退出", Command.EXIT, 1);
    this.addCommand(ok);
    this.addCommand(exit);
    this.setCommandListener(this);
    g = this.getGraphics();
    try {
      img = Image.createImage("/title.png");//开始画面

      bgimg = Image.createImage("/bg.png");//背景

      g.drawImage(img,0,0,Graphics.LEFT|Graphics.TOP);
    }
    catch (IOException ex) {
      ex.printStackTrace();
    }
  }


  /**
   * 开始游戏
   */
  private void start() {
    this.setFullScreenMode(false);//设置为非全屏模式
    gameWidth = getWidth();//游戏屏幕宽度
    gameHeight = getHeight() - 16;//高度,因为需要留出空间给信息,因此减去了16
    int x = gameWidth / width;
    int y = gameHeight / height;
    posX = x / 2;
    posY = y / 2;
    snakeData = null;
    cannot = null;
    System.gc();//垃圾回收
    snakeData = new SnakePos[x * y];
    cannot = new SnakePos[x * y];
    snakeData[0] = new SnakePos(posX, posY);
    snakeData[1] = new SnakePos(posX - 1, posY);
    snakeData[2] = new SnakePos(posX - 2, posY);
    snakeData[3] = new SnakePos(posX - 3, posY);
    count = 4;
    cannotCount = 0;
    direction = DIR_RIGHT;
    putBlock();
    score = 0;
    level = 1;
  }

  /**
   * 在游戏中显示信息
   * @param str String 信息内容
   * @param g Graphics
   */
  private void drawMessage(String str, Graphics g) {
    g.setColor(255,255,255);
    g.fillRect(0,getHeight()-15,getWidth(),getHeight());
    g.setColor(0,0,255);
    g.drawString(str, 5, getHeight() - 16, Graphics.TOP | Graphics.LEFT);
  }

  /**
   * 检查贪吃蛇在x,y处是否合法
   * @param x int
   * @param y int
   * @return boolean
   */
  private boolean check(int x, int y) {
    if (!canPut(x, y)) {
      if (block != null)
        if (block.x == x && block.y == y)
          return true;
      return false;
    }
    return true;
  }

  /**
   * 判断在xy处是否可以放置食物或者障碍物
   * @param x int
   * @param y int
   * @return boolean
   */
  private boolean canPut(int x, int y) {
    System.out.println("x=" + x + " y=" + y);
    for (int i = 0; i < count; i++) {
      if (x == snakeData[i].x && y == snakeData[i].y)
        return false;
    }
    for (int i = 0; i < cannotCount; i++) {
      if (x == cannot[i].x && y == cannot[i].y)
        return false;
    }
    if (block != null)
      if (x == block.x && y == block.y)
        return false;
    if (x <= 0 || y <= 0)
      return false;
    if (x >= gameWidth / width - 1 || y >= gameHeight / height - 1)
      return false;
    return true;
  }

  /**
   * 放置食物和障碍物
   */
  private void putBlock() {
    Random rnd = new Random();
    block = null;
    int x = Math.abs(rnd.nextInt()) % (gameWidth / width - 1);
    int y = Math.abs(rnd.nextInt()) % (gameHeight / height - 1);
    while (!canPut(x, y)) {
      x = Math.abs(rnd.nextInt()) % (gameWidth / width - 1);
      y = Math.abs(rnd.nextInt()) % (gameHeight / height - 1);
    }
    block = new SnakePos(x, y);
    x = Math.abs(rnd.nextInt()) % (gameWidth / width - 1);
    y = Math.abs(rnd.nextInt()) % (gameHeight / height - 1);
    while (!canPut(x, y)) {
      x = Math.abs(rnd.nextInt()) % (gameWidth / width - 1);
      y = Math.abs(rnd.nextInt()) % (gameHeight / height - 1);
    }
    cannot[cannotCount] = new SnakePos(x, y);
    cannotCount++;
  }

  /**
   * 画游戏画面和贪吃蛇等
   * @param g Graphics
   */
  private void drawSnake(Graphics g) {
    g.setColor(255,255,255);
    g.drawRect(0,0,getWidth(),getHeight());
    g.drawImage(bgimg,0,0,Graphics.LEFT|Graphics.TOP);
    g.setColor(255, 0, 0);
    g.drawRect(0, 0, gameWidth, gameHeight);
    g.drawRect(width - 1, height - 1, gameWidth - width * 2 + 1,
               gameHeight - height * 2 + 1);
    g.setColor(200, 5, 100);
    for (int i = 0; i < count; i++) {
      g.fillRect(snakeData[i].x * width, snakeData[i].y * height, width, height);
    }
    if (block != null) {
      Random rnd = new Random();
      int rr = Math.abs(rnd.nextInt())%255;
      int gg = Math.abs(rnd.nextInt())%255;
      int bb = Math.abs(rnd.nextInt())%255;
      g.setColor(rr, gg , bb);
      g.fillRect(block.x * width, block.y * height, width, height);
    }
    for (int i = 0; i < cannotCount; i++) {
      g.setColor(0, 0, 0);
      g.fillRect(cannot[i].x * width, cannot[i].y * height, width, height);
    }
    drawMessage("Level:" + level + " Score:" + score, g);
  }

  /**
   * run 游戏线程
   */
  public void run() {
    start();//初始化
    status = 1;//设置状态
    while (status != 0) {
      if (status != 2) {
        g = this.getGraphics();
        int key = getKeyStates();//获取键盘状态
        if (key != 0) {
          if ( (key & UP_PRESSED) != 0) {
            direction = DIR_UP;
          }
          else if ( (key & DOWN_PRESSED) != 0) {
            direction = DIR_DOWN;
          }
          else if ( (key & LEFT_PRESSED) != 0) {
            direction = DIR_LEFT;
          }
          else if ( (key & RIGHT_PRESSED) != 0) {
            direction = DIR_RIGHT;
          }
        }
        int newX, newY;
        //获取新坐标
        newX = posX + dirX[direction];
        newY = posY + dirY[direction];
       
        if (!check(newX, newY)) {
          break;
        }
        //如果遇到了食物,吃掉它
        if (newX == block.x && newY == block.y) {
          count++;
          snakeData[count - 1] = new SnakePos(0, 0);
          snakeData[count - 1].x = snakeData[count - 2].x;
          snakeData[count - 1].y = snakeData[count - 2].y;
          putBlock();
          score += 10;
          if (score == level * 100) {//每级100分
            level++;
            time -= 10;//每升级一次速度加快
          }
        }
        for (int i = count - 1; i > 0; i--) {
          snakeData[i].x = snakeData[i - 1].x;
          snakeData[i].y = snakeData[i - 1].y;
        }
        snakeData[0].x = newX;
        snakeData[0].y = newY;
        drawSnake(g);
        this.flushGraphics();
        posX = newX;
        posY = newY;
      }
      try {
        Thread.sleep(time);
      }
      catch (InterruptedException ex) {
      }
    }
    removeCommand(ok);
    ok = new Command("开始",Command.OK,2);
    addCommand(ok);
    drawMessage("您的得分:" + score,g);
    status = 0;
    this.flushGraphics();
  }

  /**
   * 处理命令按钮
   * @param command Command
   * @param displayable Displayable
   */
  public void commandAction(Command command, Displayable displayable) {
    if (command == ok) {
      System.out.println("OK");
      if (status == 0) {
        thread = new Thread(this);
        thread.start();
        this.removeCommand(ok);
        ok = new Command("暂停", Command.OK, 2);
        addCommand(ok);
      }
      else
      if (status == 1) {
        status = 2;
        this.removeCommand(ok);
        ok = new Command("继续", Command.OK, 2);
        addCommand(ok);
      }
      else if (status == 2) {
        status = 1;
        this.removeCommand(ok);
        ok = new Command("暂停", Command.OK, 2);
        addCommand(ok);
      }
    }

    if(command == exit){
      SnakeGame.quitApp();
    }
  }

}

游戏运行画面:

在我自己的阿而卡特OT756上已经通过测试

分享到:
评论

相关推荐

    j2me 手机短信编程(sms),经典

    j2me 手机短信编程(sms),经典 适合编程各个阶段的人学习,一定很有帮助

    J2ME手机扫雷游戏

    J2ME是Java技术的一个分支,主要用于嵌入式系统和移动设备,如早期的智能手机和平板电脑,它为开发者提供了跨平台的编程能力。 在这款J2ME手机扫雷游戏中,开发者运用了J2ME的核心技术,包括MIDP(Mobile ...

    j2me游戏开发实例

    **J2ME游戏开发实例详解** J2ME(Java 2 Micro Edition)是Java平台的一个子集,专门用于...通过这个J2ME游戏开发实例,你可以深入理解移动游戏开发的各个方面,逐步提升自己的编程技能,为未来的项目打下坚实基础。

    基于J2me MIDP2.0的手机游戏模拟

    MIDP(Mobile Information Device Profile)是J2ME的一部分,主要针对移动设备,特别是手机的游戏和应用开发。MIDP2.0是MIDP的一个版本,增加了更多功能和改进,如更强大的用户界面组件、多媒体支持和数据存储。 ...

    【中文】【 J2ME开发大全 】【pdf】【15.87 MB】

    给定信息中的“【中文】【 J2ME开发大全 】【pdf】【15.87 MB】”指的是一本关于J2ME开发的经典书籍,该书籍提供了详尽的J2ME开发指南,包括基础概念、编程技巧、最佳实践等内容。作为一本经典书籍,它对于想要深入...

    J2me手机泡泡堂游戏

    《J2ME手机泡泡堂游戏》是一款基于Java平台开发的移动设备游戏,它以其与经典泡泡堂游戏的高度相似性赢得了玩家的喜爱。此游戏的核心亮点在于它不仅提供了丰富的游戏体验,而且还附带了全部的源代码,这对于开发者和...

    j2me小练习,教学用

    【标题】"j2me小练习,教学用" 在IT领域,J2ME(Java 2 Platform, Micro Edition)是...通过实践这个项目,学习者不仅可以提升J2ME编程技能,还能深入理解移动游戏开发的各个方面,为未来更复杂的项目打下坚实的基础。

    j2me_fly_game_1945

    《J2ME飞翔之旅:1945飞行射击游戏源码解析》 在移动设备尚未普及智能操作系统的时代,Java...通过对这款源码的学习,开发者不仅可以掌握J2ME编程技巧,还能深入理解游戏开发的核心流程,为今后的项目提供宝贵的参考。

    J2ME学习视频

    这个资源可能是由一位名为“txyly998”的博主分享的,旨在帮助初学者和开发者掌握J2ME编程。 描述中提到的“博文链接”指向了iteye博客的一个页面(https://txyly998.iteye.com/blog/339081),该页面可能包含更...

    一个超简单的J2ME游戏实例

    J2ME,全称Java Micro Edition,是Java平台的一个子集,主要用于嵌入式设备和移动设备,如早期的智能手机和功能手机。它提供了开发和部署小型应用程序的框架,包括游戏。在这个超简单的J2ME游戏实例中,我们主要关注...

    Java手机游戏海底探险源文件

    总的来说,Java手机游戏海底探险源文件提供了一个实践性的学习案例,涵盖了Java编程、J2ME技术、游戏设计与开发等多个重要知识点。通过研究这个项目,开发者不仅可以提升Java编程技能,还能了解到游戏开发的全过程,...

    手机游戏开发全书试读版本

    #### 三、《手机游戏开发全书——J2ME完整实例精解》书籍特色与价值 - **内容覆盖广泛**:本书不仅涵盖游戏立项、策划方案撰写、美术制作流程等方面的内容,还重点介绍了基于J2ME平台的游戏程序开发技巧。 - **实战...

    java基础学习心得.docx

    Java 基础学习心得 Java 是一种广泛使用的编程语言,随着其广泛应用,越来越多的人开始学习 Java。那么,Java 学习需要什么根底?下面,我们将详细介绍 Java 学习的基础知识。 Java 学习需要什么根底? Java 学习...

    编程人员应常去的网站

    42. **Fyter的博客**:个人技术博客,分享编程经验和心得。 43. **DevExpress**:提供ASP.NET、WinForms等控件和开发工具。 44. **OperaMask**:浏览器插件开发,尤其与JavaScript和Web开发相关。 45. **中国源码...

    个人收藏的编程下载资源全部公布

    ### 个人收藏的编程下载资源全面解析 在数字化时代,编程资源的获取变得前所未所地便捷,但对于初学者或是寻找特定资源的专业人士来说,筛选出高质量、可靠的学习资料仍然是一个挑战。本文将深入分析一份个人收藏的...

    java实习心得.pdf

    每个方向都有其独特的挑战和潜力,如中国庞大的手机用户市场就为J2ME提供了广阔的发展空间。 实习不仅是技能的提升,更是个人成长的过程。在实习结束后,你需要反思,持续学习,保持对新信息的敏感度,这对于一个...

    java学习心得总结.pdf

    8. **J2EE、J2SE和J2ME**:Java分为三个主要平台,J2SE(Java Standard Edition)是基础,提供了核心的Java API;J2EE(Java Enterprise Edition)用于构建企业级应用,涉及到Servlet、JSP、EJB等技术;J2ME(Java ...

    JAVE 基础入门 外带经验心得 原版

    - **J2ME (Java 2 Micro Edition)**:专为移动设备如手机和平板电脑等小型设备设计的 Java 版本。 - **J2SE (Java 2 Standard Edition)**:标准版 Java,适用于桌面应用和企业级应用程序。 - **J2EE (Java 2 ...

    《Practical Java》中文版随书

    此外,文件名"okbase.net"可能是指一个包含更多资源或讨论平台的网站,读者可以在该网站上获取额外的支持、答疑解惑,或者与其他学习者交流心得,进一步提升自己的Java和J2ME技能。 总的来说,《Practical Java》...

Global site tag (gtag.js) - Google Analytics