J2ME手机游戏设计与开发
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

3.6 高级屏幕类综合应用实例

3.6.1 Form组件综合练习

【例3-14】 Form组件综合练习。前面已经学习了所有的Form组件,这里将所有的组件都集中放置在Form界面上,进行综合练习。

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class mainMidlet extends MIDlet implements CommandListener{
    private Form mainscreen;
    private Command okCommand = new Command("OK", Command.OK, 1);
    private Command exitCommand = new Command("Exit", Command.EXIT, 1);
    private Display display;
    public mainMidlet() {
        mainscreen= new Form("Form demo");
        mainscreen.addCommand(okCommand);
        mainscreen.addCommand(exitCommand);
        mainscreen.setCommandListener(this);
        //创建StringItem对象
        mainscreen.append(new StringItem("StringItem Test",
                       "The following is Duke."));
        //创建ImageItem对象
        Image img=null;
        try {
           img= Image.createImage("/smallDuke.png");
        } catch (Exception e) {}
        mainscreen.append(new ImageItem("ImageItem test",
                       img,
                              ImageItem.LAYOUT_CENTER,
                              "Image can not display"));
        //创建Choice对象
        String[] editable_choices={"editable", "uneditable"};
        mainscreen.append(new ChoiceGroup("Gauge option",Choice.EXCLUSIVE, editable_choices,null));
        //创建TextField对象
        mainscreen.append(new TextField("TextField", "", 20, TextField. ANY));
        //创建DateField对象
        mainscreen.append(new DateField("DateField", DateField.DATE));
        //创建Gauge对象
        mainscreen.append(new Gauge("Gauge Test",true,100,50));
        //创建Display对象
        display=Display.getDisplay(this);
    }
    public void startApp() throws MIDletStateChangeException {
        display.setCurrent(mainscreen);
    public void pauseApp() {
    }
    public void destroyApp(boolean unconditional) {
        //清除所有对象
        mainscreen=null;
        okCommand = null;
        exitCommand = null;
        display=null;
    }
    public void commandAction(Command c, Displayable d) {
        if(c==okCommand) {
        //事件响应
        }
        else if(c==exitCommand) { //退出程序
            destroyApp(true);
            notifyDestroyed();
        }
    }
}

执行效果如图3-26所示。

图3-26 Form组件综合应用效果图

3.6.2 生物钟软件

1.游戏设计思想

人体生物钟的节律特征如表3-19所示。

表3-19 人体生物钟的节律特征

节律的计算公式:

Y=X%N:Y是节律,X是总天数,N是节律周期。

体力节律:Y1=X%23

情绪节律:Y2=X%28

智力节律:Y3=X%33

·当Y=0或Y=1或(N/2-1)<=Y<=(N/2+1)时,人体处于临界日;

·当Y<N/2时,且不是临界日,人体则处于高潮期;

·当Y>N/2时,且不是临界日,人体则处于低潮期。

游戏规则:游戏者输入出生日期,系统检测出游戏者当日的体力、情绪和智力方面的生理现象。

2.游戏设计流程

生物钟软件设计流程图如图3-27所示。

图3-27 生物钟软件流程图

3.游戏设计的难点和解决方法

(1)如何计算天数。

Date Date;=datefield.getDate()
Long temp=System.currenttimeMillis-date.getTime();
Long X=temp/24/60/60/1000;

(2)重置游戏。

将3个StringItem清空或者设成无检测即可:

si1.setText(""); si2.setText(""); si3.setText("");

4.程序的完整代码

import java.util.Date;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
public class ClockMidlet extends MIDlet implements CommandListener {
    Form f;
    DateField df;
    StringItem si1;
    StringItem si2;
    StringItem si3;
    Command exitCommand;
    Command checkCommand;
    Command restartCommand;
    public ClockMidlet() {
    super();
    f=new Form("生物钟");
    df=new DateField("出生日期",DateField.DATE);
    si1=new StringItem("体力","");
    si2=new StringItem("情绪","");
    si3=new StringItem("智力","");
    exitCommand=new Command("退出",Command.EXIT,1);
    checkCommand=new Command("检测",Command.OK,2);
    restartCommand=new Command("重置",Command.OK,2);
    f.addCommand(exitCommand);
    f.addCommand(checkCommand);
    f.addCommand(restartCommand);
    f.append(df);
    f.append(si1);
    f.append(si2);
    f.append(si3);
    f.setCommandListener(this);
}
protected void destroyApp(boolean arg0) {       }
protected void pauseApp() {}
protected void startApp(){
    Display.getDisplay(this).setCurrent(f);
}
public void commandAction(Command cmd, Displayable arg1) {
      if(cmd==checkCommand)
      {
          Date date=df.getDate();
          long temp=System.currentTimeMillis()-date.getTime();
          long X=temp/24/60/60/1000;
          long Y1=X%23;
          long Y2=X%28;
          long Y3=X%33;
          if(Y1==0||Y1==1||(Y1>=23/2-1&&Y1<=23/2+1)) //计算体力周期
              si1.setText("易患疾病");
          else if(Y1<23/2)
              si1.setText("体力充沛精力旺");
          else
              si1.setText("体力不足易疲劳");
          if(Y2==0||Y2==1||(Y2>=28/2-1&&Y2<=28/2+1)) //计算情绪周期
              si2.setText("容易冲动");
          else if(Y2<28/2)
              si2.setText("情绪高精神爽");
          else
              si2.setText("情绪低心情烦");
          if(Y3==0||Y3==1||(Y3>=33/2-1&&Y3<=33/2+1)) //计算智力周期
              si3.setText("易出差错");
          else if(Y2<33/2)
              si3.setText("思维敏捷反应快");
          else
              si3.setText("反应迟钝记忆差");
      }else if(cmd==exitCommand)                                        //退出按钮
      {
          destroyApp(false);
          notifyDestroyed();
      }else if(cmd==restartCommand)                                     //重置按钮
      {
          si1.setText("");
          si2.setText("");
          si3.setText("");
      }
      }
}

5.执行效果如图3-28所示

图3-28 生物钟软件效果图

3.6.3 猜数字游戏设计

1.游戏设计思想

计算机随机产生不重复的四位数字,用户输入猜测的数字,根据所给反馈信息继续输入,直到正确或者到达最多次数失败为止。

(1)每次启动游戏,系统先随机生成一个四位数,每个数字不重复。

(2)游戏者有5次机会来猜出目标数,每次机会中,游戏者可以输入一个四位数,同样不允许重复,例如2334是错误的。

(3)游戏者输入后,单击“确定”按钮,系统给出判断信息,以文本形式出现,例如2A1B,即有2个数的位置正确和数字正确,1个数的位置错误但是数字正确。

(4)如果输入数与目标数完全正确则成功,若5次都没猜对,则失败。

2.游戏的设计流程

猜数字游戏设计流程图如图3-29所示。

图3-29 猜数字游戏流程图

3.游戏的制作难点和解决方法

(1)启动游戏后,如何生成四位不同的随机数。

Random随机类的用法如下。

构造方法:Random r=new Random();

常用方法:r.nextInt(); 生成一个随机整数,通常采用以下方法处理Math.abs(ran.nextInt()%10)生成10以内的整数。

private void initNum() {
        for(int i=0;i<4;i++)
        {
            n_Num[i]=Math.abs(ran.nextInt()%10);
            for(int j=i;j<i;j++)
            {
                if(n_Num[i]==n_Num[j]) //避免生成相
                                           同的数字
                {
                    j--;
                    break;
                }
            }
        }
}

(2)如何判断游戏者输入的数字是合法的。

private boolean check(char[] a_Num) {
if(tf.getString().length()!=4)  //判断是否输入了四位数
    return false;
for(int i=0;i<4;i++)         //判断是否输入了重复的数字
    for(int j=i;j<4;j++)
    { if(a Num[i]==a_Num[j]&&i!=j)
           return false;
    }
return true;
}

(3)如何根据游戏者的输入给出反馈信息。

tf.getChars(c_aNum);            //获取输入内容
if(check(c_aNum))               //判断输入内容是否正确的
{
    for(int i=0;i<4;i++)
        for(int j=0;j<4;j++)
            if((int)(c_aNum[i]-'0')==n_Num[j])
            //进行对比,计算nA和nB
            {
                if(i==j)
                    nA++;
                else
                    nB++;
            }
}

4.完整代码

import java.util.Random;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
public class GuessMidlet extends MIDlet implements CommandListener {
    Display disp;
    Form form;
    TextField tf;
    StringItem si;
    Command cmdEnter;
    Command cmdExit;
    Random ran=new Random();
    int[] n_Num=new int[4];
    char[] c_aNum=new char[4];
    public GuessMidlet() {
        disp=Display.getDisplay(this);
        form=new Form("猜数字");
        tf=new TextField("输入数字","",4,TextField.NUMERIC);
        si=new StringItem("反馈信息","");
        cmdEnter=new Command("确定",Command.OK,1);
        cmdExit=new Command("退出",Command.EXIT,1);
        form.append(tf);
        form.append(si);
        form.addCommand(cmdEnter);
        form.addCommand(cmdExit);
        form.setCommandListener(this);
        form.setCommandListener(this);
        initNum();
    }
    private void initNum() {
        for(int i=0;i<4;i++)
        {
            n_Num[i]=Math.abs(ran.nextInt()%10);
            for(int j=i;j<i;j++)
            {
                if(n_Num[i]==n_Num[j])
                {
                    j--;
                    break;
                }
            }
        }
    }
    protected void destroyApp(boolean arg0) throws MIDletStateChange Exception {        }
    protected void pauseApp() { }
    protected void startApp() throws MIDletStateChangeException {
        disp.setCurrent(form);
    }
    private boolean check(char[] a_Num)
    {
        if(tf.getString().length()!=4)
             return false;
        for(int i=0;i<4;i++)
             for(int j=i;j<4;j++)
                  {if(a_Num[i]==a_Num[j]&&i!=j)
                       return false;
                  }
        return true;
    }
    public void commandAction(Command cmd, Displayable d) {
        int nA=0;
        int nB=0;
        if(cmd==cmdExit)
        {
            try {
                destroyApp(false);
            } catch (MIDletStateChangeException e) {
                // TODO 自动生成 catch 块
                e.printStackTrace();
            }
            notifyDestroyed();
        }
        else if(cmd==cmdEnter)
        {
            tf.getChars(c_aNum);
            if(check(c_aNum))
            {
                 for(int i=0;i<4;i++)
                      for(int j=0;j<4;j++)
                           if((int)(c_aNum[i]-'0')==n_Num[j])
                           {
                                 if(i==j)
                                      nA++;
                                 else
                                      nB++;
                           }
            }
            else
            {
                System.out.println("False");
            }
            StringBuffer buffer=new StringBuffer();
            buffer.append(nA);
            buffer.append("A");
            buffer.append(nB);
            buffer.append("B");
            si.setText(buffer.toString());
        }
    }
}

5.执行效果如图3-30所示

图3-30 猜数字游戏效果图

3.6.4 心理测试软件

1.游戏的设计思想

(1)用户根据问题选择答案,答完所有题目后单击“确定”按钮,根据所选答案给出心理测试的结果信息。

(2)第一个界面显示心理测试的问题。

(3)用户输入后,计算所得分数切换到第二个界面。

(4)第二个界面给出相应的信息,并且可以返回到第一个界面。

(5)第一个界面可以退出软件。

2.界面对象分析

(1)界面1:formAsk负责提出问题。

Form对象:

ChoiceGroup对象,负责给出问题和选项;

Command对象,负责退出和确定。

(2)界面2:formAnswer负责给出心理测试的答案。

Form对象:

Command对象,负责返回初始界面。

3.游戏的设计流程

心理测试软件设计流程图如图3-31所示。

图3-31 心理测试软件流程图

4.游戏的制作难点和解决方法

(1)计算得分。根据选项的序号设定得分:

int i=cg1.getSelectedIndex()+cg2.getSelectedIndex()+
cg3.getSelectedIndex()+cg4.getSelectedIndex()+cg5.getSelectedIndex();

(2)返回问题界面时同时清除答案界面的内容。

if(cmd==cmdBack){
      disp.setCurrent(formAsk);
      formAnswer.deleteAll();
}

5.完整代码

import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
public class HeartMidlet extends MIDlet implements CommandListener {
    Display disp;
    Form formAsk,formAnswer;
    ChoiceGroup cg1,cg2,cg3,cg4,cg5;
    Command cmdEnter;
    Command cmdExit,cmdBack;
    public HeartMidlet() {
        disp=Display.getDisplay(this);
        formAsk=new Form("提问");
        formAnswer=new Form("测试结果");
        cg1=new ChoiceGroup("你想改变目前的生活状态么?",ChoiceGroup. EXCLUSIVE);
        cg1.append("想", null);
        cg1.append("无所谓", null);
        cg1.append("不想", null);
        cg2=new ChoiceGroup("你想改变目前的生活状态么?",ChoiceGroup. EXCLUSIVE);
        cg2.append("想", null);
        cg2.append("无所谓", null);
        cg2.append("不想", null);
        cg3=new ChoiceGroup("你想改变目前的生活状态么?",ChoiceGroup. EXCLUSIVE);
        cg3.append("想", null);
        cg3.append("无所谓", null);
        cg3.append("不想", null);
        cg4=new ChoiceGroup("你想改变目前的生活状态么?",ChoiceGroup. EXCLUSIVE);
        cg4.append("想", null);
        cg4.append("无所谓", null);
        cg4.append("不想", null);
        cg5=new ChoiceGroup("你想改变目前的生活状态么?",ChoiceGroup. EXCLUSIVE);
        cg5.append("想", null);
        cg5.append("无所谓", null);
        cg5.append("不想", null);
        cmdEnter=new Command("确定",Command.OK,1);
        cmdExit=new Command("退出",Command.EXIT,2);
        cmdBack=new Command("返回",Command.BACK,2);
        formAsk.append(cg1);
        formAsk.append(cg2);
        formAsk.append(cg3);
        formAsk.append(cg4);
        formAsk.append(cg5);
        formAsk.addCommand(cmdEnter);
        formAsk.addCommand(cmdExit);
        formAnswer.addCommand(cmdBack);
        formAsk.setCommandListener(this);
        formAnswer.setCommandListener(this);
    }
    protected void destroyApp(boolean arg0) {   }
    protected void pauseApp() { }
    protected void startApp() throws MIDletStateChangeException {
        disp.setCurrent(formAsk);
    }
    public void commandAction(Command cmd, Displayable arg1) {
        if(cmd==cmdExit)
        {
        destroyApp(false);
        notifyDestroyed();
        }else if(cmd==cmdBack){
            disp.setCurrent(formAsk);
            formAnswer.deleteAll();
        }else if(cmd==cmdEnter)
        {
            int i=cg1.getSelectedIndex()+cg2.getSelectedIndex()+
            cg3.getSelectedIndex()+cg4.getSelectedIndex()+cg5.getSelectedIndex();
            if(i<4)
                formAnswer.append("你处在比较积极的状态");
            else if(i<6)
                formAnswer.append("你已经开始发懒了");
            else if(i<8)
                formAnswer.append("你的惰性很大了");
            else if(i<=10)
                formAnswer.append("你已经是懒骨头了");
            disp.setCurrent(formAnswer);
        }
    }
}

6.执行效果如图3-32所示

图3-32 心理测试软件效果图

3.6.5 电子书的制作

通过高级屏幕类阅读已经存储在程序中的诗词,重点是建立诗词目录界面及每首诗词的显示界面。

1.游戏功能

启动界面加载条,当加载结束后进入一级菜单,选项包括“唐诗鉴赏”和“宋词鉴赏”。根据选择进入相应的二级菜单,包括唐诗和宋词的题目,然后进入具体的内容阅读。

2.程序的构成

整个程序只有一个EBookMIDlet类,用来切换不同的显示内容。

本程序主要是通过高级屏幕类阅读已经存储在程序中的诗词,重点是建立诗词目录界面以及每首诗词的显示界面。

完整代码如下:

import javax.microedition.lcdui.*;
import javax.microedition.midlet.MIDlet;
public class EBookMIDlet extends MIDlet implements Runnable,CommandListener, ItemCommandListener{
    /**屏幕显示对象*/
    private Display display;
    /**加载提示*/
    private Alert alert;
    /**加载条*/
    private Gauge gauge;
    /**数目列表*/
    private List list;
    /**章节列表*/
    private Form form;
    /**书本内容*/
    private TextBox textBox;
    /**初始时间*/
    long firstTime;
    private Image image;
    private final Command cmdEnter = new Command("进入",Command.OK,1);
    private final Command cmdExit = new Command("退出",Command.EXIT,1);
    private final Command cmdBack = new Command("返回",Command.BACK,1);
    /**当前书目索引*/
    private int curBookIndex = 0;
    /**书目*/
    private String[] bookName = {"《唐诗鉴赏》","《宋词鉴赏》"};
    /**二维字符串数组,用以每首诗词的序号、名称、作者及内容*/
    private String[][] text = {{
            "第一首","水调歌\n作者:无名氏\n","平沙落日大荒西,陇上明星高复低。\n孤山几处看烽火,壮士连营候鼓鼙。",
            "第二首","感遇四首之一\n作者:张九龄\n"," 孤鸿海上来,池潢不敢顾。\n侧见双翠鸟,巢在三珠树。\n矫矫珍木巅,得无金丸惧。\n美服患人指,高明逼神恶。\n今我游冥冥,弋者何所慕。",
            "第三首","春思\n作者:李白\n"," 燕草如碧丝,秦桑低绿枝。\n当君怀归日,是妾断肠时。\n春风不相识,何事入罗帏?",
            "第四首","夕次盱眙县\n作者:韦应物\n"," 落帆逗淮镇,停舫临孤驿。\n浩浩风起波,冥冥日沈夕。\n人归山郭暗,雁下芦洲白。\n独夜忆秦关,听钟未眠客。",
            "第五首","溪居\n作者:柳宗元\n"," 久为簪组累,幸此南夷谪。\n闲依农圃邻,偶似山林客。\n晓耕翻露草,夜榜响溪石。\n来往不逢人,长歌楚天碧。",
            "第六首","塞下曲\n作者:王昌龄\n"," 饮马渡秋水,水寒风似刀。\n平沙日未没,黯黯见临洮。\n昔日长城战,咸言意气高。\n黄尘足今古,白骨乱蓬蒿。",
            "第七首","子夜四时歌:春歌\n作者:李白\n"," 秦地罗敷女,采桑绿水边。\n素手青条上,红妆白日鲜。\n蚕饥妾欲去,五马莫留连。",
            "第八首","子夜四时歌:夏歌\n作者:李白\n"," 镜湖三百里,菡萏发荷花。\n五月西施采,人看隘若耶。\n回舟不待月,归去越王家。",
            "第九首","子夜四时歌:秋歌\n作者:李白\n","长安一片月,万户捣衣声。\n秋风吹不尽,总是玉关情。\n何日平胡虏,良人罢远征?",
            "第十首","子夜四时歌:冬歌\n作者:李白\n","明朝驿使发,一夜絮征袍。\n素手抽针冷,那堪把剪刀。\n裁缝寄远道,几日到临洮?",
            "第十一首","送别\n作者:王维\n","下马饮君酒,问君何所之。\n君言不得意,归卧南山陲。\n但去莫复闻,白云无尽时。"},
       {
            "第一首","宴山亭.北行见杏花\n作者:赵佶\n","裁剪冰绡,轻叠数重,淡着燕脂匀注。\n新样靓妆,艳溢香融,羞杀蕊珠宫女。\n易得凋零,更多少、无情风雨。 愁苦,问院落凄凉,几番春暮?\n凭寄离恨重重,者双燕何曾,会人言语?\n天遥地远,万水千山,知他故宫何处?怎不思量?\n除梦里有曾去。无据,和梦也新来不做。",
            "第二首","木兰花\n作者:钱惟演\n","城上风光莺语乱,城下烟波春拍岸。\n绿杨芳草几时休?泪眼愁肠先已断。\n情怀渐觉成衰晚,鸾镜朱颜惊暗换。\n昔年多病厌芳尊,今日芳尊惟恐浅。",
            "第三首","苏幕遮\n作者:范仲淹\n","碧云天,黄叶地,秋色连波,波上寒烟翠。\n山映斜阳天接水,芳草无情,更在斜阳外。\n黯乡魂,追旅思。夜夜除非,好梦留人睡。\n明月楼高休独倚,酒入愁肠,化作相思泪。",
            "第四首","御街行\n作者:范仲淹\n","纷纷坠叶飘香砌。夜寂静,寒声碎。\n真珠帘卷玉楼空,天淡银河垂地。\n年年今夜,月华如练,长是人千里。\n愁肠已断无由醉,酒未到,先成泪。\n残灯明灭枕头[奇支],谙尽孤眠滋味。\n都来此事,眉间心上,无计相回避。",
            "第五首","千秋岁\n作者:张先\n","数声[是鸟][夫鸟],又报芳菲歇。\n惜春更选残红折,雨轻风色暴,梅子青时节。\n永丰柳,无人尽日花飞雪。莫把幺弦拨,怨极弦能说。\n天不老,情难绝,心似双丝网,中有千千结。\n夜过也,东窗未白孤灯灭。",
            "第六首","菩萨蛮\n作者:张先\n","哀筝一弄《湘江曲》,声声写尽湘波绿。\n纤指十三弦,细将幽恨传。 当筵秋水慢,玉柱斜飞雁。\n弹到断肠时,春山眉黛低。 醉垂鞭 张先双蝶绣罗裙,东池宴初相见。朱粉不深匀,闲花淡淡春。\n细看诸处好,人人道柳腰身。昨日乱山昏,来时衣上云。"
       }
};
public EBookMIDlet() {
    display = Display.getDisplay(this);
    alert = new Alert("E-Book启动中",null,null,AlertType.INFO);
    gauge = new Gauge(null,false,5,1);
    alert.setIndicator(gauge);
    alert.setTimeout(6000);
    firstTime = System.currentTimeMillis();
    image = createImage("/flag.png");
    list = new List("书目",Choice.IMPLICIT,bookName,new Image[]{image, image});
    list.addCommand(cmdEnter);
    list.addCommand(cmdExit);
    list.setCommandListener(this);
    new Thread(this).start(); //启动线程,将在之后的章节具体介绍
}
private Image createImage(String file){
    Image image = null;
    try{
        image = Image.createImage(file);
    }catch(Exception e){
        e.printStackTrace();
    }
    return image;
}
protected void destroyApp(boolean arg0){
}
protected void pauseApp() {
}
protected void startApp(){
    display.setCurrent(alert);
}
/**
 * 控制进度提示
 */
public void run() {
    // TODO Auto-generated method stub
    while(true){
        int time = (int)(System.currentTimeMillis() - firstTime);
        gauge.setValue(time/1000);
        if(time >= alert.getTimeout()){
             display.setCurrent(list);
             alert.setIndicator(null);
             break;
        }
    }
}
/**
 * 创建每首诗词显示在Form中的Item
 * @param label
 * @param text
 * @return
 */
private Item createItem(String label,String text){
    Item item = new StringItem(label,text,Item.PLAIN);
    item.addCommand(cmdEnter);
    item.setItemCommandListener(this);
    return item;
}
/**
 * 创建显示诗词信息的Form
 * @param bookIndex
 * @return
 */
private Form createForm(int bookIndex){
    Form form = new Form(bookName[bookIndex]);
    for(int i=0; i<text[bookIndex].length/3; i++){
        form.append(createItem(text[bookIndex][i*3+0],text[bookIndex] [i*3+1]));
    }
    form.addCommand(cmdBack);
    form.setCommandListener(this);
    return form;
}
/**
 * 创建诗词显示的TextBox
 * @param title
 * @param text
 * @return
 */
private TextBox createTextBox(String title,String text){
    TextBox textBox = new TextBox(title,text,200,TextField.ANY);
    textBox.addCommand(cmdBack);
    textBox.setCommandListener(this);
    return textBox;
}
/**
 * 各个窗体事件
 */
public void commandAction(Command command, Displayable displayable) {
    if(command == cmdEnter){
        if(displayable.equals(list)){
            curBookIndex = list.getSelectedIndex();
            form = createForm(curBookIndex);
            display.setCurrent(form);
        }
    }else if(command == cmdBack){
        if(displayable.equals(form)){
            display.setCurrent(list);
        }else if(displayable.equals(textBox)){
            form = createForm(curBookIndex);
            display.setCurrent(form);
        }
    }else if(command == cmdExit){
        notifyDestroyed();
        destroyApp(true);
    }
}
/**
 * 得到当前所选的诗词索引号
 * @param indexText
 * @return
 */
public int getIndex(String indexText){
    for(int i=0; i<text[curBookIndex].length/3; i++){
        if(indexText.equals(text[curBookIndex][i*3+0]))
            return i;
    }
    return -1;
}
/**
 * ItemCommandListener事件,显示当前所选诗词的内容
 */
public void commandAction(Command command, Item item) {
    if(command == cmdEnter){
        int num = getIndex(item.getLabel());
        if(num == -1)
            return;
        textbox = createTextBox(text[curBookIndex][num*3+0]+text
        [curBookIndex][num*3+1],
        text[curBookIndex][num*3+1]+text[curBookIndex][num*3+2]);
        display.setCurrent(textBox);
    }
}
}

执行效果如图3-33所示。

图3-33 电子书效果图

3.6.6 字母拼图

1.游戏功能

启动界面出现4×4的字母块,单击“开始”按钮,将字母块打乱,通过上、下、左、右方向键将字母块拼回到起始界面,显示胜利的信息。

2.程序的构成

整个程序由3个类构成,分别是:

·mainMidlet类:程序的入口,调用MyCanvas对象;

·StringBlock类:定义字母块的结构,包括坐标,字母内容及是否反显;

·myCanvas类:程序的主要类,实现字母的初始化、字母的显示、键盘响应、字母的移动。

(1)mainMidlet类。

import javax.microedition.lcdui.Display;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;
public class mainMidlet extends MIDlet {
    private static mainMidlet instance;
    public mainMidlet() {
    instance=this;
    }
    protected void destroyApp(boolean arg0) {
    }
    protected void pauseApp() {
    }
    protected void startApp() throws MIDletStateChangeException {
        Display.getDisplay(this).setCurrent(new myCanvas());
    }
    public static void quit(){
        instance.destroyApp(false);
        instance.notifyDestroyed();
        instance=null;
    }
}

(2)StringBlock类。

public class StringBlock {
    int ox,oy;
    int x,y;
    char word;
boolean inv;
}

(3)myCanvas类。

import java.util.Random;
import javax.microedition.lcdui.*;
//Canvas类的子类,负责手机画面的内容和响应逻辑
public class myCanvas extends Canvas implements Runnable, CommandListener
    {
    int scrW,scrH;                      //屏幕的宽和高
    Thread th;                          //线程类
    StringBlock sb[],blank;     //字母块及空白块
    boolean winstate;           //是否胜利
    /*
     * 负责初始化变量
     */
    public myCanvas() {
        scrW=getWidth();
        scrH=getHeight();
        String sbstring="J2MEJAVAVC++SQL ";
        sb=new StringBlock[16];
    //利用循环生成4×4的字母块
        for(int i=0;i<16;i++){
            sb[i]=new StringBlock();
            sb[i].ox=i%4;               //字母块的行数
            sb[i].oy=i/4;               //字母块的列数
            sb[i].x=sb[i].ox;
            sb[i].y=sb[i].oy;
        if(sb[i].oy>=2)
            sb[i].inv=true;
        else
            sb[i].inv=false;
            sb[i].word=sbstring.charAt(i);
        }
        blank=sb[15];
        blank.inv=false;
        winstate=false;
        addCommand(new Command("Exit",Command.EXIT,1));
        addCommand(new Command("Start",Command.OK,1));
        setCommandListener(this);
        th=new Thread(this);
    }
    /*
     * 负责绘制屏幕内容
     */
    protected void paint(Graphics g) {
        //清屏三句话
        g.setColor(255,255,255);
        g.fillRect(0,0,scrW,scrH);
        g.setColor(0);
        //具体绘制内容
        Font ft=Font.getFont(Font.FACE_MONOSPACE,Font.STYLE_PLAIN,Font. SIZE_MEDIUM);
        int wordw=ft.charWidth('M');
        int wordh=ft.getHeight();
        int pad=4;
        int gpad=2;
        int allw=(wordw+pad*2)*4+gpad*5;
        int allh=(wordh+pad*2)*4+gpad*5;
        //绘制外框线
        g.setColor(0);
        g.drawRect((scrW-allw)/2, (scrH-allh)/2, allw,allh);
        //绘制具体内容
        int x,y,dx,dy;
        for(int i=0;i<16;i++){
            x=sb[i].x;y=sb[i].y;
            dx=(scrW-allw)/2+(x+1)*gpad+x*(wordw+pad*2);
            dy=(scrH-allh)/2+(y+1)*gpad+y*(wordh+pad*2);
            if(sb[i].inv){
                g.setColor(0);
                g.fillRect(dx,dy,wordw+pad*2,wordh+pad*2);
                dx+=pad;
                dy+=pad;
                g.setColor(0xffffff);
                g.drawChar(sb[i].word,dx,dy,20);
        }
            else
            {
                g.setColor(0);
                g.drawRect(dx,dy,wordw+pad*2,wordh+pad*2);
                dx+=pad;
                dy+=pad;
                g.drawChar(sb[i].word,dx,dy,20);
            }
        }
        //当胜利时绘制胜利信息
        if(winstate){
        g.setColor(0xff);
        g.drawString("You Win!",scrW/2,scrH-20,20);
        }
    }
    /*
     * 负责键盘响应
     */
    protected void keyPressed(int key) {
        //把输入的键盘码转换成游戏码
        int k=getGameAction(key);
        //对转换的游戏码进行分析
        switch(k)
        {
        case UP: //如果是按下向上键有什么反应
            moveBlock(0);
            break;
        case DOWN:
            moveBlock(1);
            break;
        case LEFT:
            moveBlock(2);
            break;
        case RIGHT:
            moveBlock(3);
            break;
        }
        if(isSolved())
            winstate=true;
        repaint(); //千万不要忘了重绘命令
    }
    //判断是否所有字母块都归位
    private boolean isSolved() {
        int i=0;
        while(i<16)
        {
            if((sb[i].ox==sb[i].x)&&sb[i].oy==sb[i].y)
                i++;
            else
                return false;
        }
        return true;
    }
    //移动字母块,根据方向让字母块和空白块交换
    private void moveBlock(int i) {
        StringBlock temp = null;
        switch(i){
        case 0:
            temp=findBlock(blank.x,blank.y+1);
        break;
        case 1:
            temp=findBlock(blank.x,blank.y-1);
        break;
        case 2:
            temp=findBlock(blank.x+1,blank.y);
        break;
        case 3:
            temp=findBlock(blank.x-1,blank.y);
        break;
        }
        if(temp==null)return;
        swapblock(temp,blank);
    }
    private void swapblock(StringBlock a, StringBlock b) {
        int x,y;
        x=a.x;
        y=a.y;
        a.x=b.x;
        a.y=b.y;
        b.x=x;
        b.y=y;
    }
    private StringBlock findBlock(int x, int y) {
        StringBlock temp=null;
        for(int i=0;i<16;i++)
        {
            if(sb[i].x==x&&sb[i].y==y)
            {
                temp=sb[i];
                break;
            }
        }
        return temp;
    }
    public void run() {
        while(true){
            repaint();
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                // TODO 自动生成 catch 块
                e.printStackTrace();
            }
        }
    }
    public void commandAction(Command cmd, Displayable arg1) {
        switch(cmd.getCommandType())
        {
        case Command.EXIT:
            mainMidlet.quit();
            break;
        case Command.OK:
            winstate=false;
            daluan();
            break;
        }
    }
    //将字母块的顺序打乱
    private void daluan() {
        int j;
        Random rd=new Random();
        StringBlock temp;
        for(int i=0;i<140;i++){
            j=Math.abs(rd.nextInt())%4;
            moveBlock(j);
        }
        while(blank.x<3)
            moveBlock(2);
        while(blank.y<3)
            moveBlock(0);
        repaint();
    }
}

3.执行效果如图3-34所示

图3-34 字母拼图效果图