通过本项目能够更直观地理解应用层和运输层网络协议, 以及继承封装多态的运用. 网络部分是本文叙述的重点, 你将看到如何使用Java建立TCP和UDP连接并交换报文, 你还将看到如何自己定义一个简单的应用层协议来让自己应用进行网络通信

一.主要设计内容:

1、需要有图形用户界面,让用户能看到游戏给出的反馈。
2、不同队伍的坦克,须显示不同的外观,以区分敌我。
3、坦克能够开火,攻击敌方,但不能攻击队友。
4、需要有不可被子弹穿透的墙体,以及墙体有可被摧毁和不可被摧毁两种。
5、敌方坦克有生命值,并非被击中一次就会爆炸。
6、游戏结束时会有胜利或失败场景
7、游戏结束后可重新开始。

二. 程序源码基本结构

三.设计的环境、方法及措施:

  • 主要设备:电脑。
  • 软件:eclipse软件。
  • 方法措施:
  • 利用学到的java基础应用程序知识实现需求分析上的功能模块,并在设计与实现时分析遇到的问题并解决,对实现的模块进行测试,查找不足,尽量做到满足用户要求

四. 实现了哪些功能

此系统是使用Java语言实现坦克大战游戏程序,玩家通过连接访问进入游戏,通过操纵坦克来守卫基地,玩家还可以获得超级武器来提升坦克的属性,摧毁全部敌方坦克来取得胜利。本系统结构如下:
(1)面板功能:
对双方坦克、基地、河道、草坪、普通墙与铁墙等地图元素,还实现了页面按钮功能,玩家可以点击按钮来实现相应的功能。

(2)坦克功能:
操作玩家坦克的方法,还设置了超级武器,玩家吃掉后会获得特殊技能。

(3)子弹功能:
设置了子弹打中不同物体对象产生的不同效果。

五. 运行效果





六. 实现思路

  • 数据存储表示: 在JPanel绘制图像,统一规定各个方块的大小为同一大小(如墙壁,坦克之类,子弹除外),从而方便使用二维数组存储地图的各个元素。

  • 关于检测物体碰撞,这里使用了一个MyImage的父类,将坦克,墙壁
    定义为继承这个父类的一个类。

class MyImage {int width = Game.width;int height = Game.height;//二维地图的坐标Coord coord;//屏幕上的像素坐标int x;int y;MyImage(Coord coord) {x = coord.x * width;y = coord.y * height;this.coord = coord;}private Rectangle getRect() {return new Rectangle(x, y, width, height);}//碰撞检测boolean isIntersects(MyImage other) {return other.getRect().intersects(getRect());}
}
  • 图像打印则借助遍历两个ConcurrentHashMap分别储存坦克和其他类型的方块。将这些方块使用Map而不是使用数组是因为管理起来比较方便,而二维数组则是为了寻路算法而准备的,防止了频繁使用上面的两个Map而导致线程锁的问题。

七. 遇到的问题

ava的按键监听在响应按键长按时会有1-2秒的延迟,导致操作手感极差
解决方法:在坦克类中设置一个布尔属性move以及整形变量key储存键入的按键值,创建一个线程来响应按键。

实现代码:

