您的当前位置:首页正文

J2ME课程设计

2024-04-27 来源:步旅网


浙江万里学院2012 /2013 学年第 一 学期

《J2ME开发技术》大作业

题目:角色扮演类游戏RPG(Role Play Game)游戏

《MM历险记》

组长:XXX

组员:XXX XXX|

小组分工:

package mmrpg; package mmrpg; package mmrpg; package mmrpg; package mmrpg; package mmrpg; package mmrpg; 代码调试及修改实验报告

-- 行动 --界面布局 --按钮控制 --用户界面 --NPC设置 --事件管理 --主应用程序

目 录

1 摘要…………………………………………………………………………….……. 3

2 设计内容及要求…………………………………………………………………… 3

3 设计过程…………………………………………………………............…………. 4 3.1 设计方案……………………………..................................…………………… 4 3.2 概要设计………………………............................................…………………...5 3.3 界面设计图 ………………........................................………………………… 6 3.4 代码实现………….............................................................................…………...11

4 设计总结….......................................…………………………………………………11

附录:程序源代码…….....................................…………………………………….11

1 、摘要

本文给出了一个基于MIDP的角色扮演类游戏RPG(Role Play Game)游戏设计方案,并给出全部实现源代码。利用J2ME语言编程的思想来完成系统的设计,然后编写出程序设计代码进行界面设计,实现友好的界面交互,具有清晰的程序流程图,最后编程实现了全过程。该游戏的最大特色是屏幕自适应,无论各种手机,PDA的屏幕大小如何,该游戏总是能获得最佳的显示效果。

2 、设计内容和要求

一个完整的RPG游戏至少要有故事情节、人物、NPC(游戏中不受游戏者操控的角色,通常为游戏中城镇、村落的商人等游戏人物通过与之对话进行物品交易或获取信息)、场景四个要素。

3 、设计过程

3.1 设计方案

J2ME语言继承了JAVA语言易学易用的特点,特别适合于初学者学系统编程。随着21世纪信息社会的到来,计算机在人们的工作和生活中的深入,要求我们越来越多地与计算机打交道,为了使用户在繁忙的日程工作中得到放松,于是出现了各种各样的休闲软件,如聊天工具,游戏等等。通过这学期来J2ME课程的学习,我初步掌握了J2ME语言的最基本的知识,于是老师的指导下动手用J2ME编写角色扮演类游戏RPG(Role Play Game)游戏,MM历险记。

RPG要素如下:1、故事情节:一个MM被困在洞穴里,她不懈努力,最终逃出了洞穴。2、人物:MM,是游戏的控制角色。可使用方向键移动MM。3、NPC:游戏中设置若干个NPC,MM通过与之对话,可知道洞穴的出口。4、场景:本游戏要求设计至少2个以上场景,分别是洞穴的第N层。MM可通过阶梯从洞穴的一层进入另一层。每层场景都有阶梯、泥地和石头等区域。其中,有石头的区域被设置成MM不可以通过的区域。

3.2 概要设计

本游戏的操作流程非常简单,用户启动MIDlet启动后,即进入游戏主画面,屏幕开始显示为欢迎画面。用户按下[开始]按钮后,就可以开始玩游戏了,当用户想暂停时,再次按一下[开始]按钮,游戏就暂停了,在暂停的情况下再按[开始]按钮,游戏继续运行。任何时候按[退出]按钮,游戏MIDlet都会终止.

游戏画面流程图如下:

MIDlet选择画面

[启动]按钮 欢迎画面 [退出]按钮 游戏运行画面 [开始]按钮 [退出]按钮

游戏暂停画面

游戏在结束状态

GAME OVER 本程序共有7个java源文件: package mmrpg; -- 行动 package mmrpg; --界面布局 package mmrpg; --主应用程序 package mmrpg; --按钮控制 package mmrpg; --用户界面

package mmrpg; --NPC设置 对话 package mmrpg; --事件管理

3.3界面设计图

paint方法的流程图如下所示:

游戏处于欢迎画面状态 游戏处于Game Over状态 游戏处于暂停状态 游戏处于运行状态 绘制欢迎画面 绘制Game Over 画面 NPC 对话 是 执行空操作 否 继续寻找 否 是否找到出口 是 继续寻找 得到提示 显示对话 显示Game Over 是 Game Over 设置游戏状态为 否 Game Over 继续寻找 Game Over 结 束

