赞
踩
基于Java的坦克大战游戏的设计与实现
目 录
基于Java的坦克大战游戏的设计与实现
摘要:随着人们对生活质量的要求一天比一天高,为了让人们更好地开掘自身的智慧,游戏就此进入了大众的视野,在人们的生活中有着重要的位置,已然变得必不可少。游戏产业推动高新技术不断升级,极大地促进了经济的增长,推动了“第四产业”的经济腾飞。坦克大战游戏是童年时期经常玩的经典游戏,我们对它都十分了解。游戏通过分析JAVA游戏开发和代码设计,用Eclipse软件开发了坦克大战游戏,运用接口技术,使一个类能够实现多个接口,使用套接字Socket来完成client端和server端的连接。玩家通过连接访问进入游戏,通过操纵坦克来守卫基地,玩家还可以获得超级武器来提升坦克的属性,摧毁全部敌方坦克来取得胜利,操作非常简单,还具有非常高的普遍率,适合所有人群玩。该游戏既满足了人们的个性化需求,也让玩家在游戏过程中丢掉烦恼,尽情地释放压力。
关键词:Java 坦克大战游戏 Socket
1.引言
随着社会和时代的进步,来自各个方面的压力让人没精打采,为了分解人们的压力,休养那变得疲顿的头脑和劳累的身心,特设计了坦克大战小游戏,游戏操作非常容易,只要将手指放在键盘上敲击相关的游戏键就可以玩,在玩游戏的过程中能够体验现实生活中没有的快乐,既有利于身心健康,又不会影响工作和学习。本游戏采用的是基于J2SE标准平台的java编程技术,在Windows 7操作系统中使用Eclipse软件进行代码编译,通过方法Graphics()来进行游戏地图界面的绘制,使用了接口技术使一个类能够实现多个接口,使用套接字Socket来完成client端和server端的连接。
Java是一项面向对象编程语言,既包含了C语言的全部优点,又具有面向对象,跨平台性,安全性等特点,是现在程序设计中较为常用的编程语言。Java具备了“一次编译,处处运行”的特点,很好的体现了其跨平台性和面向对象的特点,允许程序员用感性的思路来进行繁杂的编程。
Eclipse是一个基于java的开放源代码的可扩展开发平台,是知名的跨平台的自由集成开发环境(IDE)Eclipse是一个基于,还捎带了一个标准规范的插件集,包含了Java开发工具(JDK),Eclipse因为安装不同的插件,所以它支持不同的计算机语言,主要用来Java语言开发。
Graphics类是软件包java.awt(其全部类都用来用户界面的创建和图形图像的绘制)下的类,它同意一个应用程序绘制到组件,以及在屏幕图像上进行绘制。Graphics 对象封装了 Java 支持的基本呈现操作所需的状态信息。Graphics()方法构造了一个新的 Graphics 对象, 由于 Graphics类是抽象类,因此Graphics()方法不可以被直接调用,此构造方法是图形上下文的默认构造方法,通过在组件上调用 getGraphics() 来创建图形上下文,或者从其他图形上下文获取。
2.1 需求和技术分析
如今的游戏已经成为世界上最大的娱乐休闲项目之一,游戏市场规模持续增长,潜力巨大,我国政府一向以来都特别鼓励游戏产业的发展,特别是我国当地的游戏产业,扶持力度连年加大,由此可见,我国对游戏产业的重视程度。该坦克大战游戏是对红白机经典90坦克大战的延续,对于80后,90后来说,都是童年里最宝贵的回忆,而80后,90后恰好占据着当今游戏人群的主体,对于他们来说,该坦克大战游戏不仅可以减轻人们的社会压力,放松身心,也可以回味小时候玩红白机游戏的疯狂时光,又不会沉迷于游戏,老少咸宜,能够更好地体验游戏的乐趣。
该程序代码有着贼高的运用率,因此,设计时必须要有相当缜密的逻辑条理思维,还要考虑一些无法操控的因素和所有可能出现的突发事件。
(1)玩家能够通过敲击游戏键来操纵玩家坦克的动作,但对于敌方坦克来说,就要有第一定的自主性和智能型,因为是自动运行。同时,屏幕上的敌方坦克需要开创一个线程让其自主运行来应对数量过多而导致的混乱。要精密设置敌方坦克的操作运行算法,不要使游戏太过单一。
(2)要对所有坦克打出的子弹进行实时监测并判断它打到了什么物体对象,因此需要开辟一个独立的线程来处理子弹,还需要控制好所有的物体对象。在同一时候,在JVM虚拟机上保持运行这么多的线程,可能会造成程序的迟钝,甚至瘫痪。
(3)由于游戏界面中物体对象繁多,为了避免重叠运行,玩家坦克在前进时需要时刻地扫描周围环境。
(4)游戏的动态画面是一个优秀程序不可缺少的组成成分,精美的用户界面是引起玩家兴趣的关键,相关的构图美化技术也需要有所考虑。
(5)在游戏地图中会有许多各种不同的物体对象,这不是绘图方法能够解决的,而且过多的大型photo会束缚程序的大小,所以要准确掌握Graphcis()方法的使用。同时使用读取外部文件的方法来加载游戏关卡,因为内存有限,不适合用于存储地图关卡。
(6)游戏要对玩家的分数进行记录,这就需要对其功能和属性进行妥善的策划,还需要制作良好的解决方案来处理其存储方式。
(7)为了确保游戏程序的运行顺畅,需要对结构进行严格把控,将算法完善得更精准,还可以运用混淆器对打包后的软件程序进行优化。
2.2 功能分析
该坦克大战选择使用以往的游戏规矩。服务器端创建并设置一个主机,客户端申请连接加入,若其IP输入判断无误,载入地图关卡并开始游戏,在游戏界面中,会实时显示敌方坦克数量和玩家坦克的生命数量及分数。敌方坦克自行移动和打出子弹,玩家通过敲击键盘来操控自己坦克的动作并打出子弹,子弹无法打中相同阵营的坦克,当两方阵营的子弹相交时会相互抵消,打中对方坦克时会产生爆炸效果,中途可以暂停、发送信息,玩家坦克吃掉超级武器后会赋予其特殊的功能,在游戏地图界面中还同时游戏中还包含了通信功能。如果取得了胜利,会显示“你过关了!”,如果失败了,则系统给出“GAME OEVR!还想再玩一次吗?(y/n)”的提示,如果玩家双方都选择继续游戏,则游戏重新加载并开始,不然结束并退出游戏界面。
3.总体设计
3.1 总体功能
游戏由服务器端和客户端两部分组成。
在服务器端,ServerModel类主要用来创建主机,ServerView类主要负责服务器端图形界面的面板信息的设置,ServerControler类处理来自服务器视图框架的输入,包括创立通信与帮助信息等,enemy类主要负责敌方坦克的创建,player类主要用来设置玩家的得分及其显示位置等信息,drawingPanel类主要负责服务器端界面窗口的创建和设置,powerUp类主要用来设置子弹属性,例如加快速度、提升火力等,feedbackHandler类主要用来解码从客户端发来的指令字符串,再将其转换成指令来判断游戏失败后玩家是否继续游戏的问题。
在客户端,ClientModel类主要用来设置与服务器的连接,ClientView类主要负责客户端端图形界面的面板信息,ClientControler类主要负责处理来自客户端视图框架的输入和创立通信与帮助信息等,drawingPanel主要用来设置客户端窗口界面,instructionHandler类主要用来解码从服务器端发来的指令字符串,再将其转换成指令来判断游戏失败后玩家是否继续游戏的问题,shield类主要负责设置坦克吃掉头盔图标获得保护时的状态,normalObject类主要用来创建和描绘其他物体对象。
在服务器端和客户端中都存在的类中,Actor类主要用来创建接口,base类主要用来创建基地并设置属性,bullet类主要用来创建子弹并设置属性,Ticker类主要用来创建时间信息,bomb类主要用来创建子弹打出后产生的爆炸效果,river类主要用来创建河道并设置属性,grass类主要负责创建草坪并设置属性,Steelwall类主要用来创建铁墙并设置属性,wall类主要用来创建和设置普通墙及其属性,level类负责创建关卡。如表1,表2所示。
表1 游戏服务器端各类功能表
ServerModel | 创建主机 |
ServerView | 设置服务器端图形界面的面板信息 |
ServerControler | 处理来自服务器视图框架的输入 |
enemy | 创建敌方坦克 |
player | 设置玩家的得分及其显示位置等信息 |
drawingPanel | 创建和设置服务器端界面窗口 |
powerUp | 加快子弹速度并提升火力 |
feedbackHandler | 判断指令并执行 |
Actor | 创建接口 |
base | 创建并设置基地 |
Ticker | 创建并设置时间信息 |
bullet | 创建子弹并设置属性 |
bomb | 设置爆炸效果 |
river | 创建河道并设置属性 |
grass | 创建草坪并设置属性 |
Steelwall | 创建铁墙并设置属性 |
wall | 创建普通墙并设置属性 |
level | 创建关卡 |
表2 游戏客户端各类功能表
ClientModel | 设置与服务器的连接 |
ClientView | 设置客户端端图形界面的面板信息 |
ClientControler | 负责处理来自客户端视图框架的输入 |
drawingPanel | 设置客户端窗口界面 |
instructionHandler | 判断指令并执行 |
shield | 设置玩家坦克防护盾 |
normalObject | 创建并描绘其他的物体对象 |
level | 创建关卡 |
base | 创建并设置基地 |
Ticker | 创建并设置时间信息 |
bullet | 创建子弹并设置属性 |
bomb | 设置爆炸效果 |
river | 创建河道并设置属性 |
wall | 创建普通墙并设置属性 |
客户端玩家输入主机地址来完成与服务器玩家的连接,双方通过使用指令键来操控自己的坦克,敌方坦克和子弹则是自主随机运行,游戏中会对玩家的分数进行记录,还增加了特殊武器,另外,此游戏还进行了小小的创新,添加了通信功能,客户端与服务器端的连接访问通过使用套接字Socket来实现。
其总体功能如图1所示。
图1 总体功能图
如图2所示。
图2 总体流程图
4.详细设计
4.1 面板功能设计
4.1.1 基地的设计
base类定义了几个变量,通过构造器初始化了基地的变量参数,使用g.drawImage()方法设置一幅图片来代表基地,通过public void move(){}来处理基地受到铁墙防护时的变化,使用if()判断语句判断铁墙的保护时间。游戏的核心重点自然就是基地了,一旦基地被毁,则玩家失败,游戏结束。游戏面板是游戏程序的关键,这里使用了方法paintComponent(Graphics g)来进行建立并设置其属性,具体实现代码如下:
public void draw(Graphics g){
g.drawImage(base, xPos - 12, yPos - 12, null );}
public void paintComponent(Graphics g) {
Graphics offScreenGraphics;
if (offScreenImage == null) {
offScreenImage = createImage(640, 550);
}
offScreenGraphics = offScreenImage.getGraphics();
myPaint(offScreenGraphics);
g.drawImage(offScreenImage, 0, 0, this);}
4.1.2敌方坦克的设计
enemy类设置了敌方坦克的共同属性,并根据不同外形的坦克设置了不同的属性,如椭圆形的坦克的移动速度会比较快,拥有多层颜色坦克的生命力与其拥有的颜色数量一样,利用随机函数Math.random()*4随机生成一个随机值,并转换成整形数值,将此值赋给变量direction来作为敌方坦克生成时的方向,再将Math.random()*200生成的随机值转换成整形数值,赋予变量interval来作为生成时的时间间隔,并且设置了地方坦克的移动周期,在一个周期内将会朝着相同的方向继续移动,并设置了其发射子弹的遂进行。而在特殊属性中,分别设置了敌方坦克的的火力、速度、图标等属性,再用方法draw(Graphics g){}向地图中加入敌方坦克。具体实现代码如下:
interval = (int)(Math.random()*200);
direction = (int)(Math.random()*4);
if(type ==args1 ){
firePosibility = args2;
speed = args3;
textures = new Image[args4];}
public void draw(Graphics g){
if(flashing && gameModel.gameFlow%10 > 4)
g.drawImage(textures[textures.length-4+direction], xPos - size, yPos - size, null);
else
g.drawImage(textures[direction], xPos - size, yPos - size, null);}
4.1.3河道、草坪的设计
grass类继承了Actor接口,通过grass类构造器定义了草坪的x,y坐标和矩形边界以及图标,通过public void draw(Graphics g) {}方法绘制了草坪。游戏双方坦克及其子弹可以自由通过草坪。具体实现代码如下:
public grass(int a, int b){
xPos = a;
yPos = b;
border = new Rectangle(0,0,0,0);
}
public void draw(Graphics g) {
g.setColor(new Color(0, 225, 0));
for(int i = yPos - 11; i <= yPos + 12; i+=5)
g.drawLine(xPos - 12, i, xPos + 12, i);
for(int i = xPos - 11; i <= xPos + 12; i+=5)
g.drawLine(i, yPos - 12, i, yPos + 12);
g.setColor(new Color(0, 128, 0));
for(int i = yPos - 10; i <= yPos + 12; i+=5)
g.drawLine(xPos - 12, i, xPos + 12, i);
for(int i = xPos - 10; i <= xPos + 12; i+=5)
g.drawLine( i, yPos - 12, i, yPos + 12);
}
river类继承了Actor接口,用river类构造器定义了河道的x,y坐标和矩形边界以及图标,使用g.drawImage(Image,int,int, ImageObserver)方法设置一幅图片来代表河道。以前各个经典版本的坦克大战游戏都将河道设置为不允许坦克经过,但子弹可以自由通过,本程序为了遵循经典,也如此设计。具体实现代码如下:
public river(int a, int b, ServerModel gameModel){
this.gameModel = gameModel;
river = gameModel.textures[71];
xPos = a;
yPos = b;
Border = new Rectangle(xPos - 12, yPos - 12, 25, 25);}
g.drawImage(river, xPos - 12, yPos - 12, null)}
4.1.4墙与铁墙的设计
该模块通过new Rectangle(int x,int y,int width,int height)完成了一个矩形的创建,然后将其具体值赋给变量数组border[数组索引]生成了墙。坐标x和y为绘制矩形时的起始点,width,height分别为矩形绘制的宽和高。通过构造器定义普通墙和铁墙的矩形边界和图标。具体实现代码如下:
generalBorder = new Rectangle(xPos - 12, yPos - 12, 25, 25);
border[0] = new Rectangle(xPos - 11, yPos - 11, 11, 11);
border[1] = new Rectangle(xPos + 1, yPos - 11, 11, 11);
border[2] = new Rectangle(xPos - 11, yPos + 1, 11, 11);
border[3] = new Rectangle(xPos + 1, yPos + 1, 11, 11);
public wall(int a, int b, int orientation, ServerModel gameModel){
xPos = a;
yPos = b;
this.gameModel = gameModel;
wall = gameModel.textures[70];
generalBorder = new Rectangle(xPos - 12, yPos - 12, 25, 25);}
4.1.5界面窗口的创建
再该模块中,在ServerView类的构造器中用super()方法调用父类构造器设置窗口题目为“坦克大战”,使用JButton(String)定义了六个(退出、帮助、发送、暂停/继续、建立主机和隐藏)鼠标点击事件(即所谓的按钮),JTextField定义文本框,并将其设置为不可编辑。使用new drawingPanel()和setBackground(Color c)创建一个面板并设置背景颜色,再通过setBounds()和setLayout()方法定义了页面的大小并将页面布局定义为空。通过add()方法向页面添加按钮和文本框。使用setColor(Color c)方法设置面板颜色为指定颜色,再通过继承自java.awt.Graphics类中的drawString(String,int,int)方法向面板添加并输出当前关数及剩余敌人数,通过if判断语句进行判断,如果消灭坦克数量大于敌方坦克数量则输出胜利场景。
4.2子弹功能设计
该模块用setColor()方法设置子弹颜色为浅灰色,使用g.fillRect(int,int,int,int)方法设置子弹水平或垂直发射时的形状,子弹和什么东西相交通过if()判断语句和equals()方法来鉴定,然后再处理相交时子弹和其他对象的属性变化。具体代码如下:
public void draw(Graphics g) {
g.setColor(Color.lightGray);
if(direction == 0 || direction == 1)
g.fillRect(border.x + 1, border.y +1, 3, 9);
if(direction == 2 || direction == 3)
g.fillRect(border.x +1, border.y + 1, 9, 3);
}
if(!border.intersects(map)){
gameModel.removeActor(this);
notifiyOwner();
makeBomb();
writeToOutputLine();
return;
if(gameModel.actors[i].getType().equals("steelWall")){
Steelwall temp =(Steelwall)gameModel.actors[i];
if(!temp.walldestoried){
temp.damageWall(border,bulletpower,direction);
if(temp.bulletdestoried)
hitTarget = true;
}
}else if(gameModel.actors[i].getType().equals("wall")){
wall temp = (wall)gameModel.actors[i];
if(!temp.walldestoried){
temp.damageWall(border,bulletpower,direction);
if(temp.bulletdestoried)
hitTarget = true;
}
}else if(gameModel.actors[i].getType().equals("bullet")){
bullet temp = (bullet)gameModel.actors[i];
if(temp.owner.getType().equals("Player")){
hitTarget = true;
gameModel.removeActor(gameModel.actors[i]);
temp.notifiyOwner();
}
}else if(gameModel.actors[i].getType().equals("Player")){
if(owner.getType().equals("enemy")){
player temp = (player)gameModel.actors[i];
temp.hurt();
}else{
}
hitTarget = true;
}else if
(gameModel.actors[i].getType().equals("enemy") && owner.getType().equals("Player")){
enemy temp = (enemy)gameModel.actors[i];
player tempe = (player)owner;
if(temp.health == 0)
tempe.scores+=temp.type*100;
temp.hurt();
hitTarget = true;
}else if(gameModel.actors[i].getType().equals("base")){
base temp = (base)gameModel.actors[i];
temp.doom();
hitTarget = true;
gameModel.gameOver = true;
}
}
}
}
}
if(hitTarget){
gameModel.removeActor(this);
notifiyOwner();
makeBomb();
writeToOutputLine();
return;
}
4.3坦克功能设计
坦克吃掉了什么特殊武器图标通过if()判断语句和equals()方法来鉴定,如果吃到TNT图标,则已经出现了的敌方坦克全部被炸毁;如果吃到坦克图标,玩家坦克加一条生命;如果吃到五角星图标,则提升玩家坦克子弹火力并且速度加快,可以打破铁墙;若是头盔图标,则玩家坦克获得防护盾且免疫敌方子弹;如果吃到铁墙图标,则基地由普通墙变为铁墙,如果吃到钟表图标,则时间停止,所有敌方坦克静止。具体代码如下:
if(gameModel.actors[i].getType().equals("powerUp")){
scores+=50;powerUp temp = (powerUp)gameModel.actors[i];
int function = temp.function;
if(function == 0){ upgrade();
}else if(function == 1){ base tempe = (base)gameModel.actors[4];tempe.steelWallTime = 600;
}else if(function == 2){
for(int j = 0; j < gameModel.actors.length; j++)
if(gameModel.actors[j] != null)
if(gameModel.actors[j].getType().equals("enemy")){
enemy tempe = (enemy)gameModel.actors[j];
gameModel.addActor(new bomb(tempe.xPos, tempe.yPos, "big", gameModel));
gameModel.removeActor(gameModel.actors[j]);}
level.NoOfEnemy = 0;level.deathCount = 20 - level.enemyLeft;}else if(function == 3){
InvulnerableTime = 300 + (int)Math.random()*400;
}else if(function == 4){
enemy.freezedTime = 300 + (int)Math.random()*400;
enemy.freezedMoment = ServerModel.gameFlow;
}else if(function == 5){
if(status < 3)numberOfBullet++;
status =4;health = 2;if(type.equals("1P"))
for(int j = 0; j < 4; j ++)textures[j] = gameModel.textures[66+j];
else
for(int j = 0; j < 4; j ++)
textures[j] = gameModel.textures[84+j];
}else if(function == 6){ life++;}
4.4服务器设计
4.4.1 ServerModel类
在ServerModel类,实现了ActionListener接口,具备了监听功能。创建了一些连接变量和游戏变量,设置了布尔类型的服务器状态变量,使用构造器完成了消息队列信息的设置,使用createServer(){}方法建立主机,当布尔变量serverCreated的值为true时,主机创建成功,还设置了一个端口号,用try{}catch{}语句处理代码执行时发生的异常,并给出错误提示,服务器通过accept()方法与客户端建立连接,当端口号没有被其他应用程序占用并IP地址正确,则成功完成连接,载入游戏,如若不然,就会显示相应的错误提示。使用addMessage()在屏幕上显示消息,使用removeMessage()方法删除屏幕上的消息,通过addActor()和remove()方法完成了向地图中增添新的物体对象和清除已经不存在了的物体对象的操作。具体代码如下:
public void createServer(){
addMessage("正在建立主机(端口9999)");
try {
serverSocket = new ServerSocket(9999);
serverCreated = true;
} catch (Exception e) {
addMessage("无法建立主机,请确认端口9999没有被别的程序使用");
System.out.println(e);
t.stop();
return;
}
addMessage("建立完成,等待玩家连接");
try {
clientSocket = serverSocket.accept();
clientConnected = true;
out = new PrintWriter(clientSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(
clientSocket.getInputStream()));
} catch (Exception e) {
addMessage("连接中出现错误,请重新建立主机");
serverCreated = false;
clientConnected = false;
t.stop();
try{
serverSocket.close();
clientSocket.close();
out.close();
in.close();
}catch(Exception ex){}
return;
}
view.messageField.setEnabled(true);
addMessage("玩家已连接上,开始载入游戏");
out.println("L1;");
textures = new Image[88];
for(int i = 1; i < textures.length+1; i++)
textures[i-1] = Toolkit.getDefaultToolkit().getImage("image\\" + i + ".jpg");
actors = new Actor[400];
level.loadLevel(this);
P1 = new player("1P", this);
addActor(P1);
P2 = new player("2P", this);
addActor(P2);
gameStarted = true;
view.mainPanel.actors = actors;
view.mainPanel.gameStarted = true;
addMessage("载入完毕,游戏开始了!");
}
public void removeActor(Actor actor){
for(int i = 0; i < actors.length; i ++ )
if(actors[i] == actor){
actors[i] = null;
break;
}
}
public void addMessage(String message){
if(messageIndex < 8){
messageQueue[messageIndex] = message;
messageIndex++;
}
else{
for(int i = 0; i < 7; i++)
messageQueue[i] = messageQueue[i+1];
messageQueue[7] = message;
}
public void removeMessage(){
if(messageIndex == 0)
return;
messageIndex--;
for(int i = 0; i < messageIndex; i++)
messageQueue[i] = messageQueue[i+1];
messageQueue[messageIndex] = null;
if(!gameStarted)
view.mainPanel.repaint();
}
4.4.2 feedbackHandler类
feedbackHandler类从客户端程序解码指令字符串,然后将字符串转换为真正的指令。通过while(!instruction.substring(i, i+1).equals("?")){}语句来判断其指令,并根据其指令来完成相对性的操作。
4.4.3 其他各类设计
Lever类设置了不同的关卡,通过if(1+ (currentLevel-1)%8 == num){}判断语句来加入关卡,在进入下一关卡时,上一个关卡的所有东西都会被系统清理,并且增加了游戏难度。同时还设置了胜利场景。
Player类通过构造器设置了玩家坦克的生命数量,生成时的方向和无敌时间,以及健康状态,子弹数量等。通过if(type.equals( "1P")){}elae{}来判断两个玩家并设置其坦克的初始位置,用drawImage()方法绘制玩家坦克,当玩家敲击开火键时,会用if()语句判断是否慢如条件,若满足就会生成一个子弹,并且子弹的位置、速度等属性参数都会被设置好,再通过add()方法添加子弹。在坦克的下一个移动有效的前提下根据玩家坦克的移动定义玩家坦克的下一个边界,并判断是否与地图边界和其他物体对象相交,设置相交时坦克与物体对象会发生的变化情况。当玩家坦克被击毁时,其生命减少,使用reset()方法将玩家坦克路径重置为空,遗弃所有坐标和点类型,设置其位置为游戏开始时的位置。
在powerUp类中实现了对玩家坦克子弹火力的增加。
在Ticker类运用构造器建立了时间发生器,实现了runnable接口,并调用了其run()方法。
在ServerControler类处理来自服务器端视图框架的输入,实现了玩家消息互通功能。使用了构造器view.buttonName.addActionListener()方法完成了按钮功能的设计。使用addKeyListener(new KeyAdapter()){}方法增加了键盘输入的操作,再通过keyPressed(KeyEvent e)方法来实现,通过if(e.getKeyCode() == KeyEvent.VK_UP)语句来判断并执行相应的方向移动操作,通过if(e.getKeyChar() == 's')判断并执行”s”键的操作,if(e.getKeyCode()==e.VK_ENTER)判断是否点击Enter键,再通过if(e.getKeyChar() ==?)来判断输入什么键并执行相应的操作。通过keyReleased(KeyEvent e)方法来释放给定的键。具体代码如下:
if(!model.gameStarted){
model.addMessage("还没有和别的玩家联上, 无法发送对话");
return;
}
if(!view.messageField.getText().equals("")){
model.addMessage("主机端玩家说:" + view.messageField.getText());
model.playerTypedMessage += "m" + view.messageField.getText() + ";";
view.messageField.setText("");
}else{
model.addMessage("对话内容不能为空");
}
4.5 客户端设计
4.5.1 ClientModel类
在ServerModel类,实现了ActionListener接口,具备了监听功能。创建了一些连接变量和游戏变量,设置了布尔类型的客户端状态变量,使用构造器完成了消息队列信息的设置,用try{}catch{}语句处理代码执行时发生的异常,给出错误提示,使用add()方法向地图中添加对象,客户端程序实际上不执行任何逻辑计算,它只接受指令,将指令字符串做出的反馈告诉客户端。具体代码如下:
public void connectServer(){
addMessage("正在连接主机");
try{
serverIP = view.IPfield.getText();
InetAddress addr = InetAddress.getByName(serverIP);
clientSocket = new Socket(addr, 4321);
out = new PrintWriter(clientSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));}catch(Exceptione)
{t.stop();System.out.println(e);
addMessage("连接出现错误,请确认1.输入的IP是否正确 2.主机端已存在");
return;}
4.5.2 instructionHandler类
instructionHandler类只有客户端可读,它对从服务器程序反馈的指令字符串进行解码,然后将字符串转换为真正的指令,通过while循环语句和if判断语句来判断指令,并执行相应的指令动作,具体实现方法如下:
if(perInstruction.substring(0,1).equals("L")){
level.loadLevel(gameModel, Integer.parseInt(perInstruction.substring(1,2)));
return;}
if(perInstruction.substring(0,1).equals("w")){for(int k = 0; k < gameModel.drawingList.length; k++){
if(gameModel.drawingList[k] !=null){if(gameModel.drawingList[k].getxPos() == xPos && gameModel.drawingList[k].getyPos() == yPos){
wall tempWall = new wall(xPos, yPos, 4, gameModel);
tempWall.shape = shape;
gameModel.drawingList[k] = tempWall;
}
}
}
if(perInstruction.substring(0,1).equals("b")){gameModel.drawingList[4] = new normalObject(260, 498, gameModel, "base", 1);}
if(perInstruction.substring(0,1).equals("t")){
gameModel.addActor(new bullet(xPos, yPos, gameModel, direction))}
if(perInstruction.substring(0,1).equals("o")){
gameModel.addActor(new bomb(xPos, yPos, size, gameModel)); }
if(perInstruction.substring(0,1).equals("i")){
gameModel.addActor(new shield(xPos, yPos, gameModel)); }
if(perInstruction.substring(0,1).equals("a")){
if(!gameModel.gameOver){
gameModel.addMessage("GAME OVER ! 想再玩一次吗 ( y / n ) ?");
gameModel.gameOver = true;
}
}
if(perInstruction.substring(0,1).equals("x")){
int temp = Integer.parseInt(perInstruction.substring(1,2));
if(temp == 0){
if(gameModel.gamePaused){
gameModel.addMessage("主机端玩家取消了暂停");
gameModel.gamePaused = false;}
}else{if(!gameModel.gamePaused){
gameModel.addMessage("主机端玩家暂停了游戏");
gameModel.gamePaused = true;
}
}
4.5.3 其他各类的实现
在shield类中,使用了构造器,并实现了玩家坦克吃掉头盔图标后获得的防护盾的功能,通过draw(Graphics g){}方法绘制防护盾,用方法setColor(Color c)设置其颜色,drawRect()设置防护盾的x,y坐标和高度、宽度,当护盾时间结束时,通过removeActor()方法去除护盾。在level类中,定义了游戏正在玩的关数,设置了不同的关卡,通过if(1+ (levelIndex-1)%8 == num){}判断语句来加入关卡,在进入下一关卡时,上一个关卡的所有东西都会被系统清理,并且增加了游戏难度。此类只有一层对象,所以是一个静态变量。normalObject类代表所有其他对象。ClientControler类功能与ServerControler相同,都是实现按钮的功能和处理键盘输入操作。
5.游戏测试
5.1 测试方法
白盒测试主要是检查程序的内部逻辑结构设计。根据源代码的组织结构查找软件缺陷,但是如果要把整个网站系统的代码都要检测到也是不可能的,所以要选择最重要的核心的代码进行白盒测试。
黑盒测试不需要研究软件内部的逻辑结构和布局,以及代码的具体实现,它根据程序软件的作用和外部结构的特点来检查漏洞的存在,从整个程序使用过程的角度来检查漏洞,这就导致了黑盒测试只能局限的检查出该软件在功能和使用的时候的问题。
本游戏程序选择使用白盒测试方法。当然,还有其他的测试方法:比如静态分析方法和动态测试方法等等。我们可以在综合的需求分析之后进行选择。
5.2 系统测试
5.2.1 游戏启动测试
运行Eclipse中的server项目和client项目或双击server文件夹和client文件夹下的Play.BAT文件来运行游戏,游戏启动成功,看到了游戏界面。如图3所示。
图3 启动测试图
5.2.2 页面按钮测试
(1)在服务器端,点击“建立主机”按钮,成功建立主机,并给出了提示。如图4所示。
图4 建立主机按钮测试图
(2)在客户端,在页面上方的文本框内输入IP地址:127.0.0.1,然后点击“连接主机”按钮。连接成功并给出提示,进入游戏。如图5所示。
(3)点击帮助按钮,成功在页面上显示游戏的方法。如图6所示。
图6 帮助按钮侧视图
(4)点击页面上方的暂停/继续按钮,若游戏正在进行,点击这个按钮就会暂停游戏,然后再点击,就会取消暂停,并且在页面上给出提示。在页面下方的文本框内输入对话消息,点击发送按钮,成功发送消息,并且在页面上显示了通话内容。如图7所示。
图7 暂停/继续与发送按钮测试图
5.2.3 玩家坦克测试
敲击方向键,坦克也成功向着相同的方向移动,点击“s”键,成功发射子弹。如图8所示。
图8 坦克测试图
5.2.4 超级武器测试
玩家坦克子弹打中敌方红色坦克,在地图上随机的位置生成了随机的图标,玩家坦克吃到各种图标后成功地获得了该图标所对应的功能。
5.2.5 胜利与失败测试
在游戏中击毁了所有敌方坦克,成功地显示了“过关了!”界面。
玩家坦克数量为0或基地被敌方坦克攻破了,成功地在页面上显示了“GAME OVER!想再玩一次吗(y/n)?”的消息。若游戏双方都选择都输入“y”,则游戏重新开始,并给出了提示。
5.3 测试分析和小结
经过测试,游戏正常运行,并实现了游戏的全部主要功能,系统稳定地处理了游戏相关数据,对错误给出提示,对异常进行捕获和处理。由此可见,本游戏程序安全性较好,没有特别大的漏洞存在,系统结构清晰,页面设计也比较美观,具备了基本功能,总体上比较圆满地完成了当初游戏程序的设计的目标。
但是,对游戏程序来说,没有任何一个可以说是十全十美、毫无漏洞的,以现在国际上最受欢迎的美国Roit公司开发的英雄对战MOBA竞技游戏《英雄联盟》来说,都会有一些或多或少的漏洞,每周都会对游戏进行系统维护与更新,可想而知,本游戏虽然是一个相对来说非常简单的小游戏,但对于初次设计Java领域并进行游戏设计的大学毕业生来说,不可能做到无懈可击,毫无漏洞可言,逻辑的复杂性,难以控制,因此到目前为止还存在一些bugs没有能够解决,如下:
6.结论
该游戏是基于Java语言,使用Eclipse软件开发的一款坦克大战游戏, 该游戏包括对面板功能、坦克功能、子弹功能的设计,在面板功能中对双方坦克、基地、河道、草坪、普通墙与铁墙等地图元素进行创建并设置其属性,还实现了页面按钮功能,玩家可以点击按钮来实现相应的功能。在坦克功能中,设计了操作玩家坦克的方法,还设置了超级武器,玩家吃掉后会获得特殊技能。在子弹功能中,设置了子弹打中不同物体对象产生的不同效果。另外,还实现了服务器与客户端的连接,加载关卡等功能,玩家再游戏面板中可以实时查看自己坦克的生命数量和分数以及敌方坦克的数量,基本上完成了设计任务。总体来说,本游戏有一定的逻辑性和复杂性,对玩家有一定的吸引力。
在设计与实现游戏的过程中,遇到一些逻辑问题和技术故障都是在所难免的,例如如何加载地图关卡和物体对象等、监探坦克与地图元素是否碰撞等,都是需要完全克服的。该游戏还需要进一步的优化,需要在更大的程度上提升敌方坦克的智能化、在地图中添加物体对象来增强可玩性等等。
[1] 易向东,陈蓓,万英.Java游戏编程解析[M],程序员杂志[M].北京:电子工业出版社.2009.
[2] 张广彬,王小宁,高静.Java课程设计案例精编[M].北京:清华大学出版社,2011.
[3] 袁然,郑自国,邹丰义.Java案例开发集锦[M].北京:电子工业出版社.2005.
[4] 陈炜,张晓蕾,侯燕萍 ,何凌云.Java软件开发技术[M].北京:人民邮电出版社.2005.
[5] 陈为, 周骥 ,杨柯. 面向对象的游戏开发[M].北京:DEARBOOK出版社,2008.[6] 谭浩强,程龙,杨海兰等. Java编程技术[M].北京:人民邮电出版社. 2003.
[7]雍俊海.Java程序设计教程[M].北京:清华大学出版社,2014.
[8] 爱克尔(著),王美(译).Java编程思想[M]. 北京:机械工业出版社,2001.
[9] 邱仲潘. Java游戏编程[M].北京:机械工业出版社,2006.
[10] 陈悦,夏敏捷,葛丽萍. Java游戏编程原理与实践教程[M].北京:人民邮电出版社.2013.
[11] 邓良松,刘海岩,陆丽娜.软件工程[M].第二版.西安:西安电子科技大学出版社,2004.
[12]赵强,乔新亮. J2EE应用开发[M]. 电子工业出版社,2003.
[13]夏庆亮. Java应用开发指南[J]. 清华大学出版社,2010.
[14]耿祥义,张跃平. Java面向对象程序设计[J]. 清华大学出版社,2010.
[15]杨绍方. Java编程实用技术与案例[J]. 清华大学出版社,2000.
[16]明日科技. Java编程全能词典[J]. 电子工业出版社,2010.
[17]埃克尔(著),陈昊鹏,饶若楠等译. Java编程思想[J]. 机械工业出版社,2005.
[18]Gary J.Bronson(著),张珑 刘雅文译. Java编程原理[J]. 清华大学出版社,2004 .
[19]Michael Morrison(著),徐刚,于健,薛雷译. 游戏编程入门[J]. 人民邮电出版社,2005.9.
[20]Wendy Stahler(著),冯宝坤,曹英译. 游戏编程中的数理应用[J]. 红旗出版社,2005.
[21]克罗夫特(著),彭晖译. Java游戏高级编程[J]. 清华大学出版社,2005.
参考资料:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。