`
kalogen
  • 浏览: 879993 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

J2ME游戏设计框架

    博客分类:
  • J2me
 
阅读更多

  因为移动设备运行速度问题,J2ME开发比较注重程序的复杂度。为了寻求时间复杂度与空间复杂度的一个平衡,通常将程序分为多个页面。多个页面就需要一个管理工具。本文展示了一种经典的J2ME中管理多个页面的调度器。

基础结构

为每一个页面编写一个类,在每一个类中实现以下方法

//无参的构造方法
//执行的run方法
public void run() {}
//绘图的paint方法,参数为屏幕的画笔
public void paint(Graphics g) {}
//按键时的响应方法,参数为按键消息码
public void keyPressed(int key) {}

调度器应该继承Canvas类,实现Runnable接口,完成以下功能

1、changeState方法

负责一个页面到另一个页面的切换。为了节约资源,应该根据旧的状态量释放当前页面,再根据请求的新状态创建另一个页面。

2、run方法

根据状态量判断当前哪个页面,并调用它(当前页面)的run方法。

3、paint方法

调用当前页面的paint(绘图)方法

4、keyPressed方法

调用当前页面的keyPressed(键盘相应)方法

这些是基本的功能,还可以根据需要添加更多的Canvas类中的方法,实现更多功能。

实现示例

这里演示了ModelLogo,ModelMenu和ModelGame三个页面的切换

public class ZYMIDlet extends MIDlet
{
	static ZYCanvas canvas = null;
	static ZYMIDlet midlet = null;
	/**初始动作 不要在构造函数中进行 可能出现问题
	 * 这主要是因为移动设备的资源性能都有限,
	 * 因此此种程序开发的一个宗旨是“在需要用资源的时候申请,用完立刻释放”
	 * */
	public ZYMIDlet()
	{
		midlet = this;
	}
	
	/**大多数初始化工作是放在startApp中完成
	 * midlet创建的时候 执行完构造函数,会调用此函数,midlet进入活跃状态
	 * midlet从暂停状态 恢复的时候 也会自动调用此函数*/
	public void startApp()
	{
		if(canvas == null)
		{
			canvas = new ZYCanvas();
		}
		Display display = Display.getDisplay(this);
		display.setCurrent(canvas);
	}
	public void pauseApp()
	{}	
	public void destroyApp(boolean unconditional)
	{}
}
class ZYCanvas extends Canvas implements Runnable
{
	public static final byte STATE_LOGO = 0;
	public static final byte STATE_MENU = 1;
	public static final byte STATE_GAME = 2;

	public static int state;

	public ModelLogo modelLogo;
	public ModelMenu modelMenu;
	public ModelGame modelGame;

	public ZYCanvas()
	{
		state = STATE_LOGO;

		//开启线程
		changeState(STATE_LOGO);
	}

	/**改变状态:这里可以做一些 上个状态的模块清除资源工作,和 新状态模块的初始化工作*/
	public static void changeState(byte new_state)
	{
		//可做的事情:清除上一个模块的资源
		state = new_state;
		//可作的事情:创建新状态模块,初始化
	}

	//每80毫秒执行一次
	public void run()
	{
		long time = System.currentTime();
		
		action();
		repaint();	//通知调用paint()函数
		serverPaint();	//强制paint执行

		long dur = System.currentTime() - time;
		long test = 80 - dur
		if(test > 0){
			try{Thread.sleep(test);}catch(Exception e){}
		}
	}
	//可以把要做的事情全部放到一个函数中
	public void action()
	{
		switch(state)
		{
			case STATE_LOGO: modelLogo.run();break;
			case STATE_MENU: modelMenu.run();break;
			case STATE_GAME: modelGame.run();break;		
		}	
	}


	//可以把要做的事情全部放到一个函数中
	public void paint(Graphics g)
	{
		switch(state)
		{
			case STATE_LOGO: modelLogo.paint(g);break;
			case STATE_MENU: modelMenu.paint(g);break;
			case STATE_GAME: modelGame.paint(g);break;		
		}	
	}
	
	public void keyPressed(int key)
	{
		switch(state)
		{
			case STATE_LOGO: modelLogo.keyPressed(key);break;
			case STATE_MENU: modelMenu.keyPressed(key);break;
			case STATE_GAME: modelGame.keyPressed(key);break;		
		}
	}
}

/**封装模块*/
class ModelLogo
{
	public ModelLogo(){}
	public void run()
	{
		//运行自己的逻辑
		//如果这个状态结束可以调用ZYCanvas.changeState()来改变状态
	}
	public void paint(Graphics g){}
	public void keyPressed(int key){}
}
class ModelMenu
{
	public ModelGame(){}
	public void run()
	{
		//运行自己的逻辑
		//如果这个状态结束可以调用ZYCanvas.changeState()来改变状态
	}
	public void paint(Graphics g){}
	public void keyPressed(int key){}
}
class ModelGame
{
	public ModelGame(){}
	public void run()
	{
		//运行自己的逻辑
		//如果这个状态结束可以调用ZYCanvas.changeState()来改变状态
	}
	public void paint(Graphics g){}
	public void keyPressed(int key){}
}

一些问题

通过调度器只需要调用changeState方法就可以在页面直接进行切换。但是实际应用时调度器有一些不足

我们想添加一个页面,需要声明一个状态量,再页面相应的类,然后在调度器每个方法中添加对于新的页面要执行的操作。

很明显的,不符合封装的设计思想。

怎样把调度器封装起来呢?

改进思路

很明显,我们要解决的最主要的问题是当调度器编写时,并不知道未来有一个什么样的页面类将要供调度器调度。

该如何使用未知的类?

我们可以应用java语言反射机制动态加载类来解决这类问题。通常,我们想要创建一个对象,我们采用以下方法

Class c = new Class();

java提供了动态加载类的机制,在运行时通过一个表示类名的字符串查找一个类并加载,还可以产生它的一个实例。使用方法如下

getClass().forName("package.className").newInstance();

只要创建一个调度器对象,再将页面类的类名添加进调度器,调度器使用动态加载类创建页面对象就可以了

改进

通过动态加载类创建的对象是Object类型的,显然这是没有我们想要的run,paint,keyPressed方法的,要通过强制类型转换把Object类型对象装换成含有这些方法的对象。

把它转换成什么类型对象合适,又如何保证用户编写的页面类肯定有这些方法呢?

通过java的接口来保证!

下面编写一个接口,规定用户编写的所有页面必须实现这个接口

package com.shiying.frame;

import javax.microedition.lcdui.Graphics;

//页面接口
public interface Model {
	
	public void run();
	
	public void paint(Graphics g);
	
	public void keyPressed(int key);
}

要使用动态加载类,应该保存每个页面类的类名字符串,同时还要保存每个页面所对应的状态量。最简单的使用集合来保存

private static Vector stateVector = new Vector();
private static Vector nameVector = new Vector();

为了调用当前类的方法,还要保存当前类的状态和对当前类对象的引用,这个页面应该是Model类型

private static Model model = null;
private static byte state;

下面编写一个方法,用来向调度器注册页面

public void addModel(byte stateId, String modelClassName) {
	stateVector.addElement(new Byte(stateId));
	nameVector.addElement(modelClassName);
}

当用户发出切换页面的请求后,应该释放当前页面,并启动新的页面

     /*
	 * 通过状态查找在表中的位置
	 */
	private static int searchState(byte state) {
		for (int n=0; nif (((Byte)Framework.stateVector.elementAt(n)).byteValue() == state) {
				return n;
			}
		}
		return -1;
	}

	/**改变状态:这里可以做一些 上个状态的模块清除资源工作,和 新状态模块的初始化工作*/
	public static void changeState(byte new_state)
	{
		//清除上一个模块的资源
		int index = searchState(state);
		if (index != -1)
			model = null;
		
		//状态转换
		state = new_state;
		
		//创建新状态模块,初始化
		index = searchState(new_state);
		if (index != -1)
		{
			String name = (String)Framework.nameVector.elementAt(index);
			Class c = null;
			try {
				c = Class.forName(name);
				model = (Model) c.newInstance();
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
	}

因为每个时刻至多有一个页面对象,所以不需要判断状态,对页面函数调用就非常简单

     //每80毫秒执行一次
	public void run()
	{
		while (true) {
			long time = System.currentTimeMillis();

			action();
			repaint();	//通知调用paint()函数
			serviceRepaints();	//强制paint执行

			long dur = System.currentTimeMillis() - time;
			long test = 80 - dur;
			if(test > 0){
				try {
					Thread.sleep(test);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
	//可以把要做的事情全部放到一个函数中
	public void action()
	{
		if (model != null) {
			model.run();
		}
	}


	//可以把要做的事情全部放到一个函数中
	public void paint(Graphics g)
	{
		if (model != null) {
			model.paint(g);
		}
	}
	
	public void keyPressed(int key)
	{
		if (model != null) {
			model.keyPressed(key);
		}
	}

编写一个启动调度器的方法,需要指明开启的第一个页面

     public void go(byte start) {
		//开启线程 
		state = start;
		changeState(start);
		
		Thread th = new Thread(this);
		th.start();
	}
OK,改装结束,整理一下代码
 

完整代码

//    Main.java    //////////////////////////////////////
package com.shiying.frame;


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

import com.shiying.Application.Frame;

public class Main extends MIDlet{

	static Frame canvas = null;
	static Main midlet = null;

	public Main()
	{
		midlet = this;
	}
	
	public void startApp()
	{
		if(canvas == null)
		{
			canvas = new Frame();
		}
		Display display = Display.getDisplay(this);
		display.setCurrent(canvas);
	}
	public void pauseApp()
	{}
	public void destroyApp(boolean unconditional)
	{}
	
	public static void shutDown() {
		midlet.notifyDestroyed();
	}

}


//    Model.java    //////////////////////////////////////
package com.shiying.frame;

import javax.microedition.lcdui.Graphics;

//页面接口
public interface Model {
	
	public void run();
	
	public void paint(Graphics g);
	
	public void keyPressed(int key);
}


//    Framework.java    //////////////////////////////////////
package com.shiying.frame;

import java.util.Vector;

import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Graphics;

public class Framework extends Canvas implements Runnable {

	public static Framework canvas = null;
	
	private static Vector stateVector = new Vector();
	private static Vector nameVector = new Vector();
	
	private static Model model = null;
	private static byte state;
	
	public Framework()
	{
		Framework.canvas = this;
	}
	
	public void go(byte start) {
		//开启线程 
		state = start;
		changeState(start);
		
		Thread th = new Thread(this);
		th.start();
	}
	
	public void addModel(byte stateId, String modelClassName) {
		stateVector.addElement(new Byte(stateId));
		nameVector.addElement(modelClassName);
	}
	
	/*
	 * 通过状态查找在表中的位置
	 */
	private static int searchState(byte state) {
		for (int n = 0; n < Framework.stateVector.size(); n++) {
  			 	if (((Byte) Framework.stateVector.elementAt(n)).byteValue() == state) {
  			  	return n;
  			 }
  		  }
		return -1;
	}

	/**改变状态:这里可以做一些 上个状态的模块清除资源工作,和 新状态模块的初始化工作*/
	public static void changeState(byte new_state)
	{
		//清除上一个模块的资源
		int index = searchState(state);
		if (index != -1)
			model = null;
		
		//状态转换
		state = new_state;
		
		//创建新状态模块,初始化
		index = searchState(new_state);
		if (index != -1)
		{
			String name = (String)Framework.nameVector.elementAt(index);
			Class c = null;
			try {
				c = Class.forName(name);
				model = (Model) c.newInstance();
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
	}

	//每80毫秒执行一次
	public void run()
	{
		while (true) {
			long time = System.currentTimeMillis();

			action();
			repaint();	//通知调用paint()函数
			serviceRepaints();	//强制paint执行

			long dur = System.currentTimeMillis() - time;
			long test = 80 - dur;
			if(test > 0){
				try {
					Thread.sleep(test);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
	//可以把要做的事情全部放到一个函数中
	public void action()
	{
		if (model != null) {
			model.run();
		}
	}


	//可以把要做的事情全部放到一个函数中
	public void paint(Graphics g)
	{
		if (model != null) {
			model.paint(g);
		}
	}
	
	public void keyPressed(int key)
	{
		if (model != null) {
			model.keyPressed(key);
		}
	}
}
 

如何使用

首先编写的所有页面需要实现Model接口,并且具有公有的无参构造方法

package com.shiying.Application;

import javax.microedition.lcdui.Graphics;

import com.shiying.frame.Model;

/*
 * 这是一个页面的示例,每一个页面必须实现com.shiying.frame.Model接口
 */
public class ModelDemo implements Model {
	
	/*
	 * 页面必须具有一个共有的无参构造方法
	 */
	public ModelDemo() {
		
	}

	/*
	 * 这个方法中添加页面对按键消息的响应过程
	 */
	public void keyPressed(int key) {
		// TODO Auto-generated method stub
		
	}

	/*
	 * 这个方法实现页面绘图过程
	 */
	public void paint(Graphics g) {
		// TODO Auto-generated method stub
		System.out.println("Demo paint");
		g.drawString("Frame Demo", Frame.canvas.getWidth() / 2, 100,
				Graphics.HCENTER|Graphics.TOP);
	}

	/*
	 * 这个方法实现页面要执行的操作
	 */
	public void run() {
		// TODO Auto-generated method stub
		System.out.println("Demo run");
	}

}
下面编写一个调度器类,这个类是Framework类的子类
这个类需要完成的工作有
1、声明每个页面的状态量
2、注册页面类
3、启动第一个页面
package com.shiying.Application;

import com.shiying.frame.Framework;



public class Frame extends Framework {
	
	/*
	 * 这里声明代表每个页面的状态量(页面ID) 
	 */
	public static final byte STATE_DEMO = 0;
	

	public Frame() {
		super();
		
		/*
		 * 这里添加页面,需要传入两个参数,页面ID和相应页面类所在位置
		 */
		this.addModel(Frame.STATE_DEMO, "com.shiying.Application.ModelDemo");
		
		
		/*
		 * 这里设置第一个活跃的页面
		 */
		this.go(Frame.STATE_DEMO);
	}
	
}
 当这个类被创建时,第一个页面会被自动调用。在第一个页面中可以根据需要调用changeState可以切换到下一个页面。
原文地址:http://www.cnblogs.com/S-E-P/archive/2010/10/11/2045052.html
分享到:
评论

相关推荐

    j2me 手机游戏 通用框架(非常强大).rar

    《J2ME手机游戏通用框架详解》 J2ME(Java 2 Micro Edition)是Java平台的一个重要分支,主要用于移动设备、嵌入式设备和消费类电子产品的开发。在早期智能手机时代,J2ME作为手机游戏开发的重要工具,拥有广泛的...

    基于JAVA基于J2ME的手机游戏开发的毕业设计,游戏采用了J2ME的游戏框架MIDP2.0,使用了J2ME的游戏引擎LWJGL

    游戏设计了5个游戏场景,分别是森林场景、海洋场景、城堡场景、火车场景和宇宙场景。每个场景都设计了不同的游戏角色、游戏物品和游戏敌人。游戏角色可以在不同场景中切换,实现了游戏的连贯性。游戏物品和游戏敌人的...

    j2me2D游戏框架

    J2ME游戏框架通常包含一个优化的游戏循环,确保游戏性能稳定且与硬件兼容。 3. **事件处理**:框架会提供一套事件处理机制,让开发者能够轻松响应用户输入,如触摸屏点击或键盘按键。 4. **资源管理**:2D游戏通常...

    手游公司的J2ME手机游戏框架

    《手游公司的J2ME手机游戏框架详解》 Java Micro Edition(J2ME)是一种轻量级的Java平台,主要用于移动设备、嵌入式系统和其他资源有限的设备上。在手游领域,J2ME曾是开发早期手机游戏的主流技术之一。本文将深入...

    j2me开发框架介绍

    EasyMF 是一个 J2ME 开发框架,目标是设计一个简单、稳定、可快速开发的 J2ME 开发框架。它简化了 UI 设计、RMS 操作、日志框架、联网框架、通用工具设计等多个方面。EasyMF 的功能列表包括 UI 框架、日志框架、RMS ...

    J2ME游戏开发中的WTK游戏框架

    "J2ME游戏开发中的WTK游戏框架" 指的是在Java Micro Edition(J2ME)平台上,使用Wireless Toolkit(WTK)进行游戏开发时所采用的一种特定的游戏开发框架。J2ME是Java的一个子集,用于开发和部署在移动设备、...

    J2ME游戏设计马力快跑

    J2ME游戏设计的核心在于理解其基本框架,包括MIDP(Mobile Information Device Profile)和CLDC(Connected Limited Device Configuration)。MIDP提供了用户界面组件和网络功能,而CLDC则定义了小型设备所需的运行...

    J2ME游戏源代码

    通过分析这些J2ME游戏源代码,你可以学习到如何在有限的硬件条件下创建引人入胜的游戏体验,掌握游戏设计、性能优化以及跨平台开发的技巧。同时,这也能帮助你了解移动游戏开发的历史,因为随着技术的发展,现代移动...

    J2ME 游戏 J2ME 游戏 java 毕业设计

    在Java毕业设计中,J2ME游戏开发是一个常见的选题,因为它能够让学生掌握移动应用开发的基本技能,同时在实际项目中应用Java编程知识。 **J2ME游戏开发基础** 1. **环境配置**:首先,开发者需要安装Java SDK和...

    J2ME游戏开发J2ME游戏开发

    J2ME游戏开发是一个涵盖多方面技术的领域,包括理解MIDP和CLDC、图形编程、动画制作、游戏逻辑设计、网络通信以及数据存储。虽然现在许多现代移动设备已经转向更强大的平台如Android和iOS,但J2ME仍然是学习游戏开发...

    J2ME游戏设计(打地鼠)

    **J2ME游戏设计——打地鼠项目** Java 2 Micro Edition (J2ME) 是一个专门用于开发小型设备和嵌入式系统的Java平台。它为移动设备和消费电子产品的应用程序开发提供了广泛的框架。本项目“J2ME游戏设计(打地鼠)”...

    J2ME游戏框架

    **J2ME游戏框架详解** Java 2 Micro Edition(J2ME)是Java平台的一个子集,主要用于开发和运行在移动设备、嵌入式设备上的应用程序,特别是在游戏领域有着广泛的应用。J2ME游戏框架为开发者提供了一套工具和API,...

    j2me游戏开发实例

    **J2ME游戏开发实例详解** J2ME(Java 2 Micro Edition)是Java平台的一个子集,专门用于开发在移动设备和嵌入式设备上的应用程序,包括游戏。本资源包含多个J2ME游戏的源代码,对于学习J2ME游戏开发的初学者来说,...

    J2ME手机游戏开发引擎的分析与设计

    【J2ME手机游戏引擎开发引擎的分析与设计】 本文主要探讨了J2ME手机游戏引擎的开发,这种引擎能够帮助开发者快速构建J2ME平台上的游戏,通过自定义参数生成游戏...通过合理的设计和实施,有望推动J2ME游戏领域的发展。

    j2me游戏引擎(强大编辑器及光照效果)

    J2ME游戏引擎是专门针对J2ME平台构建的游戏开发框架,它简化了游戏的编程工作,提供了丰富的功能和优化性能。这种引擎通常包括图形渲染、音频处理、物理模拟、用户输入管理等多个组件,帮助开发者快速构建高质量的2D...

    j2me游戏开发详解

    《J2ME游戏开发详解》这本书深入探讨了Java 2 Micro Edition(J2ME)平台上的游戏开发技术,为读者揭示了如何利用这一强大的移动开发框架来创建吸引人的手机游戏。J2ME作为早期智能手机和平板设备上的主流开发平台,...

    J2ME游戏程序开发实例详解.pdf

    由于设备资源有限,J2ME游戏通常比PC游戏或游戏机游戏简单许多。下面将围绕J2ME游戏程序开发的关键知识点进行详细解释。 1. J2ME的架构和配置: J2ME由配置(Configuration)、简表(Profile)和可选包(Optional ...

    基于MVC模式的J2ME应用程序框架设计

    ### 基于MVC模式的J2ME应用程序框架设计 #### 1. J2ME应用程序框架背景 自1999年Sun公司推出J2ME(Java2 Micro Edition)以来,这一技术专为资源受限的设备(如早期的手机、PDA和其他小型设备)设计。J2ME的目标是...

Global site tag (gtag.js) - Google Analytics