J2ME手机编程心得(四)

    技术2022-05-11  14

       上一个贪吃蛇的游戏是可以玩了,但是有个问题是,就算我玩的分数再高也没有记录,这样玩起来不是就没有挑战性了嘛?所以还需要为游戏加上一个记录分数和排名的模块,这样玩起来会有意思的多了。这就涉及到J2ME中的持久化的内容了,网上的这方面的资料都有很多,基本的原理就不多说了,直接说说在这个游戏中用到的技术。

        首先需要将用户的姓名和分数保存,这就需要一个格式,在这里定义为"用户分数#用户姓名"这样的格式。用户姓名是在记录分数的界面用户输入的,而用户的分数则是从GameScreen类中直接获取的。那如何获取GameScreen的实例呢?可以有多种方法,可以在构造RecordScreen的时候就将实例放到构造函数的参数中,也可以在Midlet的主类SnakeGame中获取GameScreen的实例。我偏向于第二种做法,因为这样看起来结构比较清晰,因为所有的屏幕都是属于这个Midlet的,将所有的屏幕(Screen)都做为主类的成员,再为每个设置get方法就可以在任何时候很方便的获取任意一个屏幕的实例。还有个问题是如何随时获取主Midlet类的实例呢?在JBuilder里面生成的代码中有个静态的变量instance,所以在任何地方都可以用SnakeGame.instance来获取这个类的实例。不过我的习惯是将instance设置成private类型,再写一个getInstance()的静态方法返回instance。这样,如果我想获取GameScreen的实例,就可以在任何地方直接用SnakeGame.getIntance().getGameScreen()获取了。

        数据可以获取了,现在就是保存了,保存很简单了,打开一个RecordStore,然后用addRecord方法添加记录就是了,这里的记录表现形式只能是byte数组类型的。代码如下:

        int score = gameScreen.getScore();//获取的分数    String name = playerName.getString();//获取姓名    String record = score + "#" + name;//组成字符串    try {      RecordStore rs = RecordStore.openRecordStore("SnakeGame", true);//打开,如果没有就新建      rs.addRecord(record.getBytes(), 0, record.length());//保存      rs.closeRecordStore();//关闭    }    catch (RecordStoreException ex) {      ex.printStackTrace();    }

        这样简单就把数据保存进去了。

        保存完了应该读取了,而且这个是要按排名先后来排序的,一般来说,遍历整个记录集可以使用RecordEnumeration,我们可以用RecordStore的enumerateRecords来进行遍历,enumerateRecords有三个参数,在这里只需要关心第二个参数就可以了,第二个参数是需要提供一个排序的类,这个类要实现RecordComparator接口,RecordComparator接口里面有compare(byte[] a byte[] b)函数,我们只要按照我们的意图实现这个方法就可以了。我们需要的是比较#前面的数字的大小,因此也比较简单,具体类的代码如下:

    class MyExpenseComparator    implements RecordComparator {  public int compare(byte[] a, byte[] b) {    String strA = new String(a);    String strB = new String(b);    int indexA = strA.indexOf("#");    String scoreA = strA.substring(0, indexA);

        int indexB = strB.indexOf("#");    String scoreB = strB.substring(0, indexB);

        if (Integer.parseInt(scoreA) > Integer.parseInt(scoreB)) {      return this.PRECEDES;    }    if (Integer.parseInt(scoreA) < Integer.parseInt(scoreB)) {      return this.FOLLOWS;    }    return this.EQUIVALENT;  }}

    有了这个排序的类,其他的就好办了,遍历记录然后一条一条显示就可以了,考虑到如果记录多了会很长,因此遍历的时候只取出前10名的记录,后面的全部都删除掉。遍历以及显示记录的代码如下:

      private void listRecord() {    String[] names;    try {      RecordStore rs = RecordStore.openRecordStore("SnakeGame", false);      int count = 0;      RecordEnumeration e = rs.enumerateRecords(null, new MyExpenseComparator(), false);      while (e.hasNextElement()) {        int rid = e.nextRecordId();        String str = new String(rs.getRecord(rid));        int index = str.indexOf("#");        String score = str.substring(0, index);        String name = str.substring(index + 1);        if (count++ >= 10)          rs.deleteRecord(rid);        else          append("No" + count + "." + "姓名:" + name + "  得分:" + score + "/r/n");      }      rs.closeRecordStore();    }    catch (Exception e) {      e.printStackTrace();    }  }

        显示和记录都完成了,呵呵,再集成到我们的游戏里面去吧,整个RecordScreen的代码如下:

    package snakegame;

    import javax.microedition.lcdui.*;import javax.microedition.rms.RecordStore;import javax.microedition.rms.*;import java.util.Hashtable;

    public class RecordScreen    extends Form implements CommandListener {  private Command cancel;  private Command save;  private TextField playerName = new TextField("您的大名", "Noname", 10, TextField.ANY);  private GameScreen gameScreen;  public RecordScreen() {    super("记录成绩");    this.gameScreen = SnakeGame.getInstance().getGameScreen();    cancel = new Command("取消", Command.EXIT, 1);    save = new Command("保存成绩", Command.OK, 2);    this.append(playerName);    addCommand(cancel);    addCommand(save);    setCommandListener(this);    listRecord();      }

      private void saveRecord() {    int score = gameScreen.getScore();    String name = playerName.getString();    String record = score + "#" + name;    try {      RecordStore rs = RecordStore.openRecordStore("SnakeGame", true);      int id = rs.addRecord(record.getBytes(), 0, record.length());      rs.closeRecordStore();    }    catch (RecordStoreException ex) {      ex.printStackTrace();    }    listRecord();  }

      private void listRecord() {    String[] names;    try {      RecordStore rs = RecordStore.openRecordStore("SnakeGame", false);      int count = 0;      RecordEnumeration e = rs.enumerateRecords(null, new MyExpenseComparator(), false);      while (e.hasNextElement()) {        int rid = e.nextRecordId();        String str = new String(rs.getRecord(rid));        int index = str.indexOf("#");        String score = str.substring(0, index);        String name = str.substring(index + 1);        if (count++ >= 10)          rs.deleteRecord(rid);        else          append("No" + count + "." + "姓名:" + name + "  得分:" + score + "/r/n");      }      rs.closeRecordStore();    }    catch (Exception e) {      e.printStackTrace();    }  }    public void commandAction(Command command, Displayable displayable) {    if (command == save) {      saveRecord();      SnakeGame.getInstance().gameScreen();    }    if (command == cancel) {      SnakeGame.getInstance().gameScreen();    }  }

    }

    class MyExpenseComparator    implements RecordComparator {  public int compare(byte[] a, byte[] b) {    String strA = new String(a);    String strB = new String(b);    int indexA = strA.indexOf("#");    String scoreA = strA.substring(0, indexA);

        int indexB = strB.indexOf("#");    String scoreB = strB.substring(0, indexB);

        if (Integer.parseInt(scoreA) > Integer.parseInt(scoreB)) {      return this.PRECEDES;    }    if (Integer.parseInt(scoreA) < Integer.parseInt(scoreB)) {      return this.FOLLOWS;    }    return this.EQUIVALENT;  }}

    OK,这个功能就实现了!

    不过在测试中发现,如果输入的姓名有中文,可能显示的就会有点问题,上面的图片第二条记录,本来填写的是“无名”,结果显示的时候只显示出了“无”字。这个问题有人知道的话请告诉我解决的办法,多谢了!!


    最新回复(0)