java毕业设计——基于java+J2ME的堡垒游戏设计与实现(毕业论文+程序源码)——堡垒游戏

基于java+J2ME的堡垒游戏设计与实现(毕业论文+程序源码)

大家好,今天给大家介绍基于java+J2ME的堡垒游戏设计与实现,文章末尾附有本毕业设计的论文和源码下载地址哦。需要下载开题报告PPT模板及论文答辩PPT模板等的小伙伴,可以进入我的博客主页查看左侧最下面栏目中的自助下载方法哦

文章目录:

1、项目简介

  1. 该堡垒游戏是基于J2ME开发的手机RPG游戏,采用midp2.0技术实现了菜单、地图、主角动作及怪物动作和AI等,主要通过精灵间的碰撞检测来触动事件发生。游戏的主流程是玩家利用手机键盘操作主角在堡垒中拾取道具破解迷宫,并且随着关数的增加,游戏的难度也逐渐增加。另外,游戏中还包括了排行榜,声音设置,帮助等各种附加功能。其中充满了趣味性和刺激性,是适合各年龄段的益智冒险类游戏。
  2. 本论文介绍了J2ME的相关技术及该堡垒游戏程序的结构分析和具体功能的实现。


2、资源详情

项目难度:中等难度
适用场景:相关题目的毕业设计
配套论文字数:9848个字26页
包含内容:整套源码+完整毕业论文+答辩PPT


3、关键词

J2ME; 手机游戏; 堡垒

4、毕设简介

提示:以下为毕业论文的简略介绍,项目源码及完整毕业论文下载地址见文末。

引 言
省略

2 手机游戏的现状和J2ME的概况
2.1软件现状
省略

2.2 J2ME概况
2.2.1 J2ME的由来
Java的最大目标和特点,就是“一次编写,到处运行”的平台无关性。但是,一套标准无法适应各种不同的需求。因此,Java技术目前共有三套,分别针对不同的平台和应用。
省略

2.2.2 J2ME的3层体系结构及MIDP简介
J2ME的3层体系结构依照各种设备的资源特性,将J2ME技术构架分为简表(Profile)、配置(Configuration)和Java Virtual Machine(JVM)3层,然后再进一步细分,这使J2ME能够在每一类设备的限制下工作,而同时提供最低限度的Java语言功能性。

关于J2ME的体系结构,可以这样来进行总结:Configuration的分类是根据计算能力的不同来划分的,同类设备的计算能力相近。Configuration是一个规范,定义了这类设备的共同Java平台,定义与设备无关的Java虚拟机和核心库,是平台相容性的基础。Profile的分类是根据设备功能划分的,同类功能的设备其他各种硬件条件和需求也相近。Profile是一组API,在某Configuration的基础上扩展了针对设备特定功能的API,使得标准能够完全适应特殊的设备,彻底发挥设备的功能。

J2ME体系的一般结构是:由Configuration定义的Java虚拟机运行于设备的宿主操作系统之上,构成整个平台的基础。Configuration提供了基本的语言特性,Profile提供针对设备的特殊功能API和扩展类库。应用程序的运行环境需要一个Configuration和至少一个Profile,多个Profile可以共存,也可以叠加。

省略

2.2.3 Configuration和Profiles
省略

2.3 J2ME现状和前景
省略

2.4 手机游戏业务
手机游戏是移动多媒体时代最有价值的应用。这是因为,游戏是多媒体应用中集大成的业务,图像、音乐、互动都能在游戏中实现,能充分满足用户各方面的需求。

虽然目前手机游戏还无法与PC游戏相比,其显示功能和键盘输入、声音处理能力也形成一定制约。但是随时随地可操作可联网的特性大大拓展了人们娱乐休闲的时间和空间,以游戏功能为主的手机终端在市场上渐被认可,多媒体功能正向手机的标配功能演进,制约手机游戏发展的技术瓶颈将被打破。当前的手机游戏产业尽管仍然存在很多制约其发展的瓶颈,但手机游戏已显示出非比寻常的发展速度,其市场潜力十分巨大,将成为移动增值服务市场新的增长点。

