摘 要
“超级玛丽”游戏是是任天堂情报开发本部开发的Family Computer横版卷轴动作游戏,它因操作简单、娱乐性强而广受欢迎。Java 的优势在于网络编程与多线程,但其作为一门全场景语言,依然提供了强大的GUI开发API。本论文利用Java的GUI界面设计与多线程,复原了“超级玛丽”游戏,设计使用软件开发周期的过程,从需求分析到概要设计,再到详细设计,使用Java的多线程技术实现了游戏中的人物类和各种物类,游戏的界面设计与事件处理通过awt与swing两种类库来实现,最终实现了通过操作一名叫做玛丽的人物角色对象进行一关又一关的闯关设置,救出了被酷霸王绑架的松花公主的游戏情节。
关键词:
面向对象;图形用户界面;超级玛丽;多线程
"Super Mary" game is a horizontal scroll action game developed by Nintendo Intelligence Development Headquarters, which is widely popular due to its simple operation and strong entertainment. Java's advantages lie in network programming and multithreading, but as a full scene language, it still provides a powerful GUI development API. This paper uses Java's GUI interface design and multithreading to restore the "Super Mary" game. The design uses the software development cycle process, from requirements analysis to summary design, to detailed design. It uses Java's multithreading technology to implement character classes and various object classes in the game. The game's interface design and event processing are implemented through two types of libraries, namely, awt and swing, Finally, it realized the game scenario of saving Princess Songhua who was kidnapped by the Cool Overlord by manipulating a character named Mary to set levels after levels.
Key words:
object-oriented;graphical user interface;Super Marie;multithreading
摘 要
Abstract
第1章 绪 论
1.1 背景
1.2 国内外现状
1.3 系统研究内容
1.3.1 JavaGUI设计
1.3.2 Java面向对象程序设计
1.3.3 Java多线程设计
1.4 开发平台及工具介绍
1.5 可行性的分析
1.5.1 技术可行性
1.5.2 经济可行性
第2章 需求分析
2.1 非功能需求分析
2.2 功能需求分析
2.2.1 操作逻辑需求分析
2.2.2 界面设计需求分析
第3章 系统概要设计
3.1 系统模块设计
3.2 系统流程设计
3.3 Java类设计
3.3.1 窗体类
3.3.2 初始化类
3.3.3 背景类
3.3.4 元素抽象类
3.3.5 玛丽类
3.3.6 障碍物类
3.3.7 敌人类
3.3.8 背景音乐类
3.3.9 类与接口关系
第4章 系统详细设计
4.1 设计目标
4.2 系统类设计
4.2.1 窗体类
4.2.2 初始化类
4.2.3 背景类
4.2.4 元素抽象类
4.2.5 玛丽类
4.2.6 障碍物类
4.2.7 敌人类
4.2.8 背景音乐类
第5章 系统的实现
5.1 游戏开发所需要的图片
5.2 游戏设计的界面
5.2.1 游戏关卡一展示
5.2.2 游戏关卡二展示
5.2.3 游戏关卡三展示
5.3 游戏内容逻辑展示
5.3.1 游戏通过方式
5.3.2 游戏失败方式
5.3.3 游戏操作方式
第6章 系统测试
6.1 测试意义
6.2 测试过程
6.3 测试结果
总结与展望
1 总结
2 设计中的不足之处
原创性声明
参考文献
致 谢
第1章 绪 论
1.1 背景
谈及Java,会发现其主要优势在于网络编程和多线程,殊不知Java 语言是一门强大的计算机编程语言,以“万物为对象”为理念。由20来年的发展提供了各种强大的功能。因此完成计算机游戏开发也不在话下。
《超级玛丽》是一款超级玛丽全明星的同人作品,是一款经典的像素冒险过关游戏。在游戏中,玩家将操纵一名叫做玛丽的水管工(如果是双人模式,则另一位玩家操作玛丽的弟弟路易吉)跋山涉水、闯过一关又一关,最终救出被酷霸王绑架的桃花公主。游戏的故事简单而有趣。玛丽跳跃着前进,可以吃蘑菇让自己长大、可以踩死“乌龟”得分、可以用火球将爬行的乌龟打进沟里。玩家每一关的任务便是走到画面的尽头打倒BOSS酷霸王老怪、营救公主。这是历史上第一款横向卷轴游戏。它仅仅32KB的程序和8KB的图像数据,却保持着历史上销量最大游戏的纪录。
1.2 国内外现状
随着技术的发展,电子游戏已经成为一种新型娱乐,外国市场的电子游戏产业也在快速发展。电子游戏产业的发展在国外市场受到越来越多的关注,电子游戏的发展也在快速增长。外国市场的电子游戏产业最先发展到一定规模,具有更大的历史底蕴。
中国的电子游戏始于20世纪90年代。由于中国用户规模规模庞大,中国电子游戏市场也开始形成。步入21世纪中国电子游戏进入了高速发展阶段,投资回报率高,投资周期短,市场空间巨大,吸引了大量资本和人才。同时,电子游戏行业的快速发展吸引了政府的注意。其后在政府扶植下电子游戏产业迅速膨胀。从2011年开始,随着移动互联网技术的兴起和智能终端的普及,网络游戏和移动游戏的运营收入开始呈现爆炸性增长。2016年,随着以英雄联盟为代表的MOBA游戏的兴起,网络游戏开始衰落,但移动游戏仍保持快速增长。到2020年,移动游戏取代在线游戏成为游戏行业的主要增长点。
近年来,外国市场游戏产业的规模呈现出强劲的发展趋势。例如美国是呈现出主机游戏、移动游戏和PC游戏的三重模式。根据Newzoo的数据,2019年,美国游戏的销售收入排名世界第一;2020年,由于疫情影响,中国才成为世界第一大游戏业国家。
自主游戏是由个人或小团队独立开发的游戏,通常不受大型游戏公司的控制。在外国,自主游戏研究已经成为一个相对成熟的领域。以下是国外自主游戏研究的一些当前情况:
研究机构:有许多外国机构致力于研究和推广自主游戏。研究内容:自主游戏研究的内容涵盖了游戏设计、文化传承、社会议题等多个方面。研究结果:自主游戏在国外得到广泛认可,并产生了一些优秀的作品。研究趋势:随着技术和市场的不断变化,自主游戏也在不断发展和创新。未来,自主游戏可能会更加关注社交互动和虚拟现实等应用。
自主游戏在国外形成了一个相对完整的研究体系,其创新和多样性也得到了广泛认可。未来,随着技术和市场的不断变化,自主游戏将继续发挥其独特的魅力,促进游戏行业的进步。相信在未来,国内自主游戏也可以得到更好的发展,以超级玛丽为起点,并继续为此添砖加瓦。
1.3 系统研究内容
1.3.1 JavaGUI设计
GUI的全名是Graphical User Interface图形用户界面。当软件作为图形界面运行时,用户可以使用菜单、按钮、标签等组件以及鼠标和键盘等操作共同完成软件应用程序。在Java中,有两个类库可以实现图形用户界面。Java.awt和javax.swing这两个库都可以实现GUI设计界面设计和事件处理。这是两个主要部分。Javax.swing是Java基类库JFC(Java基类)的一个组件,它提供了一组比Java.awt强大、数量更多、更美观的图形用户界面组件。使用Swing组件的程序在Mac、Windows或Unix平台上具有相同的外观。通过swing组件实现人机的互动,创建游戏窗口和内容。
1.3.2 Java面向对象程序设计
面向对象程序设计(Object Oriented Programming,OOP)是一种计算机编程架构。类是Java程序中基本的结构单位,对象是类的一个实例,这恰恰是OOP的核心概念。通过对用户操控的超级玛丽、敌人、障碍物等等抽象成类,再实例化为对象,达到了游戏系统代码的三个主要目标:重用性、灵活性和扩展性。
1.3.3 Java多线程设计
多线程(Multithreading),是指实现多个线程并发执行的技术。本系统希望程序中实现障碍物,敌人,超级玛丽多线程代码交替运行的效果,。Java为此通过了线程两种方式创建,本系统实现Runnable接口以实现多线程设计理念。
1.4 开发平台及工具介绍
1.开发环境:Windows10操作系统
开发本游戏系统前提是一个支持Java开发的平台,一个可以安装并使用IntelliJ IDEA的平台。Windows 10是微软公司研发的跨平台操作系统,应用于计算机和平板电脑等设备。Windows 10在易用性和安全性方面,且支持Java开发与能够安装并使用IntelliJ IDEA。
2.编程语言:jdk1.8
JDK是 Java 语言的软件开发工具包。JDK是整个Java开发的核心,它包含了JAVA的运行环境(JVM+Java系统类库)和JAVA工具。
3.开发工具:IntelliJ IDEA
IntelliJ IDEA,是JetBrains公司的产品,是Java编程语言的集成开发环境,开发人员以严谨著称的东欧程序员为主。IntelliJ IDEA在业界,目前已超越Eclipse被公认为最好的Java开发工具。
1.5 可行性的分析
可行性研究的目的,软件开发确定能否达到目标,如果不能就可以用极小的代价解决它。如果没有进行可行性研究就会走很大的弯路,进行可行性研究分析后,可以把从可行性研究分析中发现的问题,用多种可能的解法解决它或者规避它。因此,可行性研究实质上是极大的简化了的系统分析和设计的过程,也就是在根本地对这个系统进行抽象的系统分析和设计。。一定要掌握切实可靠的资料,以保证资料选取的全面性、重要性、客观性与连接性.
1.5.1 技术可行性
Java的GUI设计对图形的处理更加逼真,玛丽主人公的形象有大的改观和提高运动的灵活性,游戏的关卡会更加复杂。通过Java多线程设计能实现主人公超级玛丽的各种功能,障碍物的状态,敌人的状态,Java面向对象程序设计便于通过系统处理准确性和及时性。玩家在玩游戏的时候,必然是不希望游戏突然卡住,或者崩溃,这是十分影响游戏体验感的。Java程序具有强大的功能,能保障游戏系统稳定且快速的反应。
1.5.2 经济可行性
即便是使用个人电脑都可以完成的超级玛丽,使用环境是依然。但在当今形式下网络游戏才是已经成为大众最喜欢的游戏,超级玛丽唯一的买点只有经典与不同的关卡设计。开发时Windows10操作系统,也可以使用更低的版本,但要能安装jdk1.8及其以上的Java版本,超级玛丽是相对非常小巧的游戏,可以说对机器本身没有要求,一般个人电脑完全可满足要求,Java在现在全球使用人数最多的开发工具,它非常受欢迎,极其庞大的类库,内置了各种功能。IntelliJ IDEA在java业界是公认为的、最好的开发工具,尤其在代码提示、自动补全可以说是超常的,最重要的一点是对使用期对整个开发是完全足够的。
第2章 需求分析
需求分析是软件生存周期中的环节,分析系统实现什么。分析和整理用户需求,之后把分析所得整理成文档,确定软件功能,要完成的功能工作。
2.1 非功能需求分析
超级玛丽这款游戏是很多人童年经典的回忆,是一种简单的大众的游戏,如果你回忆起了它,你定然会觉得现在它幼稚、无聊,画面不漂亮,游戏不精彩……但请你记住:这才是真正的游戏,它给了你无限的欢乐。利用java语言开发一款超级玛丽游戏,于人们童年的美好回忆对比,进一步开发。
2.2 功能需求分析
2.2.1 操作逻辑需求分析
本次超级玛丽游戏程序设计主要针对超级玛丽一些基本操作。明确要求以下几点的任务:
(4) 游戏结束的两种方式。
2.2.2 界面设计需求分析
(1) 采用经典的图片,色彩和谐自然。
(2) 为方便图片互相接触,确定初始游戏位置。
(3) 固定游戏大小为800*600像素,为方便对像素分割应设置小图片为30*30像素的正方形图片,而较大的障碍物多个30*30的正方形结合成大的方形图片。
第3章 系统概要设计
3.1 系统模块设计
概要设计是根据用户需求形成各种框架框架的过程,其结果布局各类元素、控件,呈现出页面框架图。概要设计的主要任务是把需求分析扩展软件结构和数据结构。超级玛丽游戏的内容是通过操作一名叫做玛丽的人物角色对象进行一关又一关的闯关设置,救出了被酷霸王绑架的松花公主的游戏情节。设计软件结构的具体任务是:将一个复杂系统例如超级玛丽按功能的加载图片、人物移动、图片界面检测进行模块划分等。数据结构设计包括数据特征的描述(例如背景图片要设置为800*600像素、小图片设置为30*30的正方形)、确定数据的结构特性(分数、生命值以文本至于界面上层,人物等以图片形式存在)。显然,只是把需求扩展出来,与计算机无关,却是软件开发过程中至关重要的一步。
3.2 系统流程设计
本次超级玛丽游戏程序设计主要针对超级玛丽一些基本操作。明确要求以下几点的任务:
(1) 游戏界面,选择游戏窗口后,播放音乐使游戏进行。
(2) 控制玛丽的动作由方向键向上键向下键向左键向右键四个键位来进行。
(3) 与图片边界接触的情况:
A.与各种敌人图片接触的情形:
对于与各种敌人图片的判定条件如以下,是否在敌人上方,如果不是玛丽被击杀,生命值减一。如果是敌人上方则判断敌人是不是可以击杀,当是蘑菇的时候则击杀敌人并使之消失,当是食人花的时候之类则食人花无改变,玛丽被击杀,生命值减一。当是乌龟的时候,乌龟图片变成龟壳这个障碍物图片使得玛丽可以推动龟壳。
B.与水管、陷阱、障碍物等等图片接触的情形:
对于与水管、陷阱、障碍物等等图片的判定条件如以下,玛丽在向左或向右移动的过程中下一步是否能继续移动,如果是砖块水管铁块箱子等等图片则停止移动,如果是移动到陷阱上方应该掉下去,并且生命值减到零。
顶到障碍物的三种场景,当碰到砖块的时候,砖块消失分数增加;当碰到?号箱子的时候,?号箱子消失变成铁块箱子并分数增加以及是否掉了物品;当碰到铁块箱子的时候,铁块箱子没有任何分数也不会增加。
(4)游戏结束的两种方式:玛丽生命值为零游戏失败,玛丽与旗子图片接触游戏通过。
具体看参考下图3-2所示:
图3-2 游戏流程图
3.3 Java类设计
在对超级玛丽游戏进行需求分析后,得出这款游戏窗口界面类。背景图片类、障碍物类、敌人类、玛丽类、初始化游戏类等等这几个类。具体介绍如下:
3.3.1 窗体类
表3-3-1 窗体类数据表
名称 | 数据类型 | 备注 |
allBackGround | List<BackGround> | 存储所有的背景 |
nowBackGround | BackGround | 存储当前的背景 |
offScreenImage | Image | 双缓存 |
mario | Mario | 玛丽对象 |
thread | Thread | 定义一个线程对象,用于实现玛丽的运动 |
3.3.2 初始化类
初始化类StaticValue需要游戏开始的时候为了提高游戏的运行速度,把必要的图片、文件数据导入,所有是用来存放程序的静态数据的。
把初始化类StaticValue中将用到的图片进行分类,分为障碍物类(例如砖块、水管等等),玛丽类(上下左右移动时的图片、死亡时的图片等等),敌人(蘑菇、食人花等等)类以及背景图片(开始游戏、游戏过程中等等)。这样调用这些集合中的图片时方便简洁,程序直接明了,运行迅速。具体数据见表3-3-2所示:
表3-3-2 初始化类数据表
名称 | 数据类型 | 备注 |
bg1 | BufferedImage | 背景1 |
bg2 | BufferedImage | 背景2 |
jump_L | BufferedImage | 玛丽向左跳跃 |
jump_R | BufferedImage | 玛丽向右跳跃 |
stand_L | BufferedImage | 玛丽向左站立 |
stand_R | BufferedImage | 玛丽向右站立 |
tower | BufferedImage | 城堡 |
gan | BufferedImage | 旗杆 |
obstacle | List<BufferedImage> | 障碍物 |
run_L | List<BufferedImage> | 玛丽向左跑 |
run_R | List<BufferedImage> | 玛丽向右跑 |
mogu | List<BufferedImage> | 蘑菇敌人 |
flower | List<BufferedImage> | 食人花敌人 |
path | String | 路径的前缀,方便后续调用 |
3.3.3 背景类
表3-3-3 背景类数据表
名称 | 数据类型 | 备注 |
bgImage | BufferedImage | 当前场景要显示的图像 |
sort | int | 记录当前是第几个场景 |
flag | boolean | 判断是否是最后一个场景 |
obstacleList_R | List<Obstacle> | 存放我们的所有障碍物 |
enemyList | List<Enemy> | 存放我们的所有敌人 |
gan | BufferedImage | 显示旗杆 |
tower | BufferedImage | 显示城堡 |
isReach | boolean | 判断玛丽是否到达旗杆位置 |
isBase | boolean | 判断旗子是否落地 |
3.3.4 元素抽象类
元素抽象类Component,游戏中的玛丽、各种敌人、各种障碍物,都具有的坐标,以及要显示的图片属性抽象出来组成的抽象类。具体数据见表3-3-4所示:
表3-3-4 元素抽象类数据表
名称 | 数据类型 | 备注 |
x | int | 当前x轴坐标 |
y | int | 当前y轴坐标 |
show | BufferedImage | 显示敌人的当前图像 |
3.3.5 玛丽类
表3-3-5 玛丽类数据表
名称 | 数据类型 | 备注 |
status | String | 当前的状态 |
backGround | BackGround | 取障碍物的信息 |
thread | Thread | 实现玛丽的动作 |
xSpeed | int | 玛丽的移动速度 |
ySpeed | int | 玛丽的跳跃速度 |
index | int | 定义一个索引 |
upTime | int | 玛丽上升的时间 |
isOK | boolean | 判断玛丽是否走到了城堡的门口 |
isDeath | boolean | 判断玛丽是否死亡 |
score | int | 分数 |
3.3.6 障碍物类
障碍物类Obstacle继承元素抽象类Component,定义所需要障碍物的类型,当前的场景对象等等。具体数据见表3-3-6所示:
表3-3-6 障碍物类数据表
名称 | 数据类型 | 备注 |
type | int | 记录障碍物类型 |
bg | BackGround | 当前的场景对象 |
thread | Thread | 障碍物线程对象 |
3.3.7 敌人类
敌人类Enemy继承元素抽象类Component,定义敌人类型标记蘑菇怪、食人花、乌龟等等敌人。针对食人花定义它的上下移动的极限范围。敌人的状态变化的速度等数据。标记他们的运动方向。具体数据见表3-3-7所示:
表3-3-7 敌人类数据表
名称 | 数据类型 | 备注 |
type | int | 存储敌人类型 |
speed | int | 敌人速度 |
face_to | boolean | 敌人运动的方向 |
bg | BackGround | 背景对象 |
max_up | int | 食人花运动的向上极限范围 |
max_down | int | 食人花运动的向下极限范围 |
thread | Thread | 敌人线程对象 |
image_type | int | 当前的图片的状态 |
3.3.8 背景音乐类
顾名思义,加载背景音乐。仅需一个构造函数即可。
3.3.9 类与接口关系
其中Component类为Obstacle类、Enemy类、Mario类的属性抽象类,以达到代码复用;StaticValue类、BackGround类、Music类准备游戏素材;MyFrame类继承JFrame类完成JavaGUI设计,Obstacle类、Enemy类、Mario类、MyFrame类实现Runnable接口通过多线程设计完成游戏逻辑的实现。IntelliJ IDEA类关系图如下图3-1-9所示:
图3-1-9 IntelliJ IDEA类关系图
第4章 系统详细设计
4.1 设计目标
详细设计是软件开发的根本步骤,是对概要设计的细化,是实现需求每个模块写下算法,所需的每一个局部结构。
点击超级玛丽小游戏进入游戏后开始,以生命值为零或者超级玛丽接触旗子结束,过程中利用方向键来控制的移动,并在移动过程中处理超级玛丽与各图片的逻辑关系。
4.2 系统类设计
本程序共包括8各类:游戏窗口类MyFrame、游戏初始化类StaticValue、游戏背景类BackGround、元素抽象类Component、玛丽类Mario、障碍物类Obstacle、敌人类Enemy、背景音乐Music。
4.2.1 窗体类
窗体类Myframe继承JFrame实现KeyListener接口和Runnable接口,设置数据存放游戏的场景的图片以及其他各类,还要能从键盘的按键中接受上下左右方向键,通过线程接口实现对超级玛丽运动的控制。该类中重要属性主要包括了如表所示:定义list集合,设置泛型BackGround,名称是allBackGround作用是存放场景图片,定义类型为Mario玛丽类 mario,保存当前场景的 BackGround数据类型nowBackGround以及定义线程对象实现超级玛丽的运动等。
在构造函数里,首先创建类名字定义为MyFrame,设置该类中的属性。通过this调用方法setSize()设置标题和设置游戏窗口的大小为800*600像素,调用方法setLocationRelativeTo(null)设置窗口居中显示,setVisible(true)设置窗口的可见性,调用方法setVisible(true)设置点击窗口上的关闭键,结束程序,调用方法设置窗口setResizable(false)大小不可变,调用方法addKeyListener(this)向窗口对象添加键盘监听器,调用方法setTitle("超级玛丽")设置窗口名称。部分代码具体实现如下:
//设置窗口的大小为800 * 600
this.setSize(800,600);
......
调用方法初始化玛丽对象,初始化图片。部分代码具体实现如下:
//初始化图片
StaticValue.init();
//初始化玛丽
mario = new Mario(10,355);
......
当窗口属性都设置好之后,应当通过循环遍历创建好全部场景以便后续使用。然后把第一个场景设置为当前场景,设置好后,绘制图像播放背景音乐,开始本线程,注意这里实例化音乐类要处理异常。部分代码具体实现如下:
//绘制图像
repaint();
//开始线程
thread.start();
//播放音乐
new Music();
......
游戏会出现闪屏问题,需要重写paint(Graphics g)方法,然后利用双缓存解决闪屏问题。在方法内通过Image类型的类对象offScreenImage获取数据类型为Graphics,名称为graphics,然后通过graphics绘制照片这个方法就是双缓存方法,其中要绘制包括背景、敌人、障碍物、城堡、旗杆、超级玛丽、分数等等,部分代码具体实现如下:
if (offScreenImage == null) {offScreenImage=createImage(800,600);}
Graphics graphics= offScreenImage.getGraphics();
graphics.fillRect(0,0,800,600);
//绘制背景
graphics.drawImage(nowBackGround.getBgImage(),0,0,this);
//通过增强for循环绘制敌人
for (Enemy e:nowBackGround.getEnemyList()) {graphics.drawImage
(e.getShow(),e.getX(),e.getY(),this);}
//窗口内添加分数
Color c = graphics.getColor();
graphics.setColor(Color.BLACK);
graphics.setFont(new Font("黑体",Font.BOLD,25));graphics.drawString("当
前的分数为: " + mario.getScore(),300,100);
graphics.setColor(c);
//将图像绘制到窗口中
g.drawImage(offScreenImage,0,0,this);
......
玩家对玛丽的控制是怎样进行的呢,这是游戏的关键所在。计算机游戏主要的是人机互动,通过控制台打印得出键盘的键位对于的编号,其中游戏开始时用到的空格键为32,方向键上所代表的编号是38,方向键左所代表的编号是37,方向键右所代表的编号是39,当玩家点击键盘,程序通过实现KeyListener接口的类重写keyPressed()方法,通过getKeyCode()方法接收玩家信息,实现人机互动。部分代码具体实现如下:
public void keyPressed(KeyEvent e) {
//向右移动
if (e.getKeyCode() == 39) {
//调用玛丽类中向右移动的方法
mario.rightMove();
}
......
}
同样对于松开按键,也就是说当键位抬起的时候。玛丽会保持一个状态停下来,让他的移动图片变为静止。过实现KeyListener接口的类重写keyReleased()方法。部分代码具体实现如下:
public void keyPressed(KeyEvent e) {
//向左停止
if (e.getKeyCode() == 37) {
//调用玛丽类中向左停止的方法
mario.leftStop();}
......
}
完成这一切以后,重写一下线程体方法了。完成超级玛丽过关逻辑以及结束游戏的两个逻辑,部分代码具体实现如下:
//当超级玛丽超过775像素的时候通过本关
if (mario.getX() >= 775) {nowBackGround=allBackGround.get(
nowBackGround.getSort());mario.setBackGround(nowBackGround);
mario.setX(10);
mario.setY(355);
}
//判断玛丽是否死亡
if (mario.isDeath()) {
JOptionPane.showMessageDialog(this,"玛丽死亡!!!");
System.exit(0);
}
//判断游戏是否通过
if (mario.isOK()) {
JOptionPane.showMessageDialog(this,"恭喜你!成功通关了");
System.exit(0);
}
......
4.2.2 初始化类
初始化类StaticValue需要游戏开始的时候为了提高游戏的运行速度,把必要的图片、文件数据导入,所有是用来存放程序的静态数据的。
把初始化类StaticValue中将用到的图片进行分类,这样调用这些集合中的图片时方便简洁,程序直接明了,运行迅速。其中分为障碍物图片(例如砖块、水管等等),玛丽图片(上下左右移动时的图片等等),敌人图片(蘑菇、食人花等等)以及背景图片(开始游戏、游戏过程中等等)。
首先定义一个泛型为BufferedImage的list集合,把它设置静态变量,名字为jump_L ,用来存放所有的超级玛丽向左跳跃状态的图片,依次类推做出向右跳跃、向左站立、向右站立等等图片;其次定义数据类型BufferedImage,设置其静态,名字为bg1,用来存放背景一图片;其次定义数据类型BufferedImage,设置其静态,名字为bg2,用来存放背景二图片;依次还有城堡、旗杆图片;接下来定义list集合,设置泛型为BufferedImage,设置其静态,名字为obstacle,用来存放所有的障碍物图片;依次类推还有超级玛丽向左跑,超级玛丽向右跑,蘑菇敌人,食人花敌人的图片,最后定义一个路径前缀方便后续调用,减少代码量。
定义数据之后,可以定义一个init()方法,通过IO流的字节流导入相应图片。这个方法在执行的时候上述数据赋予初值以及加载上述要求。
4.2.3 背景类
背景类BackGround该类表示游戏当前所在的场景,并且将还要将障碍物和敌人绘制当前背景下,还要记录他们的方便通过相应get()方法调出使用。
定义数据类型为BufferedImage ,名称为bgImage ,其作用是设置当前场景图片;定义数据类型为int,名称为sort,其作用是设置场景顺序;定义数据类型为boolean,名称为flag,其作用是标记是否为最后的场景;对于最后的场景要显示旗杆名称为gan,城堡tower两者皆为BufferedImage 类型,以及超级玛丽要胜利的时候判断旗帜是否落地和超级玛丽是否到达旗杆位置相应定义两个Boolean类型的数据isBase和isReach,至于保存障碍物和敌人就使用List集合保存设置名称为obstacleList和enemyList。既然是背景类,最重要的是布置关卡,重写一个构造函数,并在其中实例化关卡各个敌人与障碍物的,并存储入保存两者的List集合中。
4.2.4 元素抽象类
元素抽象类Component是玛丽类,敌人类,障碍物类的共同属性当期坐标,当前显示的图片可减少代码量。具体如下:
//存储当前坐标
protected int x;
protected int y;
//用于显示敌人的当前图像
protected BufferedImage show;
......
4.2.5 玛丽类
玛丽类Mario并从元素抽象类Componen继承下来,顾名思义用来控制玛丽的移动,并且在该类中加入图片边界判定,判断玛丽与障碍物或者敌人是否发生图片与图片之间接触。该类中的数据主要是当前场景,以及玛丽显示的图片是上是下还是左右的状态。还定义了是否死亡。
本类中定义数据类型为boolean,名字为isDeath,保存生命;为了更好的控制玛丽的移动状态,所有需要定义移动速度与跳跃速度两个int类型的数据,其中xSpeed为移速,ySpeed为上升下降速度。部分代码具体实现如下:
//用于表示当前的状态
private String status;
//定义一个BackGround对象,用来获取障碍物的信息
private BackGround backGround = new BackGround();
//用来实现玛丽的动作
private Thread thread = null
//用于判断玛丽是否走到了城堡的门口
private boolean isOK;
......
在构造函数中须初始化超级玛丽为向左站立并开启控制超级玛丽移动的线程。部分代码如下:
//设置其站立后保存状态
this.status = "stand--right";
//开启线程
thread = new Thread(this);
thread.start();
......
本类中,还要定义玛丽左右,跳跃,移动,死亡等方法。以方便调用控制玛丽状态,其中部分方法代码具体实现如下:
//玛丽向右移动
public void rightMove() {
xSpeed = 5;
//判断玛丽是否碰到旗子
if (backGround.isReach()) {
xSpeed = 0;
}
if (status.indexOf("jump") != -1) {
status = "jump--right";
}else {
status = "move--right";
}
}
......
完成上面的基础方法属性后,在这个线程体中对玛丽图片和障碍物图片或者敌人图片之间进行边界是否已接触,进行编写代码。这都写在本类中的run()方法了,因为这个方法中的内容相对上述的方法来说较为麻烦,情况较多下面进行详细说明。
首先在超级玛丽到达旗杆的时候应当结束游戏。代码具体实现如下:
//判断玛丽是否到达旗杆位置
if (backGround.isFlag() && this.x >= 500) {
this.backGround.setReach(true);
//判断旗子是否下落完成
if (this.backGround.isBase()) {
status = "move--right";
if (x < 690) {
x += 5;
}else {
isOK = true;
}
}else {
if (y < 395) {
xSpeed = 0;
this.y += 5;
status = "jump--right";
}
if (y > 395) {
this.y = 395;
status = "stop--right";
}
}
......
如果玛丽不是处于最后一个游戏场景,玩家才可以移动,同时才对当前玛丽当前场景中遍历各种图片,通过玛丽的坐标,与其坐标进行对比,来决定玛丽是否发生接触,并且通过是否接触来产生相应的变化。部分代码如下:
for (int i = 0; i < backGround.getObstacleList().size(); i++) {
Obstacle ob = backGround.getObstacleList().get(i);
//判断玛丽是否位于障碍物上
if (ob.getY() == this.y + 25 && (ob.getX() > this.x - 30
&& ob.getX() < this.x + 25)) {
onObstacle = true;
}
//判断玛丽是否位于陷阱上
if (ob.getType() == 2&&ob.getY( ) == this.y+ 25 &&
this.x>=ob.getX()&&this.x<=ob.getX()) {
//玛丽死亡
death();
}
4.2.6 障碍物类
在超级玛丽游戏中有诸多障碍物,其中包括地面、砖块、水管等等,在本类中我们需要设置它们的共有属性类型、所属场景的对象、一个控制它们的线程,并继承父类Component元素抽象类。部分代码具体实现如下:
//用于记录障碍物类型
private int type;
......
并重写构造方法方便实例化。具体代码如下:
public Obstacle(int x,int y,int type,BackGround bg){
show = StaticValue.obstacle.get(type);
//如果是旗子的话,启动线程
if (type == 0) {
thread.start();
}
......
}
在线程方法中当超级玛丽到达了旗杆处要设置场景对象的Base属性为true,部分代码如下:
if (this.bg.isReach()) {
if (this.y < 374) {
this.y += 5;
}else {
this.bg.setBase(true);
}
}
......
4.2.7 敌人类
对于敌人类Enemy,存在不同类型,所以需要一个属性type记录敌人类型,还有敌人也是会移动的故而存储其运动速度speed与运动方向face_to,为了实现其运动还要设置一个image_type来保存图片状态,通过图片的切换来实现动态运动,如何标记位置和显示图片可以通过父类Component元素抽象类的属性来保存。
为了控制敌人类另设一个线程来操控。其部分代码为:
//存储敌人类型
private int type;
//存储敌人速度
private int speed;
//判断敌人运动的方向
private boolean face_to = true;
//定义一个背景对象
private BackGround bg;
//定义当前的图片的状态
private int image_type = 0;针对不同的敌人可以重写不同的构造函数,方便实例化,以下给出更复杂的食人花的构造函数:
//食人花敌人的构造函数
public Enemy(int x,int y,boolean face_to,int type,int max_up,int max_down,BackGround bg) {
this.x = x;
this.y = y;
this.face_to = face_to;
this.type = type;
this.max_up = max_up;
this.max_down = max_down;
this.bg = bg;
show = StaticValue.flower.get(0);
thread.start();
}
敌人也是会被超级玛丽击杀,所以要编写其死亡方法:
show = StaticValue.mogu.get(2);
this.bg.getEnemyList().remove(this);
最后在线程方法体中编写控制它运动的代码,以下是食人花的运动代码 :
if (type == 2) {
if (face_to) {
this.y -= 2;
}else {
this.y += 2;
}
image_type = image_type == 1 ? 0 : 1;
//食人花是否到达极限位置
if (face_to && (this.y == max_up)) {
face_to = false;
}
if ((!face_to) && (this.y == max_down)) {
face_to = true;
}
show = StaticValue.flower.get(image_type);}
4.2.8 背景音乐类
只需在构造函数中通过player类将接收IO流读入的音乐,播放出来即可,其部分代码如下:
BufferedInputStream name=new BufferedInputStream(new FileInputStream(str));
player = new Player(name);
player.play();
第5章 系统的实现
5.1 游戏开发所需要的图片
在游戏开发的时候,首先要初始化类StaticValue在通过IO流的ImageIO.read()加载以下图片,其代码与图片如下分点所示:
设置属性时把站立与跳跃单独用BufferedImage类型数据存储,移动用List集合存储。图片如图5-1-1所示,部分代码如下:
//加载玛丽向左站立
stand_L = ImageIO.read(new File(path + "s_mario_stand_L.png"));
//加载玛丽向左跳跃
jump_L = ImageIO.read(new File(path + "s_mario_jump1_L.png"));
//通过循环加载玛丽向左跑
for (int i = 1; i <= 2; i++) {
run_L.add(ImageIO.read(new File(path + "s_mario_run" + i + "_L.png")));
}
......
图5-1-1 超级玛丽素材图
设置属性时用List集合存储,由于名称无规律,应用直接方式加载和循环方式加载结合。图片如图5-1-2所示,部分代码如下:
//加载旗子
obstacle.add(ImageIO.read(new File(path + "flag.png")));
//加载障碍物
for (int i = 1; i <= 5; i++) {
obstacle.add(ImageIO.read(new File(path + "brick" + i + ".png")));
}
......
图5-1-2 障碍物与水管素材图
设置属性时分别用两个List集合存储通过循环加载图片。图片如图5-1-3所示,部分代码如下:
//加载蘑菇敌人
for (int i = 1; i <= 3; i++) {
mogu.add(ImageIO.read(new File(path + "fungus" + i + ".png")));
}
......
图5-1-3 敌人素材图