1、计算机网络系统实践汇报设计题目:网络版小游戏坦克大战学生姓名:田昊轩学 号:84专业班级:物联网工程12-1班09月基于Java网络版坦克大战游戏设计一、 设计规定1.1设计目 (1)熟悉开发工具(JAVA)基本操作; (2)掌握windows/Linux应用程序编写过程; (3)对于Socket编程建立初步概念。1.2设计规定 (1)熟悉Socket API 重要函数使用; (2)掌握对应开发工具对Socket API 封装; (3)设计并实现一对一网络版小游戏,如:Tic-Tac-Toe、五子棋等。 我选择了网络版坦克大战设计。二、 开发环境与工具 2.1 编程语言:JAVA Java 语
2、言是一种跨平台,适合于分布式计算环境面向对象编程语言。JAVA目前重要用在WEB开发,手机游戏及某些平台游戏开发,由于它具有很好跨平台性,在手机等多种电子产品上应用非常广泛。 2.2 运行环境:JDK1.6 2.3 开发工具:My Eclipse 10 MyEclipse,是在eclipse 基础上加上自己插件开发而成功能强大企业级集成开发环境,重要用于Java、Java EE以及移动应用开发。MyEclipse功能非常强大,支持也十分广泛,尤其是对多种开源产品支持相称不错。 2.4 网络建立:socket 网络上两个程序通过一种双向通信连接实现数据互换,这个连接一端称为一种socket。 S
3、ocket英文原义是“孔”或“插座”。作为BSD UNIX进程通信机制,取后一种意思。一般也称作套接字,用于描述IP地址和端口,是一种通信链句柄,可以用来实现不一样虚拟机或不一样计算机之间通信。在Internet上主机一般运行了多种服务软件,同步提供几种服务。每种服务都打开一种Socket,并绑定到一种端口上,不一样端口对应于不一样服务。Socket正如其英文原意那样,像一种多孔插座。一台主机如同充斥多种插座房间,每个插座有一种编号,有插座提供220伏交流电, 有提供110伏交流电,有则提供有线电视节目。 客户软件将插头插到不一样编号插座,就可以得到不一样服务。三、 设计原理联机通信机制网络编
4、程,简朴地理解就是两台计算机互相通信。其基本模型就是客户机/服务器模型,也就是通信双方中一方必须提供一种固定位置,而另一方只需要懂得这个固定位置,并且建立两者之间联络,然后完毕数据互换。这里提供固定位置一方一般称为服务器,而建立联络一方称为客户端。Socket(中文意思为插座),基于客户机/服务器Soctet通信模式如图3.1所示:创立Socket类对象指定服务器端公认Socket地址和端口在Socket上监听客户端链接祈求接受客户端祈求信息解释并处理祈求信息向服务器发出祈求向服务器端发送链接祈求创立Socket类对象客户端将处理成果返回给客户端接受服务成果服务祈求服务响应服务器端图3.1 基
5、于客户机/服务器Soctet通信模式图当客户程序需要与服务器程序通讯时候,客户程序在客户机创立一种socket对象,Socket类有几种构造函数。两个常用构造函数是 Socket(InetAddress addr, int port) 和 Socket(String host, int port),两个构造函数都创立了一种基于Socket连接服务器端流套接字流套接字。两个函数都通过参数port获得服务器端口号。假设已经建立连接了,网络API将在客户端基于Socket流套接字中捆绑客户程序IP地址和任意一种端口号,否则两个函数都会抛出一种IOException对象。假如创立了一种Socket对象
6、,那么它也许通过调用Socket getInputStream()措施从服务程序获得输入流读传送来信息,也也许通过调用Socket getOutputStream()措施获得输出流来发送消息。在读写活动完毕之后,客户程序调用close()措施关闭流和流套接字。四、系统功能描述及软件模块划分 4.1 系统功能描述 4.1.1单机版人机对战 A)玩家通过上、下、左、右键来控制坦克八个方向:上、下、左、右、左上、右上、左下、右下; B)出现十个敌方坦克,自由运动并发射炮弹; C)玩家通过“control”键发射炮弹; D)打中敌方或被敌方打中,死亡; E)碰撞时死亡。 4.1.2网络对战模式 在人机
7、在人机对战模式中实现功能基础上,增长如下功能实现网络对战功能: A)添加网络功能,使两台或者多台不一样计算机玩家通过一定网络连接,加入到游戏中; B)可以自动分组选择阵营,一红一篮双方交替进入游戏,填写自己游戏信息,各个玩家之间实现网络对战功能,并且同是一方坦克不能互相袭击; C)玩家ID是自动分派,采用递加模式。 4.1.3总体功能设计坦克大战游戏重要实现玩家参与游戏整个流程,整个网络版坦克大战游戏流程图如图4.1所示:初 始 化游戏模式单 机对 战产生敌方坦克玩家坦克判断胜败玩家一玩家二玩家一玩家二敌方坦克我方坦克判断胜败结 束随机分派阵营图4.1 网络坦克大战游戏流程 4.2 软件模块划
8、分 4.2.1TankClient类基本功能分析 TankClient类是整个系统关键部分,它承担整个系统所有可实现功能调度工作。 是整个游戏运行场所。TankClient类设计流程图如图4.2所示:开始初始化坦克对战双方玩家坦克由键盘控制移动发射炮弹碰撞检测(坦克和子弹)不处理同角色坦克产生爆炸不一样角 色坦克判断胜败结束图4.2 TankClient类设计流程TankClient类是主类,通过调用其他类中封装措施来使整个系统运行起来,下面显示TankClient与各个类之间关系如图4.3所示:TankClient类(主类)Tank类(我方)Tank类(敌方)New参数1New参数2调用Mi
9、ssile类打中调用Explode类产程爆炸判断胜败键盘控制移动键盘控制移动打击图4.3 游戏系统类关联图 4.2.2 Tank类基本功能分析 Tank类中,封装了某些变量属性,包括坦克自己大小(WIDTH,HRIGHT),运动速度(SPRRD_X:在x轴方向速度;SPEED_Y:在Y轴方向速度)、生命值控制(life)、坦克编号(id)、坦克名(name)、方向控制(dir)、生死控制(live)等。Tank类中没有main函数,不是主类,它当中只封装某些变量属性和静态措施,被TankClient类调用来实现坦克一系列动作。Tank类中重要措施罗列如下: (1)getRect()措施publ
10、ic Rectangle getRect() return new Rectangle(x, y, this.WIDTH, this.HEIGHT); Rectangle类是碰撞检测辅助类,通过得到子弹x,y坐标和宽高度,检测两个矩形与否碰撞(相交); (2)draw()措施:负责将所有活动在屏幕上画出来; (3)move()措施:重要负责控制坦克移动,包括8个方向(左,左上,上,右上,右,右下,下,左下)控制以及给坦克一种移动速度; (4)keyPressed()措施:设定使用键盘“”“”“”“”键控制坦克移动; (5)keyReleased()措施:处理按键抬起事件,抬起“CTRL”键时,
11、发射炮弹并加入新炮弹,可以逐一发射每一发炮弹、抬起“A”键可以发射超级炮弹等功能; (6)locationDirection()措施:定义了炮筒方向,可以向八个方向发射炮弹; (7)fire()措施:处剪发送子弹措施; (8)bumpWithWall()措施:重要负责处理坦克撞墙事件; (9)bumpWithTank()措施:重要到负责处理坦克和坦克相撞事件; 4.2.3 Missile类基本功能分析 Misslile(子弹)类和Tank类同样,只封装某些变量属性和静态措施,重要变量包括:子弹自己大小(WIDTH,HRIGHT),运动速度(SPRRD_X:在x轴方向速度;SPEED_Y:在Y轴
12、方向速度)、子弹标示(ID)、所属坦克id号(TankId用于网络版)等。Misslie类持有一种TankClient类(大管家)引用tc,TankClient类要执行发射炮弹操作时调用Missile类中措施。Misslie类中重要措施如下:(1) draw()措施:负责画出子弹所有活动;(2) move()措施:先判断方向再移动,并给它一定移动速度;(3) getRect()措施:负责获得子弹外切方形,为碰撞检测做准备;(4) hitTan()措施:检测子弹与否撞到坦克,若撞到返回true,否则返回false;(5) hitTanks()措施:检测与否撞到一系列坦克中一种;(6) hitWa
13、ll()措施:检测子弹和墙与否相撞。 4.2.4 Explode类基本功能分析Explode(爆炸)类也是一种只封装自己变量和措施外部包装类,没有main措施,供TankClient主类需要时调用它draw()措施,当子弹击中坦克时需要产生爆炸。 4.2.5 服务器类基本功能分析TankServer(服务器)类重要负责在网络对战游戏时维护各个在线玩家基本信息,并动态维护玩家列表。联机模式下类关系图如图4.4所示:TankServer类TankClient 1类类TankClient 2类类New参数1New参数2调用Missile类调用Explode类产程爆炸判断胜败Tank类(我方)Tank
14、类(敌方)打中打击4.4 联机模式类关联图 4.2.6 信息传送类基本功能分析 信息传送类就是用来封装客户端和服务器端交互信息。将网络中传递众多信息封装成可序列化类,将会使程序有很好可扩展性。 五、设计环节5.1 单机版坦克大战游戏(人机对战) 5.1.1主程序:TankClient 代码如下:public class TankClient extends Frame private static final long serialVersionUID = 586564L;public static final int GAME_WIDTH = 800;public static final
15、int GAME_HEIGHT = 600;public static int SCORE = 0, 0, 0 ;Random r = new Random();Tank myTank1 = new Tank(750, 550, Tank.Direction.STOP, this, 1);Tank myTank2 = new Tank(50, 550, Tank.Direction.STOP, this, 2);Wall w1 = new Wall(200, 100, 200, 10, this);Wall w2 = new Wall(200, 100, 10, 200, this);Wall
16、 w3 = new Wall(200, 300, 200, 10, this);Wall w4 = new Wall(400, 300, 10, 200, this);Wall w5 = new Wall(200, 490, 200, 10, this);Wall w6 = new Wall(500, 100, 10, 400, this);Wall w7 = new Wall(500, 490, 200, 10, this);Blood b = new Blood();List missiles = new ArrayList();List explodes = new ArrayList(
17、);Image offScreenImage = null;/ 定义背后虚拟图片public void paint(Graphics g) / g.drawString(Missiles Count: + missiles.size(), 10, 50);/ g.drawString(Explodes Count: + explodes.size(), 10, 70);/ g.drawString(Tanks Count: + tanks.size(), 10, 90);g.setColor(Color.orange);g.drawString(P1 P2, 10, 40);g.drawStr
18、ing(L C: 发射一枚一般子弹。, 10, 60);g.drawString(K V: 九个方向超级炮弹。, 10, 80);g.drawString(J B: 埋下一颗地雷等他踩., 10, 100);g.drawString(F2 F3: 购置一辆全新坦克。, 10, 140);g.drawString(P1剩余坦克数 : + myTank1.getLives(), 600, 50);g.drawString(P2剩余坦克数 : + myTank2.getLives(), 600, 70);g.drawString(P1分数 : + SCORE1, 600, 90);g.drawStr
19、ing(P2分数 : + SCORE2, 600, 110);g.drawString(剩余坦克波数 : + Tank.win, 600, 130);myTank1.collidesWithWall(w1);myTank2.collidesWithWall(w2);myTank1.collidesWithWall(w3);myTank2.collidesWithWall(w4);myTank1.collidesWithWall(w5);myTank2.collidesWithWall(w6);myTank1.collidesWithWall(w7);myTank2.collidesWithTa
20、nk(myTank1);myTank1.collidesWithTank(myTank2);for (int i = 0; i missiles.size(); i+) Missile m = missiles.get(i);m.hitTank(myTank1);m.hitTank(myTank2);m.hitWall(w1);m.hitWall(w2);m.hitWall(w3);m.hitWall(w4);m.hitWall(w5);m.hitWall(w6);m.hitWall(w7);m.draw(g);for (int i = 0; i explodes.size(); i+) Ex
21、plode e = explodes.get(i);e.draw(g);myTank1.draw(g);myTank2.draw(g);w1.draw(g);w2.draw(g);w3.draw(g);w4.draw(g);w5.draw(g);w6.draw(g);w7.draw(g);if (myTank1.getLife() 40 | myTank2.getLife() 40) myTank1.eat(b);myTank2.eat(b);b.draw(g);/ 用update截住paintpublic void update(Graphics g) if (offScreenImage
22、= null) offScreenImage = this.createImage(GAME_WIDTH, GAME_HEIGHT);Graphics gOffScreen = offScreenImage.getGraphics();Color c = gOffScreen.getColor();gOffScreen.setColor(Color.black);gOffScreen.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT);gOffScreen.setColor(c);paint(gOffScreen);g.drawImage(offScreenImag
23、e, 0, 0, null);public void launchFrame() this.setLocation(200, 80);this.setSize(GAME_WIDTH, GAME_HEIGHT);this.setTitle(TankWar-Written By Small_Light);this.addWindowListener(new WindowAdapter() public void windowClosing(WindowEvent e) System.exit(0););this.setBackground(Color.black);this.setResizabl
24、e(false);/ 不可以调整窗口大小this.addKeyListener(new KeyMonitor();this.setVisible(true);new Thread(new PaintThread().start();/主函数public static void main(String args) TankClient tc = new TankClient();tc.launchFrame();/多线程,画图private class PaintThread implements Runnable public void run() while (true) repaint()
25、;try Thread.sleep(40); catch (InterruptedException e) e.printStackTrace(); 5.1.2 信息传播 TankNewMsg(TankMoveMsg和TankDeadMsg与此模块基本相似,暂不贴出了) 代码如下:/* * 代表坦克诞生消息类 author mashibing */public class TankNewMsg implements Msg int msgType = Msg.TANK_NEW_MSG;Tank tank;TankClient tc;/* * 根据tank信息构建消息 * param tank
26、*/public TankNewMsg(Tank tank) this.tank = tank;/* * 根据消息产生场所构建新消息 * param tc */public TankNewMsg(TankClient tc) this.tc = tc;/* * 发送有关消息 * param ds 通过该socket发送数据 * param IP 数据目IP * param udpPort 数据目端口 */public void send(DatagramSocket ds, String IP, int udpPort) ByteArrayOutputStream baos = new Byt
27、eArrayOutputStream();DataOutputStream dos = new DataOutputStream(baos);try dos.writeInt(msgType);dos.writeInt(tank.id);dos.writeInt(tank.x);dos.writeInt(tank.y);dos.writeInt(tank.dir.ordinal();dos.writeBoolean(tank.good); catch (IOException e) e.printStackTrace();byte buf = baos.toByteArray();try Da
28、tagramPacket dp = new DatagramPacket(buf, buf.length,new InetSocketAddress(IP, udpPort);ds.send(dp); catch (SocketException e) e.printStackTrace(); catch (IOException e) e.printStackTrace();/* * 分析接受到消息数据 * param dis 接受到消息数据输入流 */public void parse(DataInputStream dis) try int id = dis.readInt();if (
29、tc.myTank.id = id) return;int x = dis.readInt();int y = dis.readInt();Dir dir = Dir.values()dis.readInt();boolean good = dis.readBoolean();/ System.out.println(id: + id + -x: + x + -y: + y + -dir: +/ dir + -good: + good);boolean exist = false;for (int i = 0; i tc.tanks.size(); i+) Tank t = tc.tanks.
30、get(i);if (t.id = id) exist = true;break;if (!exist) TankNewMsg tnMsg = new TankNewMsg(tc.myTank);tc.nc.send(tnMsg);Tank t = new Tank(x, y, good, dir, tc);t.id = id;tc.tanks.add(t); catch (IOException e) e.printStackTrace(); 5.1.3爆炸explode 代码如下:public void draw(Graphics g) if(!live) tc.explodes.remo
31、ve(this);return;Color c = g.getColor();g.setColor(Color.ORANGE);g.fillOval(x, y, diametersstep, diametersstep);g.setColor(c);step +;if(step = diameters.length) live = false;5.2 建立Server,建立Client并和Server连接 TankServer代码如下:服务端程序 重要代码:public class TankServer private static int ID = 100;/* * TCP监听端口 */pu
32、blic static final int TCP_PORT = 8888;/* * UDP监听端口 */public static final int UDP_PORT = 6666;List clients = new ArrayList();/* * 启动服务器 */public void start() new Thread(new UDPThread().start();ServerSocket ss = null;try ss = new ServerSocket(TCP_PORT); catch (IOException e) e.printStackTrace();while
33、(true) Socket s = null;try s = ss.accept();DataInputStream dis = new DataInputStream(s.getInputStream();String IP = s.getInetAddress().getHostAddress();int udpPort = dis.readInt();Client c = new Client(IP, udpPort);clients.add(c);DataOutputStream dos = new DataOutputStream(s.getOutputStream();dos.wr
34、iteInt(ID+);/ s.close();System.out.println(A Client Connect! Addr- + s.getInetAddress() + : + s.getPort()+ -UDP Port: + udpPort); catch (IOException e) e.printStackTrace(); finally if (s != null) try s.close();s = null; catch (IOException e) e.printStackTrace();public static void main(String args) n
35、ew TankServer().start();private class Client String IP;int udpPort;public Client(String IP, int udpPort) this.IP = IP;this.udpPort = udpPort;private class UDPThread implements Runnable byte buf = new byte1024;public void run() DatagramSocket ds = null;try ds = new DatagramSocket(UDP_PORT); catch (So
36、cketException e) e.printStackTrace();System.out.println(UDP thread started at port : + UDP_PORT);while (ds != null) DatagramPacket dp = new DatagramPacket(buf, buf.length);try ds.receive(dp);for (int i = 0; i clients.size(); i+) Client c = clients.get(i);dp.setSocketAddress(new InetSocketAddress(c.I
37、P,c.udpPort);ds.send(dp);System.out.println(a packet received!); catch (IOException e) e.printStackTrace();5.3客户端发送UDP端口,获得自己ID号 (java.util.UUID) 服务器端保留客户端信息关键代码如下:public void connect(String IP, int port) this.IP = IP;try ds = new DatagramSocket(udpPort); catch (SocketException e) e.printStackTrace(
38、);Socket s = null;try s = new Socket(IP, port);DataOutputStream dos = new DataOutputStream(s.getOutputStream();dos.writeInt(udpPort);DataInputStream dis = new DataInputStream(s.getInputStream();int id = dis.readInt();tc.myTank.id = id;if (id % 2 = 0)tc.myTank.good = false;elsetc.myTank.good = true;T
39、ankNewMsg msg = new TankNewMsg(tc.myTank);send(msg);new Thread(new UDPRecvThread().start();/* * 发送消息 * param msg 待发送消息 */public void send(Msg msg) msg.send(ds, IP, TankServer.UDP_PORT);private class UDPRecvThread implements Runnable byte buf = new byte1024;public void run() while (ds != null) Datagr
40、amPacket dp = new DatagramPacket(buf, buf.length);try ds.receive(dp);parse(dp);System.out.println(a packet received from server!); catch (IOException e) e.printStackTrace();private void parse(DatagramPacket dp) ByteArrayInputStream bais = new ByteArrayInputStream(buf, 0, dp.getLength();DataInputStream dis = new DataInputStream(bais);int msgType = 0;try msgType = dis.readInt(); catch (IOException e) e.printStackTrace();5.4 多种客户联网,并发送坦克诞生消息(TankMoveMsg和TankDeadMsg与TankNewMsg基本相似,就不再贴出了)