3 开发环境介绍
3.1开发环境
操作系统:Microsoft Windows
程序语言:Java
开发平台:JavaMicro Edition
开发工具: Wireless Tool Kit + UltraEdit

3.2 关于SonyEricsson Wireless Tool Kit
省略

4手机游戏(堡垒)的开发
4.1 游戏的的思路、构想
4.1.1 游戏想法的产生
相信大家一定都在8位机机上玩过《冒险岛》这款游戏,非常有趣味性。

游戏中玩家通过不断的闯关,来解救公主。在每个关都很很多的怪物阻挡着你,所以需要运用各种机关或者秘籍来杀死它们。杀死他们的同时还可以获得各种奖励,加生命,加血等,增加了游戏的趣味性。

如图2所示:
在这里插入图片描述

图2 游戏截图
这款《冒险岛》游戏的实现相对于其他RPG或者网络版手机游戏稍简单一些,适合初学者作为练习,所以我决定编写一款类似的手机游戏。

由于之前对手机游戏的编程知识以及游戏的设计只有初步的了解,因此,我们在游戏的构架和思路上经历了几个阶段。

4.1.2 对游戏设计的初步认识
刚开始我们只对J2ME有初步的了解。这时我们只是模仿之前在PC上看到的游戏,用语言把游戏的实现感性的描述为几大部分:
游戏界面系统:包括游戏开始界面;游戏开局界面;游戏运行界面;游戏结束界面。
游戏元素:菜单类;画布类;人物类;排行榜类。

4.1.3 模块成型阶段
在进一步熟悉了J2ME知识后,对框架做出了一些修改,逐步把游戏的基本功能确定。游戏依次进入加载界面;主菜单;游戏运行界面;游戏结束界面。

具体实现的功能为:
1.主菜单,有如下选项:
(1)开始游戏——进入游戏界面。
(2)声音——设置声音的有无选项。
(3)帮助——介绍游戏的玩法。
(4)排行榜——玩家所得分数的排行榜。
(5)关于——用来显示说明信息以及背景图片。
2.游戏运行界面,包括:
游戏界面;目前游戏得分;游戏关数;生命次数;
3.游戏结束界面:游戏结束后,显示一行说明信息,然后退回到菜单。

游戏的主要模块为:
1.游戏主MIDlet(GameMIDlet)——对游戏生命周期的判断;对画布类的调用;管理游戏程序中各个屏幕之间的转换。
2.游戏画布(MyGame)——对游戏所用变量,常量的设定;游戏的初始化;游戏中精灵运动轨迹的控制;精灵与砖块的碰撞检测以及砖块状态的控制;游戏中各关卡的基本设定;游戏中对按键状态的处理。
3.菜单类——游戏中菜单事件的处理。
4.GameOgre类——游戏中怪物的类。
5.GamePlayer类——玩家控制的精灵类。
6.GameRMS类——用于实现分数排行榜。
7.PlayMusic类——用于实现音乐的播放。
8.MySet类——声音大小的设置。

4.2 程序的类结构
程序一共有8个主要类,其中菜单类负责各个屏幕的切换。程序的类结构如图3所示:

在这里插入图片描述

图3 类结构

4.3 游戏的流程图
进入游戏菜单。初始情况下,游戏菜单有5个选项,它们分别是开始游戏、游戏说明和排行榜、设置、关于。选择开始新游戏则进入游戏,在游戏中如果按下非游戏键则中断游戏返回菜单,此时菜单中增加了一个继续游戏的选项,可以返回游戏也可以重新开始新的游戏。在菜单中选择游戏说明或者高分记录,则进入相应的屏幕,他们都能用“后退”软键返回菜单。菜单中的退出选项用于退出程序。

4.4 游戏的实现
游戏一共实现了几个类,包括用于游戏外部的、菜单类、排行榜屏幕类、声音设置屏幕类、结束屏幕类,以及用于游戏本身的游戏画布类、声音效果类。

