基于Nokia S40的猜数字游戏之二

来源:互联网 发布:软件架构总结 编辑:程序博客网 时间:2024/06/05 07:03

作者:mingjava  文章来源:http://www.j2medev.com/Article/ShowArticle.asp?ArticleID=143

现在我们已经有一能够接收用户输入事件的Button类了,下面我们应该考虑如何实现游戏中相关的逻辑,猜数字中的游戏逻辑都比较简单,主要是产生一个4位随机数字且不能重复,其次是根据输入返回给用户结果。我们提供一个Engine类来完成这个工作。
package com.j2medev.numbergame;

import java.util.Random;

public class Engine
{
    private int[] answer = new int[4];

    private Random random = new Random();

    public void init()
    {
        int[] number = new int[10];
        for (int i = 0; i < number.length; i++)
        {
            number[i] = i;
        }

        int n = 10;
        for (int index = 0; index < answer.length; index++)
        {
            int r = Math.abs(random.nextInt() % n);
            answer[index] = number[r];
            number[r] = number[n - 1];
            n--;
        }
    }

    public int[] getAnswer()
    {
        return answer;
    }

    public int[] queryResult(int[] input)
    {
        int[] state = new int[2];
        int a = 0;
        int b = 0;
        for (int i = 0; i < answer.length; i++)
        {
            for (int j = 0; j < answer.length; j++)
            {

                if ((input[j] ^ answer[i]) == 0)
                {
                    if (i == j)
                    {
                        a++;
                    } else
                    {
                        b++;
                    }

                }
            }
        }
        state[0] = a;
        state[1] = b;
        return state;
    }
}

    在游戏的运行中,我们有时候需要提示用户它的操作有误,比如输入数字为空,或者显示给用户已经答对了,一个庆祝的界面。当然这些你可以通过MIDP中提供的Alert来完成,我在这里实现了一个简单的界面类,这是一个抽象类,扩展了FullCanvas但是并没有实现paint()方法,把这个方法留给他的字类来实现。