(1) 初始化欢迎界面(如图所示)

初始欢迎界面显示了程序初始的一个屏幕

(2)游戏主界面(如图所示)

进入游戏界面后,在游戏窗体中用户就可以使用键盘的方向键来控制MM行走路线

过程中,与NPC对话,得到出口提示,图为NPC1

图为MM与NPC2对话,得到最后提示,知道出口地方

图为,MM找到游戏出口,游戏结束

3.4代码实现

MIDP的游戏设计,本质上就是用一个线程或者定时器产生重绘事件,用线程和用户输入改变游戏状态。这个游戏也不例外,启动MIDlet后,就立即生成一个重绘线程,该线程每隔50ms绘制一次屏幕。当然,重绘时有一些优化措施,并不是屏幕上所有的像素都需要重绘,而是有所选择。

游戏区域

游戏区域为手机屏幕的一部分,该区域为正方形

游戏地图

游戏地图是用来存储游戏容器上的固定地图块。游戏容器为一个宽为6个小地图块单位,高为6个小地图块单位,所以用一6X的二维数组(程序里叫mapdata)来存储固定地图块。

4 、设计总结

由于课程设计时间较短,所以该游戏还有许多不尽如人意的地方,比如NPC 数量少,才两个地图层也只有两个,游戏难度很低,退出游戏不能存储进度等多方面问题。这些都有待进一步改善,如在游戏中还可以更换背景音乐,以适合不同的玩家,在每通过一关可以给玩家播放一段flash,吸引玩家去挑战极限,不断提高玩家的兴趣。

课程设计已经结束了,但在课程设计的这些体会要应用到今后的日常学习中去。在新的学期,我觉得自己要在以下几个方面加以注意:

首先,在学习专业课的时候要注意理论联系实际。注意将课本上的知识应用到日常的操作中,真正做到学以致用。只有这样,才能做到目的明确,才能有足够的学习动力。

其次,在学习过程中要经常与同学进行交流,讨论所遇到的问题,并一起解决。在讨论中解决问题,会节约很多时间,并且在交流的过程中,我们也可以学到更多的东西。

课程设计已经结束了,这次课程设计带给自己很多体会,在以后的学习中要不断总结,不断改进,使自己的成绩有新的提高。

附录:程序源代码

package mmrpg; -- 行动

import javax.microedition.lcdui.Image;

import javax.microedition.lcdui.game.GameCanvas; import javax.microedition.lcdui.game.Sprite;

public class Actor extends Sprite{

private int m_nLastMoveX; private int m_nLastMoveY;

//上次移动的X距离 //上次移动的Y距离

Actor(Image image, int frameWidth, int frameHeight){ super(image, frameWidth, frameHeight); }

//处理按键输入

public void Input( int keyStates ){ int nFrame = getFrame();

if( ( keyStates & GameCanvas.UP_PRESSED ) != 0 ) {//向上运动 Move( 0, -1 );

nFrame ++;

if( nFrame > 1 || nFrame < 0 ) nFrame = 0; setFrame( nFrame );

setTransform( TRANS_NONE ); }

else if( ( keyStates & GameCanvas.RIGHT_PRESSED ) != 0 ) {//向右运动 Move( 1, 0 );

nFrame ++;

if( nFrame > 3 || nFrame < 2 ) nFrame = 2; setFrame( nFrame );

setTransform( TRANS_NONE ); }

else if( ( keyStates & GameCanvas.DOWN_PRESSED ) != 0 ) {//向下运动 Move( 0, 1 ); nFrame ++;

if( nFrame > 5 || nFrame < 4 ) nFrame = 4; setFrame( nFrame );

setTransform( TRANS_NONE );

}

else if( ( keyStates & GameCanvas.LEFT_PRESSED ) != 0 ) {//向左运动 Move( -1, 0 );

nFrame ++;

if( nFrame > 3 || nFrame < 2 ) nFrame = 2;

setFrame( nFrame );

setTransform( TRANS_MIRROR ); }

}

//移动MM,参数nX、nY分别是移动的X、Y距离 private void Move( int nX, int nY ){ m_nLastMoveX = nX;

m_nLastMoveY = nY;

setRefPixelPosition( getRefPixelX() + nX, getRefPixelY() + nY ); }