4.4.1 主类GameMIDlet的实现
MIDlet是最核心的类。MIDlet程序有三种状态:
1.暂停状态
2.运行状态
3.销毁状态
J2ME程序都是从MIDlet类开始执行,系统在执行MIDlet程序时,首先构造一个MIDlet类型的对象,然后使程序进入到暂停状态,按照生命周期的规定,系统会自动调用MIDlet对象的startApp方法使程序进入到运行状态,开始程序的执行。

下图是运行时显示的画布对象:
在这里插入图片描述

图5 屏幕之间的切换
首先,先要创建MIDlet类型的对象,下面我们来看对象的构造方法:

//主程序构造方法
        public GameMIDlet()
        {
        		rs = null;
        		RecordName = “GameRMS”;
        		GameMenu.display = Display.getDisplay(this) ;
        		GameMenu.midlet = this;
        }

在这个构造器中,创建了一个Display对象用于显示,然后,把当前程序的引用传给菜单类中的静态变量。

Display类有两个最主要的作用:
1、 获得屏幕的属性。例如屏幕是否是彩色的,以及支持的颜色数量等信息。
2、 控制屏幕的显示。例如使屏幕显示某个指定界面或者获得当前的显示界面等。
其中,特别是第二个作用使用的更加频繁。

当程序启动的时候,则调用了程序的startApp方法,用来显示画面:

   public void startApp()
        {
        	//程序开始,打开数据库,如果数据库没有数据就添加10笔空白数据,最后关闭数据库
        	try {
				rs = RecordStore.openRecordStore(RecordName,true);
			} catch (Exception e) 
			{
				System.out.println(“创建数据库失败”);
			}
			GameRMS rd = new GameRMS(“player”,0);
			byte tem[] = rd.encode();
			try 
			{
				if(rs.getNumRecords()==0)
				{	
					for(int i=1;i<=11;i++)
					   	  {
						   	  try
							  {
							  rs.addRecord(tem,0,tem.length);
							  }catch(Exception e)
							  {
							  	System.out.println(“添加数据失败”); 
							  }
				   	      }
				}	
			} 
			catch (Exception e1) 
			{
				System.out.println(“得到数据库大小失败”);
			}	   
				
			try
			{
			    rs.closeRecordStore();
			}catch(Exception e)
			{
			 	System.out.println(“关闭数据库失败”);
			}
        	   //将画面设为主画面MAIN SCREEN
			new Thread(this).start(); 
        }

程序开始,打开数据库,如果数据库没有数据就添加10笔空白数据,最后关闭数据库,然后开始一个新的线程,启动菜单。
MIDP中的存储系统是实际为一个类似于数据库的系统,而并不是简单的文件系统,这个系统称为记录管理系统(Record Management System,RMS)。RMS实现数据的持久性管理,提供了数据存储的功能,可以在程序下次启动是再次使用。

记录存储是面向记录的数据库,可把一个记录存储看作一个数据库文件,由许多记录组合而成,这些记录将持久保存并支持跨多个MIDlet的请求。在系统平台的整个常规应用期间,包括重启,更换电池等,MIDlet的记录存储都由系统平台负责维护,系统会尽可能维持记录的完整性。

当调用destroyApp 这个方法的时候,则退出程序。

public void destroyApp(boolean unconditional) 
{
        exit();
 }
public void exit() 
{
        System.gc();
        notifyDestroyed();
 }

退出程序的时候,要实行垃圾回收,释放掉不再使用的内存。
2.屏幕切换,如图6:
在这里插入图片描述

图6 屏幕切换
菜单的图形切换采用的是流程控制器,非常方便,简洁的实现了屏幕画面的切换,下面是关键实现代码:

//导航器
	//设置4个常量分别代表主画面,游戏画面,帮助画面和排行榜画面
	final public static int MY_MENU = 1;
	final public static int MY_GAME = 2;
	final public static int MY_HELP = 3;
	final public static int MY_RMS = 4;
	final public static int MY_ABOUT = 5;
	final public static int MY_SET = 6;
