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