//使MM向后退 public void MoveBack(){

Move( -m_nLastMoveX, -m_nLastMoveY ); m_nLastMoveX = 0; m_nLastMoveY = 0; } }

package mmrpg; --界面布局

import java.io.IOException; import java.util.Random;

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

import javax.microedition.lcdui.game.GameCanvas; import javax.microedition.lcdui.game.LayerManager;

public class MainCanvas extends GameCanvas implements Runnable{ public static final int GAME_UI = 0; //进入用户界面 public static final int GAME_GAMING = 1; //进行游戏 public static final int GAME_END public static final int GAME_STATE_NUM private int m_nState 态

= 2; //游戏结束 = 3; //状态总数

//存储当前的游戏状

= GAME_UI;

private boolean

m_bRunning;

//控制线程运行 //界面对象

//层管理器对象 //MM对象 //NPC对象

private MyUI m_UI;

private LayerManager m_Manager; private Actor m_Actor; private Npc m_Npc;

private Scene m_Scene;

private Random m_Random; public MainCanvas( ){ super(true);

//场景对象 //随机数对象

try{

//创建用户界面,并设置界面中的按钮 MyButton button = new MyButton(); m_UI = new MyUI(button); }

catch(Exception exception){exception.printStackTrace();} setState(GAME_UI); Start();

}

//重新开牌

private void Reset(){

//创建随机数对象

if( m_Random == null )

{ m_Random = new Random();}

if( m_Actor == null ){ try{

//读取MM及NPC的精灵图像

Image image = Image.createImage(\"/MM.png\"); m_Actor = new Actor( image, 16, 32 );

m_Actor.defineCollisionRectangle( 0, 16, 16, 16 ); m_Actor.defineReferencePixel( 8, 24 ); image = Image.createImage(\"/NPC.png\"); m_Npc = new Npc( image, 16, 32 );

m_Npc.defineCollisionRectangle( 0, 16, 16, 16 ); m_Npc.defineReferencePixel( 8, 24 ); //创建场景

m_Scene = new Scene(); //创建层管理器

m_Manager = new LayerManager(); }

catch (IOException e){ e.printStackTrace();} }

m_Manager.append( m_Actor );

m_Manager.append( m_Npc );

m_Scene.AppendToManager( m_Manager ); m_Scene.EnterScene( 0, m_Actor, m_Npc ); //设置可视区域

SetViewWindow(); }

//设置可视区域

private void SetViewWindow(){

int nX = m_Actor.getRefPixelX() - getWidth()/2; int nY = m_Actor.getRefPixelY() - getHeight()/2; if( nX < 0 )

nX = 0;

else if( nX > m_Scene.GetWidth() - getWidth() ) nX = m_Scene.GetWidth() - getWidth(); if( nY < 0 )

nY = 0;

else if( nY > m_Scene.GetHeight() - getHeight() ) nY = m_Scene.GetHeight() - getHeight();

m_Manager.setViewWindow( nX, nY, getWidth(), getHeight() ); }

private void setState( int state ){

//设置游戏状态

if( state < 0 || state >= GAME_STATE_NUM ) return;

m_nState = state; switch( m_nState ){ case GAME_UI: 界面

m_UI.setState(MyUI.UI_TITLE); 界面

break;

case GAME_GAMING: m_UI.setState(MyUI.UI_HIDE); break; case GAME_END: break; } }

public void Start(){

m_bRunning = true;

Thread thread = new Thread(this); //分配新线程 thread.start(); //线程启动

//进入用户//显示标题

//正在游戏

//游戏结束

m_UI.setState(MyUI.UI_HIDE);

}

public void run() {

//得到系统当前时间,并将时间换算成毫秒 long T1 = System.currentTimeMillis(); long T2 = T1; while(m_bRunning){

T2 = System.currentTimeMillis(); if( T2 - T1 > 100 ){ //间隔100毫秒 T1 = T2; Input(); Logic(); Paint();

} } }

public void Stop(){

m_bRunning = false; }

public void Input(){

int keyStates = getKeyStates(); try{

switch( m_nState ){ case GAME_UI: {

switch( m_UI.Input( keyStates ) ){ case MyButton.BUTTON_START: //按下开始键 Reset();

setState(GAME_GAMING);

break;

case MyButton.BUTTON_EXIT: 按下退出键

MMRpgMidlet.midlet.notifyDestroyed(); break; } }

break;

case GAME_GAMING:

//游戏中

//

if( !m_Npc.m_bDialog )

m_Actor.Input( keyStates );

if( m_Scene.m_nCurIndex == 0 &&

m_Actor.getRefPixelX() > 250 &&

m_Actor.getRefPixelY() > 250 ){ setState(GAME_END); return; }

CheckCollisions(); SetViewWindow(); break;

case GAME_END:

if( ( keyStates & GameCanvas.FIRE_PRESSED ) != 0 ){ Reset();

setState(GAME_GAMING); } break; }

}catch(Exception e){e.printStackTrace();}

}

public void Logic(){

switch( m_nState ){ case GAME_GAMING: m_Npc.Logic(); break; } }

public void Paint(){

Graphics g = getGraphics(); //清屏

g.setColor(0);

g.fillRect( 0, 0, getWidth(), getHeight() );

g.setColor(0xFFFF0000); switch( m_nState ){ case GAME_UI:

//显示界面

m_UI.Paint(g, getWidth(), getHeight()); break;

case GAME_GAMING:

//显示游戏画面

m_Manager.paint( g, 0, 0 ); if( m_Npc.m_bDialog )

m_Npc.DrawText( g, getWidth(), getHeight() ); break; case GAME_END:

m_Manager.paint( g, 0, 0 );

g.setColor( 0xffffff );

g.drawString( \"MM终于走出了洞穴!\ getHeight() / Graphics.TOP|Graphics.HCENTER ); break; }

flushGraphics(); }

//碰撞检测

public void CheckCollisions(){

if( m_Actor.collidesWith( m_Npc, false ) ){ m_Actor.MoveBack(); m_Npc.DialogStart(); return; }

m_Scene.CollidesWidth( m_Actor, m_Npc ); } }

package mmrpg; --主应用程序

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

import javax.microedition.midlet.MIDletStateChangeException;

public class MMRpgMidlet extends MIDlet { public static MMRpgMidlet midlet;

private static MainCanvas m_MainCanvas; //定义MainCanvas的引用 public MMRpgMidlet() {

super(); //初始化,继承MIDlet类的构造 midlet = this;

}

protected void startApp() throws MIDletStateChangeException { //程序开始运行,为m_MainCanvas分配存储空间

try{

m_MainCanvas = new MainCanvas(); //分配存储空间

}

catch (Exception ex){ex.printStackTrace(); } 误处理

//设m_MainCanvas为屏幕的当前画布

Display.getDisplay(this).setCurrent(m_MainCanvas);

2,

//不做错

}

protected void pauseApp() {

//由被呼叫或其他原因使程序暂停 m_MainCanvas.Stop(); }

protected void destroyApp(boolean arg0)

throws MIDletStateChangeException { m_MainCanvas.Stop(); }

}

package mmrpg; --按钮控制

import javax.microedition.lcdui.Graphics;

import javax.microedition.lcdui.Image;

import javax.microedition.lcdui.game.GameCanvas; import javax.microedition.lcdui.game.Sprite;

public class MyButton {

//定义一组表示按钮类型值

public static final int BUTTON_START = 0; //开始按钮 public static final int BUTTON_EXIT = 1; //退出按钮

public static final int BUTTON_TYPE_NUM = 2; //按钮种类总数

private int m_nType 型

private Sprite

//构造方法

public MyButton(){

try{//创建按钮

Image img = Image.createImage(\"/button.png\"); m_ButtonSp = new Sprite(img, 41, 21); }

catch (Exception ex){ex.printStackTrace();} }

//处理按键的输入,返回选择的按键类型 public int Input(int keyStates){

if( ( keyStates & GameCanvas.UP_PRESSED ) != 0 ) {//选择上一个按钮

if( m_nType > 0 ) m_nType --; }

= BUTTON_START;

//当前选择的按钮类

m_ButtonSp; //按钮精灵图像

if( ( keyStates & GameCanvas.DOWN_PRESSED ) != 0 ) {//选择下一个按钮

if( m_nType < BUTTON_TYPE_NUM - 1 ) m_nType ++; }

if( ( keyStates & GameCanvas.FIRE_PRESSED ) != 0 ) {//按下当前选择的按钮 return m_nType; }

return -1; 何按钮

}

//显示按钮

public void Paint(Graphics g, int scrWidth, int scrHeight){ int h = m_ButtonSp.getHeight() + 2; int x = 15;

int y = 15;

for( int n = 0; n < BUTTON_TYPE_NUM; n ++ ) {

if( m_nType == n ) {//显示高亮的按钮

m_ButtonSp.setFrame(n); } else

{//显示灰色按钮

m_ButtonSp.setFrame(n + BUTTON_TYPE_NUM); }

m_ButtonSp.setPosition(x, y); m_ButtonSp.paint(g); y = y + h; } }

}

package mmrpg; --用户界面

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

public class MyUI {

//定义一组表示界面显示状态的数值

public static final int UI_TITLE = 0; //显示标题画面 public static final int UI_HIDE = 1; //隐藏界面 public static final int UI_STATE_NUM = 2; //界面状态总数

//返回-1表示未选择任

private int m_nState = UI_TITLE; //当前的界面状态

private Image m_TitleImg; //标题画面图像 private MyButton m_Button; //按钮对象

public MyUI( MyButton button ){

m_Button = button; try{ //读取标题图像

m_TitleImg = Image.createImage(\"/title.png\"); }

catch (Exception ex){ex.printStackTrace();} }

/*****

* 获取当前的界面状态 * @返回:当前界面状态 */

public int getState(){

return m_nState; }

/*****

* 设置当前的界面状态,并进行出错处理 * @参数 nType.........要设置的状态

*/

public void setState( int state ){

if( state < 0 || state >= UI_STATE_NUM ) return; m_nState = state; }

public MyButton getButton(){ return m_Button;

}

/*****

* 处理按键的输入

* @参数 keyStates.....当前的按键状态 * @返回所选按钮的类型 */

public int Input( int keyStates ){ int type = -1;

switch( m_nState ){ case UI_TITLE:

type = m_Button.Input(keyStates); break; case UI_HIDE: break;

}

return type; }

/*****

* 显示界面内容

* @参数 g.............对应显示屏幕 * @参数 scrWidth......屏幕的宽 * @参数 scrHeight.....屏幕的高 */

public void Paint( Graphics g, int scrWidth, int scrHeight ){ int x = scrWidth; int y = scrHeight; switch( m_nState ){ case UI_TITLE:

//显示标题画面

if( m_TitleImg != null ){

x = ( x - m_TitleImg.getWidth() ) / 2; y = ( y - m_TitleImg.getHeight() ) / 2; g.drawImage(m_TitleImg, x, y, 0 ); }

m_Button.Paint(g, scrWidth, scrHeight); break; case UI_HIDE: break; } }

}

package mmrpg; --NPC设置 对话

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

import javax.microedition.lcdui.game.Sprite;

public class Npc extends Sprite{

public boolean m_bDialog = false; private String m_strText = null;

//隐藏界面

//是否正在对话 //对话的文字 //对话开始的时间

private long m_nDialogStartTime = 0;

Npc(Image image, int frameWidth, int frameHeight){ super(image, frameWidth, frameHeight); }

//设置对话的文字

public void SetText( String strText ){ m_strText = null;

m_strText = new String(strText);

}

//开启对话

public void DialogStart(){

m_nDialogStartTime = System.currentTimeMillis(); m_bDialog = true; }

//逻辑操作

public void Logic(){

if( !m_bDialog ) return;

long lTime = System.currentTimeMillis(); if( lTime - m_nDialogStartTime > 3000 ) m_bDialog = false; }

//显示对话文字

public void DrawText( Graphics g, int nWidth, int nHeight ) {

if( !m_bDialog ) return; g.setColor( 0 );

g.fillRect( 0, nHeight - 30, nWidth, 30 ); g.setColor( 0xffffff );

g.drawRect( 0, nHeight - 30, nWidth - 1, 29 ); g.drawString( m_strText, 10, nHeight - 25,

Graphics.TOP|Graphics.LEFT); } }

package mmrpg; 事件管理

import java.io.IOException; import java.io.InputStream;

import javax.microedition.lcdui.Image;

import javax.microedition.lcdui.game.LayerManager; import javax.microedition.lcdui.game.TiledLayer;

public class Scene {

public int m_nCurIndex;

private TiledLayer m_LyPass; private TiledLayer m_LyNotPass; private TiledLayer m_LyJump; Scene( ){ try{

//可通过的区域 //不可通过的区域

//跳转场景的区域

//读取tile图像

Image image = Image.createImage(\"/map.png\"); m_LyPass = new TiledLayer( 10, 10, image, 32, 32 ); m_LyNotPass = new TiledLayer( 10, 10, image, 32, 32 ); m_LyJump = new TiledLayer( 10, 10, image, 32, 32 );

}catch (IOException e){e.printStackTrace();} }

//将各图层加入到层管理器

public void AppendToManager( LayerManager mManager ){ mManager.append( m_LyPass ); mManager.append( m_LyNotPass ); mManager.append( m_LyJump ); }

//进入指定场景

//nIndex是场景的编号,mActor、nNpc分别是MM和NPC对象 public void EnterScene( int nIndex, Actor mActor, Npc mNpc ){ m_nCurIndex = nIndex; InputStream is = null;

//根据场景,设置MM和NPC的位置及图像 switch( nIndex ) { case 0:

is = getClass().getResourceAsStream(\"/map0.txt\"); mActor.setRefPixelPosition( 150, 150 ); mNpc.setFrame( 0 );

mNpc.SetText( \"洞穴上层有个人知道出口!\" );

mNpc.setRefPixelPosition( 130, 120 );

break; default:

is = getClass().getResourceAsStream(\"/map1.txt\");

mActor.setRefPixelPosition( 200, 160 ); mNpc.setFrame( 1 );

mNpc.SetText( \"洞穴出口在下层的右下角。\" ); mNpc.setRefPixelPosition( 150, 50 );

break; }

//读取场景 LoadScene( is ); }

//获取场景的宽度 public int GetWidth(){

return m_LyPass.getWidth(); }

//获取场景的高度

public int GetHeight(){

return m_LyPass.getHeight(); }

//检测MM和场景及NPC的碰撞

public void CollidesWidth( Actor mActor, Npc mNpc ){ if( mActor.collidesWith( m_LyJump, false ) ) {

mActor.MoveBack(); if( m_nCurIndex == 0 )

EnterScene( 1, mActor, mNpc ); else

EnterScene( 0, mActor, mNpc ); }

else if( mActor.collidesWith( m_LyNotPass, false ) ) {

mActor.MoveBack(); } }

//读取场景文件

private void LoadScene( InputStream is ){ try{

int ch = -1;

for( int nRow = 0; nRow < 10; nRow ++ ) {

for( int nCol = 0; nCol < 10; nCol ++ ) {

ch = -1;

while( ( ch < 0 || ch > 7 ) ) {

ch = is.read(); if( ch == -1 ) return; ch = ch - '0'; }

if( ch == 4 || ch == 5 ) {//不可通过的区域

m_LyPass.setCell( nCol, nRow, 0 ); m_LyNotPass.setCell( nCol, nRow, ch );

m_LyJump.setCell( nCol, nRow, 0 ); }

else if( ch == 6 || ch == 7 ) {//跳转场景的区域

m_LyPass.setCell( nCol, nRow, 0 );

m_LyNotPass.setCell( nCol, nRow, 0 );

m_LyJump.setCell( nCol, nRow, ch ); } else

{//可通过的区域

m_LyPass.setCell( nCol, nRow, ch ); m_LyNotPass.setCell( nCol, nRow, 0 );

} }

m_LyJump.setCell( nCol, nRow, 0 ); } } } }

catch (IOException e){e.printStackTrace();}

因篇幅问题不能全部显示,请点此查看更多更全内容