采用静态变量来对画面进行标识。
//流程执行,获得需要画面的对象,并显示在屏幕上
	public static void show()
	{
		switch(current)
		{
			case MY_MENU:
				display.setCurrent(MyMenu.getInstance());
				break;
			case MY_GAME:
				display.setCurrent(MyGame.getInstance());
				break;
			case MY_SET:
				display.setCurrent(MySet.getInstance());
				break;
			case MY_HELP:
				display.setCurrent(MyHelp.getInstance());
				break;
			case MY_RMS:
				display.setCurrent(MyRms.getInstance());
				break;
			case MY_ABOUT:
				display.setCurrent(MyAbout.getInstance());
				break;
		}
	}

这样,采用上面这个函数,非常方便的实现了流程的转换。实现屏幕的切换。

4.4.2 游戏画布MyGame类的实现
在J2ME游戏编程中,Canvas类是最常用的类之一,该类提供了获得手机屏幕属性、绘制界面以及事件处理等很多实用的功能。
Canvas类是Displayable的子类,主要用来需要处理低级事件,例如键盘按键事件等,以及需要绘制屏幕的程序。在实际的使用过程,一般都通过继承Canvas来利用该类提供的功能。Canvas类是一个抽象类,继承该类的时候必须覆盖paint方法。
GameCanvas 类提供了基本的游戏用户接口。除了从Canvas 继承下来的特性(命令,输入事件等)以外,它还提供了专门针对游戏的功能,比如后备屏幕缓冲和键盘状态查询的能力。这也是GameCanvas与Canvas相比所具有的两个优点.来看游戏画面:
当流程控制器转到游戏运行界面时,则用到了游戏画布MyGame类。

下面是游戏截图:
在这里插入图片描述

图7 游戏截图
下面来看类的声明:

public class MyGame extends GameCanvas implements Runnable
{
}
我们所用的画布程序,正是继承了GameCanvas这个类,同时派生了Runnable接口,来实现生成一个新的线程的功能。
程序的run方法:
public void run() 
	{
		long st = 0;
        long et = 0;
        Graphics g = getGraphics();
        for(stage = 2;stage <= 4;stage++)
        {
        	flag = true;
        	g.setColor(0,0,0);
        	g.fillRect(0,0,getWidth(),getHeight());
        	g.setColor(255,255,0);        	g.setFont(Font.getFont(Font.FACE_PROPORTIONAL,Font.STYLE_BOLD,Font.SIZE_LARGE));
g.drawString(“第 ” + (stage -1)+ “ 关”,getWidth()/2-30,getHeight()/2-10,Graphics.TOP|Graphics.LEFT);
        	flushGraphics();		
        	try { Thread.sleep(1000);} 
catch (InterruptedException e1) {}
			CREAT_STAGE();   //	调用创建关卡的方法
        	try {Thread.sleep(500);} 
        	catch (InterruptedException e1) {}
			mpaint(g);
			isKey = true;
	        while(flag)   //游戏正式开始
	        {
	        	while(ispause)  //判断是否按下暂停
	        	{
	        		try{ Thread.sleep(100); }
	        		catch(Exception e){}
	        	}
	            st = System.currentTimeMillis();
	            StartGameTime = System.currentTimeMillis();
	       	            INPUT_KEY();       //调用按键方法

	   	            PENG_ZHUANG();    //调用各种判断和行动的方法
	   	    	movMing();    //调用刷新画面的方法
	            mpaint(g);
	            et = System.currentTimeMillis();
	            if((et-st)<rest)
	            {
                try { Thread.sleep(rest-(et-st)); }
catch(Exception e){}
	            }}
	        if(isEndGame)      //判断是否输掉游戏
	        {
		        if(islose)
		        {
		        	EedGameTime = System.currentTimeMillis();
		        	g.setColor(0,0,0);
		        	g.fillRect(0,0,getWidth(),getHeight());
		        	g.setColor(255,255,0);		        	g.setFont(Font.getFont(Font.FACE_PROPORTIONAL,Font.STYLE_PLAIN,Font.SIZE_LARGE));
		        	g.drawString(“你失败了!”,getWidth()/2-40,getHeight()/2-20,Graphics.TOP|Graphics.LEFT);
		        	flushGraphics();
		        	try { Thread.sleep(3000); }
catch(Exception e){}
//	                init_Game();
	                break;
		        }}} 
        if(isEndGame)      //判断是否赢得游戏
        {
	        if(!islose)
	        {
	        	EedGameTime = System.currentTimeMillis();
	        	g.setColor(0,0,0);
	        	g.fillRect(0,0,getWidth(),getHeight());
	        	g.setColor(255,255,0);
	g.setFont(Font.getFont(Font.FACE_PROPORTIONAL,Font.STYLE_PLAIN,Font.SIZE_LARGE));
	        	g.drawString(“你胜利了!”,getWidth()/2-40,getHeight()/2-20,Graphics.TOP|Graphics.LEFT);
	        	flushGraphics();
	        	try {Thread.sleep(3000); }
catch(Exception e){}
//	            init_Game();
	        } 
//	        GetScore();
	        if (score > 0)
	        {
		        GameName in = new GameName();
		        GameMenu.display.setCurrent(in);
		        in.start();
	        }
	        else
	        {
		        GameMenu.current = GameMenu.MY_MENU;
		        GameMenu.show();
	        }} } }

