随着社会和时代的进步,来自各个方面的压力让人没精打采,为了分解人们的压力,休养那变得疲顿的头脑和劳累的身心,特设计了坦克大战小游戏,游戏操作非常容易,只要将手指放在键盘上敲击相关的游戏键就可以玩,在玩游戏的过程中能够体验现实生活中没有的快乐,既有利于身心健康,又不会影响工作和学习。本游戏采用的是基于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.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所示。
如图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相同,都是实现按钮的功能和处理键盘输入操作。