以前本人做过贪吃蛇的游戏(C++),现在正好在学java,我可以帮你看一下,你把代码发到我的信箱里:[email protected],我会尽快给你答复的

解决方案 »

  1.   

    我不太了解j2me,但我可以帮你分析一下代码!!同上!!
      

  2.   


    你好,代码我看了一下,虽然我对j2me的midlet不太了解,但我认为此程序只有两个线程:main主线程-A和wormpit中的线程--B,主线程负责监听键盘事件,而线程B负责对界面进行重绘操作,因此程序中有很多的wait,notifyall,以及synchronized,下面我来解释一下为什么?
    由于线程A,B都会对一些变量进行访问如:gameOver,gamePaused,audioPlayer等,因此需要对他们进行同步的访问。 首先,程序出现了很多的同步块:而没有使用synchronized方法
    其格式为:synchronized(object){....}
        它可以获得对象的少数几个指令的独占访问权,在程序中使用同步机制时有一个原则:就是不要在synchronized方法中花费大量的时间。如果本程序使用了同步方法的话,无疑会违背这一原则(虽然也可运行,但效率不高),因此在程序中当需要对一些变量进行操作时,使用了同步块。一般系统编程人员比较可能使用同步块以提高程序运行效率,see了,老外做东西是TMD得想得多了一点。
    OK。下面看看程序中的代码的几个同步块:
      1。  synchronized (myWorm) {//不是在B的run()方法中,它是主线程A的操作
            if (audioPlayer != null) {
            audioPlayer.close();
            audioPlayer = null;
            }
            if (tonePlayer != null) {
            tonePlayer.close();
            tonePlayer = null;
            }//主线程A取得了对象myWorm的锁,并取得了块中的代码的独占访问权(即是其中 几个变量的访问权),这样可以与主线程A互斥的设置这几个变量。
            myWorm.notifyAll();//当设置结束后释放该锁,通知所有在等待列表中的线程(这里只有线程B)可以访问该资源了,B线程会从程序中的wait()方法后继续运行。
        } 2。 synchronized (myWorm) {
            gameDestroyed = true;
            
            myWorm.notifyAll();//同上
        }
      
    3。     synchronized (myWorm) {
                if (gameOver) {
                  if (WormScore.getHighScore(level) < score) {
                    /* Display score screen */
                    WormScore.setHighScore(level, score, "me");
                }
                if ((audioPlayer != null) &&
                    (audioPlayer.getState() == Player.STARTED)) {
                    try {
                    audioPlayer.stop();
                    Manager.playTone(60, 400, 100);
                    } catch (Exception ex) { }
                }
                repaint();
                // serviceRepaints(); // Draw immediately
                myWorm.wait();// 挂起线程B等待主线程A的操作,这里是等待用户的键盘事件
                        //当主线程A运行到上面的notifyAll()方法后,说明键盘事件结束,
               //主线程A已经对一些变量进行了同步的设置,这时线程B继续从这里运行
                                   
                } else if (gamePaused) {
                repaint();
                // serviceRepaints(); // Draw immediately
                myWorm.wait();//同上
              }
       完!不知道你还有什么问题?大家一同商量,如有错误请高手多多指教!!!
      

  3.   

    不好意思错了
    ,上面第一个注释应该是//主线程A取得了对象myWorm的锁,并取得了块中的代码的独占访问  权(即是其中 几个变量的访问权),这样可以与"线程B"互斥的设置这几个变量。在请问楼上的可否把你的Worm程序法一份给我。[email protected],谢了
      

  4.   

    谢谢楼上的,不过我觉得repaint方法里肯定还包括一个线程的,你认为呢?
      

  5.   

    经过一段时间学习j2me,除了类库受限外,我还觉得midlet和application之间的差别
    主要表现在对程序的控制上,一个application的控制权完全在于程序员本身,但是,
    我觉得自己写的midlet程序是不能叫做完整的程序的,因为JAMS(Java Application Management System)也是控制midlet的极为重要的角色,这个角色甚至比你自己还要重要。我认为,当一个midlet启动的时候,必然有一个优先级较高的线程跟随着该midlet启动,
    其主要任务是监听键盘输入,当然,就像楼上所说,这个线程就是主线程。除过主线程之外,JAMS应该还有一个机制来监听midlet的状态的转变,当你调用destroyApp(false);noticeDestroyed();时,这个机制就将当前状态转变为销毁态,当你调用pauseApp();noticePause();时,这个机制就将当前状态转变为暂停态。notice方法正是这个机制和midlet的通信接口!当然,这个机制也可以是主线程。上面所说的两点,其内容都由JAMS来做,所以说,midlet不完全控制在程序员的手中。
      

  6.   

    我对j2me不是很了解,但是我觉得midlet有点像java applet,也有一个init,start,stop的过程,但这些是由系统或者说虚拟机控制的,其实你一样可以很好的控制程序,只不过要多考虑一些问题而已。放暑假也没回家,正好没事一个人在实验室又写了个贪吃蛇(applet的),不过还有点问题,搞好了我会把它贴出来。
      

  7.   

    to:gyf168(下蛋的猴子)这是我昨天写的一篇文档,咱们讨论讨论:==============================================================================
    标题:敲开MIDlet的脑壳----在MIDlet中另外运行的两个线程
    作者:qlampskyface先定义几个名词:
    1.MyMIDlet是继承了MIDlet的类(至于MyMIDlet是否实现其它接口,我们不去关心)
    2.MyCanvas是继承了Canvas的类(MyCanvas是否实现其它接口,我们也不去关心)
    3.“进入”表示跟进debug的路线
    第一个“另外”:
        经过debug,我发现,在主线程中,一个midlet中最先被执行的代码是MyMIDlet类的对象的构造函数,而后进入了java.lang.Class类(public final)的runCustomCode()方法(static),而后再进入com.sun.midp.midlet.MIDletState类(public abstract)中未知方法(调试看不出来,如有人知道请告知),而后再进入com.sun.midp.midlet.Selector类(extends MIDlet implements CommandListener, Runnable)中,启动了run()方法,第一个“另外”诞生了。第二个“另外”:
        接着上面继续debug:
        下来才是调用MyMIDlet类实例的startApp方法,执行
    Display.getDisplay(this).setCurrent(Displayable),由于setCurrent的参数是MyCanvas类的实例,所以,这一执行(指Display.getDisplay(this).setCurrent(Displayable))即调用(进入)了MyCanvas的paint()方法,所以,Display的成员方法setCurrent应该类似于下面的代码:
    public void setCurrent(Displayable d){
      ... ...
      Graphics g = d.getGraphics();//生成Graphics实例
      d.paint(g);
      ... ...
    }在执行完paint方法之后,进入了Canvas类中的其它未知方法,而后再进入Display的未知方法,而后进入几个无关类之后就断掉了,原因无从查找,不过我们可以这样得到第二个另外:
    在模拟器单击开始,你会发现又能debug了,这时,当你执行完commandAction方法后,再debug几次,你就进入了这么一个类:com.sun.midp.lcdui.DefaultEventHandler(public & implements EventHandler),而后进入com.sun.midp.lcdui.AutomatedEventHandler(public & extends DefaultEventHandler implements AutomationHandler)类,这两个类成继承关系,而在DefaultEventHandler类中又有一个内部类VMEventHandler(implements Runnable)实现了run()方法,所以,第二个“另外”产生了:)关于第一个“另外”:我认为这个线程是监听midlet状态的监听线程,叫状态监听线程关于第二个“另外”:我认为是监听键盘输入的监听线程,叫键盘监听线程所以,在一个midlet中,一般有下面这四个线程:1.主线程2.状态监听线程3.键盘监听线程4.自己实现的画动画的线程。关于自己程序中画动画的线程(该线程中实现了对动画的repaint):
    该线程在上述步骤中已经启动,启动的地方通常有两个,一处是在MIDlet对象的构造过程中(如果有和该对象成聚合关系的其它对象,则也在这里初始化);另外一处则在startApp()方法中,在实现了Display.getDisplay(this).setCurrent(Displayable);语句之后。
    =======================================================================
    在上面的debug过程中,我使用的是sun自己的wtk2.1,别的api的debug过程可能不一样,但是这是大同小异的,你可以触类旁通。
    比如西门子的api中监听键盘线程在javax.microedition.lcdui.EventQueue(final & implements Runnable)中实现.