在线程中,通过
1、调用创建关卡的方法CREAT_STAGE();
2、判断是否按下暂停while(ispause)
3、调用按键方法INPUT_KEY();
4、调用各种判断和行动的方法PENG_ZHUANG();
5、调用刷新画面的方法movMing();
6、判断是否输掉游戏if(isEndGame)
7、判断是否赢得游戏if(isEndGame)
来对游戏进行不断监控。

4.4.3 玩家精灵GamePlayer类的实现
Sprite类是继承自Layer的用于存储多帧的基本可视元素。不同的frame可交相显示,构成动态的效果。图片可翻转、颠倒、由一个主角图片就可以方便的得到所有方向的显示状态,相比原先只能使用Canvas绘图,需要将所有方向的主角图像都绘制在png图像中简化了许多。Sprite也可以从整合的图像中读图,读图时将把大图分解为若干等宽等高的小图。每个小图按照其排列顺序有相应的序号,在程序中调用其序号,就可以绘制出相应的图片。本程序中的玩家、怪物都由Sprite继承得到。在有些情况下,控制主角的翻转,尤其是多幅图片配合显示的过程,如果将多图的共享定位点设置在通常的左上角,将很不容易控制,因为许多翻转都是以其他点为参考电的(比如,中心点)。由此,引入参考点的概念。参考点由defineReferencePixel函数确定未翻转图片状态时的坐标。默认是(0,0)点,如果需要,可将参考点设置在画面边界之外。
在本程序中,由于J2ME中提供的Sprite类功能有限,所以我自己写了一个GamePlayer类来继承Sprite类,扩充了更多的功能。