/*
 * Created on 2004-12-21
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package com.j2medev.numbergame;

import java.util.Timer;
import java.util.TimerTask;

import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Font;

import com.nokia.mid.ui.FullCanvas;

public abstract class NumScreen extends FullCanvas
{
    protected Timer timer = new Timer();
    protected Display display;
    protected Manager next;
    protected int timeout;
    protected Font font;
   
    public NumScreen(Display display,Manager next)
    {
        this.display = display;
        this.next = next;

        setTimeout(3000);
    }
   
    public Font getFont()
    {
        if(font == null)
        {
            font = Font.getDefaultFont();
        }
        return font;
    }
   
    public void setFont(Font font)
    {
        this.font = font;
    }
   
    public void setTimeout(int time)
    {
        this.timeout = time;
    }
   
   
    public void dismiss()
    {
        timer.cancel();
        display.setCurrent(next);
    }
   
    public void showNotify()
    {
        timer.schedule(new TimerTask()
                {
              public void run()
              {
                  dismiss();
              }
                },3000);
    }
   
}
基于这个类,我们实现一个SplashScreen用在程序启动的时候的欢迎界面上,还提供一个类CongScreen用于显示用户的成绩和提示。

package com.j2medev.numbergame;

import java.io.IOException;

import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;

public class SplashScreen extends NumScreen
{

    public SplashScreen(Display display,Manager next)
    {
        super(display, next);
    }

    protected void paint(Graphics arg0)
    {
        Image welcome = null;
        try
        {
            welcome = Image.createImage("/welcome.png");
        } catch (IOException e)
        {
            e.printStackTrace();
        }

        arg0.drawImage(welcome, 2, 2, Graphics.TOP | Graphics.LEFT);
       

    }
   

}


package com.j2medev.numbergame;

import java.io.IOException;

import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;

public class CongScreen extends NumScreen
{

    private String title;

    private Mark mark;

    private Image image;
   
    private Image star;
   
    private Manager manager;
   
    private int type = CONG;
   
    public static final int CONG = 1;
    public static final int WARNING = 2;

    public CongScreen(Display display, Manager next)
    {
        super(display, next);
       
    }

    public CongScreen(Display display,Manager next, Mark mark)
    {
        this(display, next);
        this.mark = mark;
    
    }


    protected void paint(Graphics g)
    {
        int width = this.getWidth();
        int height = this.getHeight();
        if (image == null)
        {
            try
            {
                image = Image.createImage("/cong.png");
                star = Image.createImage("/star.png");
            } catch (IOException e)
            {
                e.printStackTrace();
            }
        }
        if (title != null)
        {
            g.drawString(title, width / 2, 5, Graphics.HCENTER | Graphics.TOP);
        }
        int offset = 10 + getFont().getHeight();
        g.drawImage(image, 2, offset, Graphics.TOP | Graphics.LEFT);
        offset = offset + image.getHeight();
       
        if(type == CONG)
        {
            int number = 5 - mark.getCount()/2;
            if(number ==0) number = 1;
           
            g.drawString("成绩:",2,offset+3,Graphics.TOP|Graphics.LEFT);
            for(int i = 0;i<number;i++)
            {
               g.drawImage(star,4+font.stringWidth("成绩:")+i*star.getWidth(),offset+3,Graphics.LEFT|Graphics.TOP);
               
            }
           
        }
    }

    public void setType(int type)
    {
        this.type = type;
    }

    public String getTitle()
    {
        return title;
    }

    public void setTitle(String title)
    {
        this.title = title;
    }

    public Mark getMark()
    {
        return mark;
    }

    public void setMark(Mark mark)
    {
        this.mark = mark;
    }
   

}

    至此我们程序需要的元素都有了,下面我们的任务是写游戏的MIDlet了。由于我是针对s40的手机写的游戏,因此在了解到他的屏幕为128*128之后,进行了界面布局的计算。并且用到了Nokia UI提供的FullCanvas类,但是没有使用它提供的DirectGraphics,因为没有太多需要图形和动作的处理。

package com.j2medev.numbergame;

import javax.microedition.lcdui.Display;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;

public class NumberGame extends MIDlet implements ButtonListener
{

    private Display display;

    private SplashScreen welcome;

    private Manager manager;

    private Button[] buttons = new Button[4];

    private Button cmd;

    private Mark mark;

    private Engine engine;

    protected void startApp() throws MIDletStateChangeException
    {
      
        initMIDlet();

    }

    private void initMIDlet()
    {
        display = Display.getDisplay(this);
        manager = new Manager();
        engine = new Engine();
        engine.init();

        int screenWidth = manager.getWidth();
        int screenHeight = manager.getHeight();
        int balance = screenWidth / 5;
        int buttonWidth = balance - 1;
        int buttonHeight = 15;
        for (int i = 0; i < buttons.length; i++)
        {
            buttons[i] = new Button("", 1 + i * balance, 1, buttonWidth,
                    buttonHeight);
            manager.add(buttons[i]);
            buttons[i].setMargin(8, 4);
            buttons[i].setListener(this);
        }

        cmd = new Button("OK", 1 + buttons.length * balance, 1, buttonWidth,
                buttonHeight);
        manager.add(cmd);
        cmd.setListener(this);
        cmd.setModifiable(false);

        mark = new Mark(1, 1 + cmd.getHeight() + 2, screenWidth - 3,
                screenHeight - 3 - cmd.getHeight());
        manager.add(mark);

        welcome = new SplashScreen(display, manager);
        display.setCurrent(welcome);

    }

    protected void pauseApp()
    {


    }

    protected void destroyApp(boolean arg0) throws MIDletStateChangeException
    {
       
    }

    public void buttonPressed(Button button)
    {
        String label = button.getLabel();
        if (label == "OK")
        {
            int[] res = getInput();
            if (res.length == 1)
            {
                CongScreen cs = new CongScreen(display, manager);
                cs.setTitle("数字不能为空");
                cs.setType(CongScreen.WARNING);
                display.setCurrent(cs);

                return;
            }
            int[] feedback = engine.queryResult(res);

            if (feedback[0] == 4)
            {

                CongScreen cs = new CongScreen(display, manager, mark);
                cs.setTitle("恭喜您!");

                display.setCurrent(cs);

                resetGame();
                return;
            }
            if (mark.getCount() == 9 & feedback[0] != 4)
            {

                CongScreen cs = new CongScreen(display, manager, mark);
                cs.setTitle("重新开始吧");
                cs.setType(CongScreen.WARNING);

                display.setCurrent(cs);

                resetGame();
                return;
            }
            mark.setInput(res);
            mark.setAB(feedback);
            mark.setOpen(true);
            manager.repaintArea(mark, true);
            mark.setOpen(false);

        }

    }

    public String input2String(int[] input)
    {
        String s = "";
        for (int i = 0; i < input.length; i++)
        {
            s = s + input[i];
        }
        return s;
    }

    private int[] getInput()
    {
        String[] inputString = new String[4];
        for (int i = 0; i < buttons.length; i++)
        {
            inputString[i] = buttons[i].getLabel();
        }

        for (int k = 0; k < inputString.length; k++)
        {
            if (inputString[k].equals(""))
            {
                return new int[] { 100 };
            }
        }

        int[] number = new int[4];
        for (int j = 0; j < inputString.length; j++)
        {
            number[j] = Integer.parseInt(inputString[j]);
        }
        return number;
    }

    private void resetButton()
    {
        for (int i = 0; i < buttons.length; i++)
        {
            buttons[i].setLabel("");
        }
    }

    public void resetGame()
    {
        resetButton();
        mark.reset();
        engine.init();
    }

}

    总结:这个游戏比较简单,但是其中组件的实现比较重要。我们从中可以学到回调以及容器管理组件的技术。由于本人没有游戏开发经验,因此在美工方面比较欠缺,只是随便画了几个图形。猜数字的界面也很淡薄,缺乏吸引力。我们的目的在于学习。希望游戏开发的高手多多分享一下自己的经验,我也会开始自己的下一个动作类游戏。

原创粉丝点击