//按键响应的线程类
class MyTankMove implements Runnable{public void run(){while(flag){GetKey(key);while(move){//决定是否移动try {e.printStackTrace();Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}try {Thread.sleep(10);//防止无按键时陷入死循环导致线程堵塞} catch (InterruptedException e) {}}}

按键监听事件,即给key和move赋值

//按键监听接口
private class KeyBoradListener extends KeyAdapter{public void keyPressed(KeyEvent e){super.keyPressed(e);int key = e.getKeyCode();if(key<65){//为了实现双人对战而设置的。。。if(key!=KeyEvent.VK_SHIFT&&!MyTank.isEmpty()){MyTank.getFirst().key=key;MyTank.getFirst().move=true;}}else{if(key!=KeyEvent.VK_G&&!MyTank.isEmpty()){switch (key){case KeyEvent.VK_W:key = KeyEvent.VK_UP;break;case KeyEvent.VK_A:key = KeyEvent.VK_LEFT;break;case KeyEvent.VK_S:key = KeyEvent.VK_DOWN;break;case KeyEvent.VK_D:key = KeyEvent.VK_RIGHT;break;}MyTank.getLast().key=key;MyTank.getLast().move=true;}}
}
public void keyReleased(KeyEvent e){super.keyReleased(e);int key = e.getKeyCode();if(key<65){if(!MyTank.isEmpty()){if(key!=KeyEvent.VK_SHIFT&&key==MyTank.getFirst().key){//避免了同时按两个以上按键后会卡住MyTank.getFirst().move=false;}else{MyTank.getFirst().GetKey(key);}}}else{switch (key){case KeyEvent.VK_W:key = KeyEvent.VK_UP;break;case KeyEvent.VK_A:key = KeyEvent.VK_LEFT;break;case KeyEvent.VK_S:key = KeyEvent.VK_DOWN;break;case KeyEvent.VK_D:key = KeyEvent.VK_RIGHT;break;case KeyEvent.VK_G:key = KeyEvent.VK_SHIFT;break;}if(!MyTank.isEmpty()){if(key!=KeyEvent.VK_SHIFT&&key==MyTank.getLast().key){MyTank.getLast().move=false;}else{MyTank.getLast().GetKey(key);}}}
}
}

项目内的图片资源如何在项目导出后也能使用

解决方法:假设在项目的scr文件夹中建立img文件夹,在项目的.classpath中加一句(Eclipse),也可以通过设置项目的Modules,将图像文件夹设置为resources(IDEA),并使用当前类的名.class.getResource("/(文件名)")).getImage()获得图像对象。

寻路的实现

实现思路:通过使用一个存储了地图内各个元素的二维数组Game.map,使用广度优先算法遍历出一条路线,将结果存放于栈之中。

实现代码:

 /*** 使用广度遍历算法,使用队列存储遍历的节点** @return 移动的路径*/private Stack<Coord> GetPath() {Coord target = Game.tanks.get(Game.P1_TAG).coord;Queue<Coord> d_q = new LinkedBlockingQueue<>();ArrayList<Coord> IsMove = new ArrayList<>();d_q.offer(coord);IsMove.add(coord);Coord last = null;boolean flag;while (!d_q.isEmpty()) {Coord t = d_q.poll();int tx = t.x;int ty = t.y;int i;//遍历所有的方向for (i = 0; i < 4; ++i) {switch (i) {case Game.UP:ty -= 1;break;case Game.LEFT:tx -= 1;break;case Game.RIGHT:tx += 1;break;case Game.DOWN:ty += 1;break;}//判断该点是否可行flag = true;Coord z = new Coord(tx, ty);//检查是否为目标终点if (z.equals(target)) {z.per = t;last = z;break;}//检查该坐标是否已经遍历了for (Coord c : IsMove) {if (c.equals(z)) {flag = false;break;}}if (flag) {//检查下一格是否可以抵达flag = !(Game.map[ty][tx] == Game.BLANK || Game.map[ty][tx] == Game.WALLS);}//该点可以用if (flag) {//将坐标纳入已经遍历的队列中d_q.offer(z);IsMove.add(z);z.per = t;last = z;}IsMove.add(z);//重新选择方向遍历tx = t.x;ty = t.y;}//如果没有四个方向都遍历完就跳出,说明已经找到了终点if (i != 4) {break;}}Stack<Coord> coords = new Stack<>();while (null != last && last.per != null) {coords.push(last);last = last.per;}return coords;}

八.网络联机

客户端连接上服务器

  • 首先客户端通过TCP连接上服务器, 并把自己的UDP端口号发送给服务器, 这里省略描述TCP连接机制, 但是明白了连接机制后对为什么需要填写服务器端口号和IP会有更深的理解, 它们均为TCP报文段中必填的字段
  • 服务器通过TCP和客户端连上后收到客户端的UDP端口号信息, 并将客户端的IP地址和UDP端口号封装成一个Client对象, 保存在容器中
  • 这里补充一点, 为什么能获取客户端的IP地址? 因为服务器收到链路层帧后会提取出网络层数据报, 源地址的IP地址在IP数据报的首部字段中, Java对这一提取过程进行了封装, 所以我们能够直接在Java的api中获取源地址的IP
  • 服务器封装完Client对象后, 为客户端的主机坦克分配一个id号, 这个id号将用于往后游戏的网络传输中标识这台坦克
  • 同时服务器也会把自己的UDP端口号发送客户端, 因为服务器自身会开启一条UDP线程, 用于接收转发UDP包. 具体作用在后面会讲到
  • 客户端收到坦克id后设置到自己的主战坦克的id字段中. 并保存服务器的UDP端口号.
    这里你可能会对UDP端口号产生疑问, 别急, 后面一小节将描述它的作用

附上这部分的代码片段:

//客户端
public void connect(String ip, int port){serverIP = ip;Socket s = null;try {ds = new DatagramSocket(UDP_PORT);//创建UDP套接字s = new Socket(ip, port);//创建TCP套接字DataOutputStream dos = new DataOutputStream(s.getOutputStream());dos.writeInt(UDP_PORT);//向服务器发送自己的UDP端口号DataInputStream dis = new DataInputStream(s.getInputStream());int id = dis.readInt();//获得服务器分配给自己坦克的id号this.serverUDPPort = dis.readInt();//获得服务器的UDP端口号tc.getMyTank().id = id;tc.getMyTank().setGood((id & 1) == 0 ? true : false);//根据坦克的id号的奇偶性设置坦克的阵营} catch (IOException e) {e.printStackTrace();}finally {try{if(s != null) s.close();//信息交换完毕后客户端的TCP套接字关闭} catch (IOException e) {e.printStackTrace();}}TankNewMsg msg = new TankNewMsg(tc.getMyTank());send(msg);//发送坦克出生的消息(后面介绍)new Thread(new UDPThread()).start();//开启UDP线程
}//服务器
public void start(){new Thread(new UDPThread()).start();//开启UDP线程ServerSocket ss = null;try {ss = new ServerSocket(TCP_PORT);//创建TCP欢迎套接字} catch (IOException e) {e.printStackTrace();}while(true){//监听每个客户端的连接Socket s = null;try {s = ss.accept();//为客户端分配一个专属TCP套接字DataInputStream dis = new DataInputStream(s.getInputStream());int UDP_PORT = dis.readInt();//获得客户端的UDP端口号Client client = new Client(s.getInetAddress().getHostAddress(), UDP_PORT);//把客户端的IP地址和UDP端口号封装成Client对象, 以备后面使用clients.add(client);//装入容器中DataOutputStream dos = new DataOutputStream(s.getOutputStream());dos.writeInt(ID++);//给客户端的主战坦克分配一个id号dos.writeInt(UDP_PORT);}catch (IOException e) {e.printStackTrace();}finally {try {if(s != null) s.close();} catch (IOException e) {e.printStackTrace();}}}
}

结论

该游戏是基于Java语言,使用Eclipse软件开发的一款坦克大战游戏, 该游戏包括对面板功能、坦克功能、子弹功能的设计,在面板功能中对双方坦克、基地、河道、草坪、普通墙与铁墙等地图元素进行创建并设置其属性,还实现了页面按钮功能,玩家可以点击按钮来实现相应的功能。在坦克功能中,设计了操作玩家坦克的方法,还设置了超级武器,玩家吃掉后会获得特殊技能。在子弹功能中,设置了子弹打中不同物体对象产生的不同效果。另外,还实现了服务器与客户端的连接,加载关卡等功能,玩家再游戏面板中可以实时查看自己坦克的生命数量和分数以及敌方坦克的数量,基本上完成了设计任务。总体来说,本游戏有一定的逻辑性和复杂性,对玩家有一定的吸引力。

在设计与实现游戏的过程中,遇到一些逻辑问题和技术故障都是在所难免的,例如如何加载地图关卡和物体对象等、监探坦克与地图元素是否碰撞等,都是需要完全克服的。该游戏还需要进一步的优化,需要在更大的程度上提升敌方坦克的智能化、在地图中添加物体对象来增强可玩性等等。

Java实现坦克大战小游戏(源码+注释)相关推荐

  1. 【180930】坦克大战小游戏源码

    坦克大战小游戏源码程序实现了小霸王游戏机上坦克大战的功能,主要功能是开火.移动.3种不同的敌方坦克.用户自制地图等,缺点是有些小细节还处理的不好,感觉画面不够好,还没实现自动的下一关功能(主要是嫌做默 ...

  2. 【JAVA程序设计】基于JAVA的坦克大战小游戏--入门级小游戏

    基于JAVA的坦克大战小游戏--入门级小游戏 零.项目获取 一.项目简介 二.开发环境 三.游戏玩法 四.运行截图 零.项目获取 获取方式(点击下载):是云猿实战 项目经过多人测试运行,可以确保100 ...

  3. html+javascript实现的网页版飞机大战小游戏源码

    html+javascript实现的网页版飞机大战小游戏源码 完整代码下载地址: html+javascript实现的网页版飞机大战小游戏源码 index.html <!DOCTYPE html ...

  4. 飞机大战小游戏源码---飞机大战初体验

    开发环境: Windows10,pycharm,python3 源码使用教程: 打开pycharm,创建一个新的项目,文件-->新建项目 项目命名:飞机大战初体验,基本解释器选择python3版 ...

  5. java飞机场模拟程序_java 飞机大战 小游戏源码

    [实例简介] 本项目是一个使用java做的一个飞机大战的小游戏,一个英雄机,初始有三次生命,当打中蜜蜂会有一次生命奖励,当打中敌机会有相应分数奖励,但如果被敌机打中会失去一次生命机会.如果生命都失去, ...

  6. 《游戏学习》Java实现蜘蛛纸牌小游戏源码

    游戏截图 项目目录结构 蜘蛛牌 <关于>功能类 import javax.swing.*; import java.awt.*;/***"关于"窗口*/ public ...

  7. Java项目-坦克大战(附源码+文档)

    今天给小伙伴们分享一个坦克大战游戏的详细编写流程,即使你是刚入门java的新手,只要你简单掌握了该游戏所需要的javase基础知识,便可以跟随教程视频完成属于你自己的坦克大战游戏!同时还可以加深和巩固 ...

  8. JAVA开发坦克大战小游戏个人实战笔记

    1.认识frame类 a.这是一个窗口类 b.常用方法 setSize();## 标题//设置大小 setVisible();//显示窗口 setTitle();//设置标题 setResizable ...

  9. 射击小游戏源码《90坦克大战》源码H5+安卓+IOS三端源码

    cocos creator2.2.2射击小游戏源码<90坦克大战>源码H5+安卓+IOS三端源码,开发脚本为javaScript方便扩展和阅读,支持cocos creator2.X版本,完 ...

  10. 100行JS代码实现❤坦克大战js小游戏源码 HTML5坦克大战游戏代码(HTML+CSS+JavaScript )

    坦克大战js小游戏源码 HTML5坦克大战游戏代码(HTML+CSS+JavaScript ) HTML5坦克大战网页小游戏,完美还原小霸王学习机效果,以坦克战斗及保卫基地为主题,属于策略型类游戏. ...

最新文章

  1. firefox兼容性问题
  2. 前线解释多线程《二》
  3. SQL语句行列转换两种方法 case ...when 和pivot函数应用
  4. eigen 编译_头条 | 使用eigen实现四元数、欧拉角、旋转矩阵、旋转向量间的转换...
  5. .Net Core配置与自动更新
  6. 从客户端*****中检测到有潜在危险的 Request.Form 值。
  7. 诗与远方:无题(五十七)
  8. 从 ReactiveCocoa 中能学到什么?不用此库也能学以致用
  9. dfs.datanode.max.xcievers参数导致hbase集群报错
  10. Windows请求连接 Vmware+Ubuntu14被拒绝 的幽怨诉说
  11. Java加密算法(十一)——双向认证
  12. 添加native和java系统服务
  13. css就近原则_CSS的引入方式和优先级
  14. lingo入门教程之三 --- 文件数据处理
  15. win 10 企业版 激活
  16. 2022年mysql国家法定节假日脚本
  17. latex表格内上下边距调整
  18. 基于c语言的象棋游戏
  19. (十五:2020.08.28)CVPR 2013 追踪之论文纲要(译)
  20. Python小游戏贪吃蛇

热门文章

  1. PHP学习总结(二)
  2. 标题栏设置及自定义标题栏
  3. 【归档】网吧计费管理系统 C语言实现
  4. vi/vim查看空格、制表符等特殊符号
  5. Visual SourceSafe 使用说明
  6. win7性能服务器,性能大改善,微软Win10版本ca18301909即将推出,网友为何仍坚持win7?...
  7. svg和css3创建环形渐变进度条
  8. 【NBA之路】启蒙—to—詹皇—to—保罗乔治
  9. 最新麦子学院嵌入式开发系列培训教程
  10. 为什么uzi排到古手羽就秒_Uzi排到古手羽秒退引热议?“网友发表看法,弹幕疑似给出答案”...