public class GamePlayer extends Sprite
{
}
在游戏中和背景的碰撞检测始终是个难点,在本程序中是这样实现的:
public void isPeng(int x,int y,int Array[][],int N)
{
for(int i = 0; i < 20; i++)
{			
for(int j = 0; j< 18; j++)
	{			
		if(Array[i][j] == N)
		{	
			if (!MyGame.isU)
			{
				if( Length * j <= x + this.getWidth() /2 && Length *(j + 1) >= x + this.getWidth() /2  && 10 + Length * i <= y  && 10 + Length *(i + 1) >= y)
				{
					this.setPosition(this.getX(),  20 + Length *(i + 1));
						System.out.println(“UP:+getY());
				}
//左
				if( Length * j <= x + 1 && Length *(j + 1) >= x + 1 && 10 + Length * i <= y + this.getHeight()/2 && 10 + Length *(i + 1) >= y + this.getHeight()/2)
				{
					this.setPosition( Length * (j + 1),this.getY());
					}
					if( Length * j <=x + this.getWidth() - 1 && Length *(j + 1) >= x + this.getWidth()1 && 10 + Length * i <= y + this.getHeight()/2 && 10 + Length *(i + 1) >= y + this.getHeight()/2)
				{
				this.setPosition(Length * j - this.getWidth() ,this.getY());
}
				}
				//左下
			if( Length * j <= x + 3&& Length *(j + 1) >= x + 3 && 10 + Length * i <= y + this.getHeight() && 10 + Length *(i + 1) >= y + this.getHeight())
			{
				this.setPosition(this.getX(),  Length * (i -1));
}
			//右下
			if( Length * j <= x +this.getWidth() -3 && Length *(j + 1) >= x + this.getWidth() -3  && 10 + Length * i <= y + this.getHeight() && 10 + Length *(i + 1) >= y + this.getHeight())
			{
this.setPosition(this.getX(),  Length * (i - 1));
Length * i:+Length * (i-1));
			}
	
		}		
}		

通过查看背景数组和玩家坐标,来实现和背景的碰撞检测。

4.4.5 SoundEffects类的实现
声音效果是一个游戏中必不可少的部分,没有了生动的音乐效果,游戏的体验就会大打折扣。在我们的游戏中当然也不能没有声音。
在我们的游戏程序中的PlayMusic类就是游戏中的音效类。该类的主要功能为使用MIDP2.0 Media API播放游戏中的声音效果:背景音乐和游戏结束的提示音。
我们用private Player createPlayer(String filename, String f, int i) 创建播放器。该方法中的filename是要播放声音文件的相对路径,f是播放音乐文件的格式,i用来控制该音乐的播放次数。在播放某个声音之前我们都需要调用stop方法来中止声音(如果声音未播放则该方法无效)。游戏中的声音我们用的startPlayer方法来播放。在需要播放游戏中的声音时我们就调用该类中相应的方法。

5 程序设计过程中遇到的一些重要问题
5.1 关于碰撞的问题
在游戏中最先要解决的也是最重要的问题就是碰撞检测的实现以及碰撞后表现出的效果。在弹球游戏中碰撞检测分为俩种:精灵与精灵之间的碰撞检测以及精灵与方块图层之间的碰撞检测。

精灵与精灵之间的碰撞检测可以直接调用Sprite类中的collidesWith()方法或者自己重新Sprite类中的collidesWith()方法并调用来进行碰撞检测。在本游戏程序中我们使用的是后者。这点表现效果还是很不错的。

再者就是精灵与图层之间的碰撞检测即主角与砖块之间的碰撞检测。我们精灵中重写的collidesWith()方法来检测它们之间的碰撞检测,这个时候我们就存在一个怎么样判断与小球碰撞的是哪个砖块的问题。我所采用的是通过查看背景数组和玩家坐标,来实现和背景的碰撞检测,但是效果不是很理想。到目前在我们经过的多次测试中还没有出现判断失误以及无法判断等错误。可是,效果不理想,我还将继续探索更精更有效的算法。

5.2 关于游戏画面的显示问题
在后期测试中发现游戏在暂停后继续游戏时,游戏画面又恢复为游戏开始的画面,而不是暂停时的游戏画面,经过多次调试后发现问题在MyGameCanvas类。

在仔细阅读了相关的资料后发现线程的创建和运行是通过调用它本身的函数start()来调动run()函数开始运行的,当run ()方法执行完毕后,线程就结束了。一旦一个线程执行完毕,这个实例就不能再重新启动,只能重新生成一个新实例,再启动一个线程。鉴于此,我们决定在MyGameCanvas类的run()内设置一个暂停标志量pause。

这样就实现了游戏的暂停(挂起)功能。当继续游戏后,游戏画面就是我们暂停时的画面。

结 论
本程序设计实现了手机上以J2ME为平台的堡垒游戏的开发,具有一定的可玩性和复杂性。经过了细心的调试和排错解决了绝大部分的问题。

通过对“沙丘魔堡”这个手机游戏的构想,设计,代码的编写和调试,我进一步学习了J2ME这个平台,并对手机游戏编程有了新认识。就我所做的模块来说,我对J2ME中的菜单、声音、画布等技术有了更进一步的认识。一个简单的菜单的背后却有着不同的写法以及一些复杂的技术。我现在已经做出的是游戏的1.0版本,实现了游戏的基本功能,离一个完全意义上的手机游戏还有一段的距离:
1.游戏只在模拟器上运行,还没有经过真机调试;
2.游戏的选项界面没有经过任何效果美化;
3.能调节声音的大小及开关背景音乐。
这款游戏算是休闲类的一款小游戏,如果能继续完善游戏的菜单功能,增加游戏可玩性等,那这款游戏将会是一款比较具有人气的手机游戏。

参考文献
[1] 胡虚怀,杨志和,李焕.J2ME移动设备程序设计[M].北京:清华大学出版社,2005。
[2] 李振鹏,龚剑.J2ME手机游戏开发技术详解[M]. 北京:清华大学出版社,2006。
[3] 詹建飞.J2ME开发精解[M].北京:电子工业出版社,2006。
[4] 施铮.J2ME技术参考手册[M].北京:电子工业出版社,2004。
[5] 微型爪哇人.JAVA手机开发[M].北京:中国铁道出版社,2003。
[6] 闻怡洋.J2ME MIDP 1.0/2.0无线设备编程指南[M].北京:北京大学出版社,2004。

致 谢
省略


5、资源下载

本项目源码及完整论文如下,有需要的朋友可以点击进行下载。如果链接失效可点击下方卡片扫码自助下载。

序号毕业设计全套资源(点击下载)
本项目源码基于java+J2ME的堡垒游戏设计与实现(源码+文档)_java_J2ME_堡垒游戏.zip
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,下面是一个基于J2ME的简单贪吃蛇游戏,使用了Canvas类来绘制游戏界面和处理用户输入。这个游戏可以在支持J2ME平台的手机上或模拟器上运行。 ``` import javax.microedition.lcdui.Canvas; import javax.microedition.lcdui.Command; import javax.microedition.lcdui.CommandListener; import javax.microedition.lcdui.Display; import javax.microedition.lcdui.Displayable; import javax.microedition.lcdui.Font; import javax.microedition.lcdui.Graphics; import javax.microedition.lcdui.TextField; import javax.microedition.midlet.MIDlet; import javax.microedition.midlet.MIDletStateChangeException; public class SnakeGame extends MIDlet implements CommandListener { private Display display; private SnakeCanvas canvas; private Command startCommand, exitCommand; private boolean running; public SnakeGame() { display = Display.getDisplay(this); canvas = new SnakeCanvas(); startCommand = new Command("Start", Command.OK, 1); exitCommand = new Command("Exit", Command.EXIT, 1); canvas.addCommand(startCommand); canvas.addCommand(exitCommand); canvas.setCommandListener(this); running = false; } protected void startApp() throws MIDletStateChangeException { display.setCurrent(canvas); } protected void pauseApp() {} protected void destroyApp(boolean unconditional) throws MIDletStateChangeException {} public void commandAction(Command c, Displayable d) { if (c == startCommand) { canvas.startGame(); } else if (c == exitCommand) { try { destroyApp(false); notifyDestroyed(); } catch (MIDletStateChangeException e) { e.printStackTrace(); } } } private class SnakeCanvas extends Canvas implements Runnable { private static final int WIDTH = getWidth(); private static final int HEIGHT = getHeight(); private static final int BLOCK_SIZE = 10; private static final int GAME_WIDTH = WIDTH / BLOCK_SIZE; private static final int GAME_HEIGHT = HEIGHT / BLOCK_SIZE; private static final int MAX_SCORE = GAME_WIDTH * GAME_HEIGHT - 1; private int[] snakeX, snakeY; private int score; private int foodX, foodY; private int direction; private boolean gameOver; private boolean running; private Thread gameThread; public SnakeCanvas() { setFullScreenMode(true); snakeX = new int[MAX_SCORE]; snakeY = new int[MAX_SCORE]; score = 0; direction = 0; gameOver = false; running = false; gameThread = null; } public void startGame() { if (!running) { running = true; gameOver = false; score = 0; direction = 0; generateFood(); for (int i = 0; i < 3; i++) { snakeX[i] = GAME_WIDTH / 2 + i; snakeY[i] = GAME_HEIGHT / 2; } gameThread = new Thread(this); gameThread.start(); } } public void run() { while (running && score < MAX_SCORE && !gameOver) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } moveSnake(); checkCollision(); repaint(); } gameOver = true; running = false; gameThread = null; } public void paint(Graphics g) { g.setColor(0xFFFFFF); g.fillRect(0, 0, WIDTH, HEIGHT); g.setColor(0x000000); g.drawRect(0, 0, WIDTH, HEIGHT); g.drawString("Score: " + score, 0, 0, Graphics.TOP | Graphics.LEFT); if (gameOver) { g.drawString("Game Over", WIDTH / 2, HEIGHT / 2, Graphics.HCENTER | Graphics.BASELINE); } else { g.fillRect(foodX * BLOCK_SIZE, foodY * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE); for (int i = 0; i < score; i++) { g.fillRect(snakeX[i] * BLOCK_SIZE, snakeY[i] * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE); } } } protected void keyPressed(int keyCode) { switch (keyCode) { case KEY_LEFT: if (direction != 1) { direction = 3; } break; case KEY_RIGHT: if (direction != 3) { direction = 1; } break; case KEY_UP: if (direction != 2) { direction = 0; } break; case KEY_DOWN: if (direction != 0) { direction = 2; } break; } } private void generateFood() { boolean valid = false; while (!valid) { foodX = (int) Math.floor(Math.random() * GAME_WIDTH); foodY = (int) Math.floor(Math.random() * GAME_HEIGHT); valid = true; for (int i = 0; i < score; i++) { if (snakeX[i] == foodX && snakeY[i] == foodY) { valid = false; break; } } } } private void moveSnake() { int dx = 0, dy = 0; switch (direction) { case 0: dy = -1; break; case 1: dx = 1; break; case 2: dy = 1; break; case 3: dx = -1; break; } int newX = snakeX[0] + dx; int newY = snakeY[0] + dy; for (int i = score; i > 0; i--) { snakeX[i] = snakeX[i - 1]; snakeY[i] = snakeY[i - 1]; } snakeX[0] = newX; snakeY[0] = newY; if (newX == foodX && newY == foodY) { score++; generateFood(); } } private void checkCollision() { if (snakeX[0] < 0 || snakeX[0] >= GAME_WIDTH || snakeY[0] < 0 || snakeY[0] >= GAME_HEIGHT) { gameOver = true; } for (int i = 1; i < score; i++) { if (snakeX[i] == snakeX[0] && snakeY[i] == snakeY[0]) { gameOver = true; break; } } } } } ``` 这个游戏使用了Canvas类来绘制游戏界面和处理用户输入,其中SnakeCanvas类是一个继承自Canvas的内部类,它实现游戏逻辑和绘制游戏界面的方法。在SnakeCanvas的构造函数中,我们初始化了一些游戏变量,如蛇的长度、方向和位置,以及食物的位置。在startGame()方法中,我们通过启动一个新的线程来运行游戏逻辑。在run()方法中,我们处理蛇的移动、碰撞检测和界面重绘。 在SnakeCanvas类中,我们还重写了Canvas的keyPressed()方法来处理用户输入,根据用户输入的方向键来改变蛇的方向。在paint()方法中,我们绘制了游戏界面,包括蛇、食物和分数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

毕业设计方案专家

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值