本系列校训
互相伤害互相卷,玩命学习要你管,天生我才必有用,我命由我不由天!
毕业论文不怕难,毕业设计来铺垫!打磨技术精心写,拿证之后尽开颜!
毕设的技术铺垫
语言选择 | 收录专辑链接 | 卷的程度 |
C | 张雪峰推荐选择了计算机专业之后-在大学期间卷起来-【大学生活篇】 | ★★★✫✰ |
JAVA | 黑马B站视频JAVA部分的知识范围、学习步骤详解 | ★★★★★ |
JAVAWEB | 黑马B站视频JAVAWEB部分的知识范围、学习步骤详解 | ★★★★★ |
SpringBoot | SpringBoot知识范围-学习步骤【JSB系列之000】 | ★★★★★ |
微信小程序 | 详细解析黑马微信小程序视频–【思维导图知识范围】 | ★★★✰✰ |
python | 详细解析python视频选择–【思维导图知识范围】 | ★★✫✰✰ |
php | PHP要怎么学–【思维导图知识范围】 | ★★★✫✰ |
环境及工具:
本系列环境
环境 | win11 |
工具 | idea 2017 |
jdk | 1.8 |
数据库 | 无 |
maven | 无 |
项目导入方式 | 打开目录 |
数据库前端工具 | 无 |
项目说明
总体设计
总体功能
表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 创建普通墙并设置属性 1、需要有图形用户界面,让用户能看到游戏给出的反馈。
2、不同队伍的坦克,须显示不同的外观,以区分敌我。 3、坦克能够开火,攻击敌方,但不能攻击队友。
4、需要有不可被子弹穿透的墙体,以及墙体有可被摧毁和不可被摧毁两种。 5、敌方坦克有生命值,并非被击中一次就会爆炸。
6、游戏结束时会有胜利或失败场景 7、游戏结束后可重新开始。
本毕业设计功能如图1所示
坦克大战总体流程图
详细设计
放关键代码
- 基地的设计
- 敌方坦克的设计
- 河道、草坪的设计
- 墙与铁墙的设计
- 界面窗口的创建
- 子弹功能设计
- 坦克功能设计
- 服务器设计
- 其他各设计
代码部分
文件编码问题。
服务端
项目文件目录如下:
关键代码:
import java.net.*; import java.io.*; import java.awt.event.*; import java.awt.*; public class ServerModel implements ActionListener{ //视图参考 public ServerView view; //连接变量 public ServerSocket serverSocket; public Socket clientSocket; public PrintWriter out; public BufferedReader in; public String inputLine, outputLine; //服务器状态 public boolean serverCreated; public boolean clientConnected; public boolean gameStarted; public boolean gamePaused; public boolean gameOver; public boolean serverVoteYes, serverVoteNo; public boolean clientVoteYes, clientVoteNo; public boolean pausePressed; //游戏消息 public String[] messageQueue; public int messageIndex; public String playerTypedMessage = ""; //实际的游戏在这个线程上运行,而主线程监听用户的输入 public Ticker t; public Image[] textures; //游戏变量 public static int gameFlow; public Actor[] actors; public player P1; //由服务器玩家控制的坦克 public player P2; //有客户端玩家控制的坦克 public ServerModel(ServerView thisview){ view = thisview; messageQueue = new String[8]; view.mainPanel.messageQueue = messageQueue; addMessage("欢迎来到坦克大战主机端! 请点击\"建立主机\"按钮开始游戏" ); t = new Ticker(1000); t.addActionListener(this); } 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 actionPerformed(ActionEvent e){ //TODO 这里可以加入限定时间 ,过期则不可以玩。 createServer(); //如果程序未能创建服务器,则什么也不做 if(!serverCreated) return; //游戏逻辑回路, try{ while((inputLine = in.readLine()) != null){ //处理客户反馈消息 feedbackHandler.handleInstruction(this, inputLine); outputLine = ""; if(!gamePaused) gameFlow++; if(pausePressed){ if(!gamePaused){ outputLine+= "x0;"; }else{ outputLine+= "x1;"; } pausePressed = false; } if(gameOver || (P1.life == 0 && P2.life == 0)){ if(P1.freezed != 1) outputLine+="a;"; if((P1.freezed != 1 || messageIndex == 1) && serverVoteYes){ addMessage("等待用户端玩家的回应..."); } if(P1.freezed != 1 || messageIndex == 0){ addMessage("GAME OVER ! 想再玩一次吗 ( y / n ) ?"); } gameOver = true; P1.freezed = 1; P2.freezed = 1; if(serverVoteNo && !serverVoteYes) System.exit(0); if(serverVoteYes){ outputLine+="j;"; if(clientVoteYes){ addMessage("用户端玩家决定再玩一次,游戏重新开始了..."); //重新启动游戏 P1 = new player("1P", this); P2 = new player("2P", this); level.reset(); level.loadLevel(this); gameOver = false; serverVoteYes = false; clientVoteYes = false; serverVoteNo = false; enemy.freezedMoment = 0; enemy.freezedTime = 0; gameFlow = 0; //告诉客户端程序重新启动游戏 outputLine+="L1;"; } } } if(level.deathCount == 20 && !gameOver){ level.winningCount++; if(level.winningCount == 120){ P1.freezed = 1; P2.freezed = 1; } if(level.winningCount == 470){ if(P1.life > 0) P1.reset(); if(P2.life > 0) P2.reset(); level.loadLevel(this); //告诉客户端程序加载下一关 outputLine+="L" +(1 + (level.currentLevel-1)%8) + ";"; } if(level.winningCount == 500){ P1.freezed = 0; P2.freezed = 0; level.deathCount = 0; level.winningCount = 0; } } //大量生产敌人坦克 if(!gamePaused) level.spawnEnemy(this); for(int i = 0; i < actors.length; i++){ if(actors[i] != null) actors[i].move(); } //从消息队列中删除一个消息每10秒,(如果有的话) if(gameFlow%300 == 0) removeMessage(); //将玩家、关卡的信息写入输出行 outputLine+="p" + level.enemyLeft + "," + level.currentLevel + "," + P1.life + "," + P1.scores + "," + P2.life + "," + P2.scores +";"; outputLine+="g" + level.winningCount + ";"; //将玩家类型信息写入输出行 if(!playerTypedMessage.equals("")){ outputLine+=playerTypedMessage; playerTypedMessage = ""; } //将最后的指令字符串发送到客户端程序 out.println(outputLine); //调用视图重绘本身 view.mainPanel.repaint(); //如果玩家切换到对话框模式,则停止所有坦克动作 if(!view.mainPanel.hasFocus()){ P1.moveLeft = false; P1.moveUp = false; P1.moveDown = false; P1.moveRight = false; P1.fire = false; } Thread.sleep(30); } }catch(Exception ex){ ex.printStackTrace(); view.messageField.setEnabled(false); serverVoteYes= false; serverVoteNo = false; clientVoteYes = false; serverCreated = false; gameStarted = false; gameOver = false; gameFlow = 0; enemy.freezedTime = 0; enemy.freezedMoment = 0; view.mainPanel.gameStarted = false; t.stop(); addMessage("玩家退出了,请重新建立主机"); //当发生错误在游戏中,摧毁任何东西,包括游戏的变量 try{ out.close(); in.close(); clientSocket.close(); serverSocket.close(); }catch(Exception exc){} //破坏游戏数据 P1 = null; P2 = null; level.reset(); } } //添加游戏对象(如坦克,子弹等..)到游戏系统 public void addActor(Actor actor){ for(int i = 0; i < actors.length; i ++ ) if(actors[i] == null){ actors[i] = actor; break; } } //从游戏系统中移除游戏对象 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; } //调用视图重绘屏幕如果游戏有没有开始 if(!gameStarted) view.mainPanel.repaint(); } //删除屏幕上最早的信息 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(); } }
控制的部分。
import javax.swing.*; import java.awt.event.*; //这个类处理来自服务器视图的输入 public class ServerControler{ public ServerView view; public ServerModel model; public int helpMessageCount = 1; //一个玩家坦克的参考 public ServerControler(ServerView thisview, ServerModel thismodel){ view = thisview; model = thismodel; //操作发送消息按钮的动作 view.sendMessage.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent 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("对话内容不能为空"); } } } ); //操作建立主机按钮的动作 view.createServer.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { if(!model.serverCreated) model.t.start(); } } ); //操作暂停/继续按钮的动作 view.pauseAndResume.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { model.pausePressed = true;; if(!model.gameOver && model.gameStarted){ if(!model.gamePaused){ model.gamePaused = true; model.addMessage("主机端玩家暂停了游戏"); }else{ model.gamePaused = false; model.addMessage("主机端玩家取消了暂停"); } } } } ); //操作帮助按钮的动作 view.help.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { model.addMessage("-------------------------------坦克大战 1.0-----------------------------------"); model.addMessage("帮助: 按 s 键开火, 按键盘的方向键来控制坦克的移动"); model.addMessage("如果按键没有反应请 1. 关闭大写功能; 2. 用 tab键切换 "); model.addMessage("到控制界面如果您在使用对话界面."); model.addMessage("--------------------------------------------------------------------------------------"); } } ); //操作退出按钮的动作 view.exit.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { System.exit(0); } } ); //操作输入按钮的动作 view.messageField.addKeyListener( new KeyAdapter(){ public void keyPressed(KeyEvent e){ if(helpMessageCount > 0){ model.addMessage("提示:用\"tab\"键可以自由切换于控制界面和对话界面"); model.addMessage("提示:按回车键可以直接发送您的对话"); helpMessageCount--; } if(e.getKeyCode()==e.VK_ENTER){ if(!view.messageField.getText().equals("")){ model.addMessage("主机端玩家说:" + view.messageField.getText()); model.playerTypedMessage += "m" + view.messageField.getText() + ";"; view.messageField.setText(""); }else{ model.addMessage("对话内容不能为空"); } } } }); JPanel temp = view.mainPanel; temp.addKeyListener( new KeyAdapter(){ public void keyPressed(KeyEvent e){ if(model.P1 != null){ if(e.getKeyCode() == KeyEvent.VK_UP){ model.P1.moveUp = true; model.P1.moveDown = false; model.P1.moveLeft = false; model.P1.moveRight = false; } if(e.getKeyCode() == KeyEvent.VK_DOWN ){ model.P1.moveDown = true; model.P1.moveUp = false; model.P1.moveLeft = false; model.P1.moveRight = false; } if(e.getKeyCode() == KeyEvent.VK_LEFT ){ model.P1.moveLeft = true; model.P1.moveUp = false; model.P1.moveDown = false; model.P1.moveRight = false; } if(e.getKeyCode() == KeyEvent.VK_RIGHT ){ model.P1.moveLeft = false; model.P1.moveUp = false; model.P1.moveDown = false; model.P1.moveRight = true; } if(e.getKeyChar() == 's') model.P1.fire = true; if(e.getKeyCode()==e.VK_ENTER){ if(!view.messageField.getText().equals("")){ model.addMessage("主机端玩家说:" + view.messageField.getText()); model.playerTypedMessage += "m" + view.messageField.getText() + ";"; view.messageField.setText(""); } } if(e.getKeyChar() == 'y' && model.gameOver && !model.serverVoteYes){ model.serverVoteYes = true; model.addMessage("等待用户端玩家的回应..."); } if(e.getKeyChar() == 'n' && model.gameOver) model.serverVoteNo = true; } } public void keyReleased(KeyEvent e){ if(model.P1 != null){ if(e.getKeyCode() == KeyEvent.VK_UP) model.P1.moveUp = false; if(e.getKeyCode() == KeyEvent.VK_DOWN ) model.P1.moveDown = false; if(e.getKeyCode() == KeyEvent.VK_LEFT ) model.P1.moveLeft = false; if(e.getKeyCode() == KeyEvent.VK_RIGHT ) model.P1.moveRight = false; if(e.getKeyChar() == 's') model.P1.fire = false; } } } ); } }
服务端界面
一定要建立主机之后,客户端才可以连接
客户端
控制的部分
import javax.swing.*; import java.awt.event.*; //Download:http://www.codefans.net //这个类处理来自客户端视图框架的输入 public class ClientControler{ public boolean serverConnected;; public boolean gameStarted; public boolean gamePaused; public ClientView view; public ClientModel model; public int helpMessageCount = 1; public ClientControler(ClientView thisview, ClientModel thismodel){ view = thisview; model = thismodel; //发送消息按钮操作 view.sendMessage.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { if(!model.gameStarted){ model.addMessage("还没有和主机端玩家联上, 无法发送对话"); return; } if(!view.messageField.getText().equals("")){ model.addMessage("用户端玩家说:" + view.messageField.getText()); model.playerTypedMessage += "e" + view.messageField.getText() + ";"; view.messageField.setText(""); }else{ model.addMessage("对话内容不能为空"); } } } ); //handel connectServer按钮操作 view.connectServer.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { if(!model.serverConnected){ model.serverIP = view.IPfield.getText(); model.t.start(); } } } ); //handel pauseAndResume 按钮操作 view.pauseAndResume.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { if(!model.gameOver && model.gameStarted){ model.pausePressed = true; if(!model.gamePaused){ model.gamePaused = true; model.addMessage("用户端玩家暂停了游戏"); }else{ model.gamePaused = false; model.addMessage("用户端玩家取消了暂停"); } } } } ); //handel help 按钮操作 view.help.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { model.addMessage("******************************坦克大战 ******************************"); model.addMessage("帮助: 按s键发射子弹,按键盘的方向键来控制坦克的移动"); model.addMessage("如果按键没有反应请 1. 关闭大写功能; 2. 用 tab键切换 "); model.addMessage("如果您在使用对话界面请移动到控制界面."); model.addMessage("********************************************************************************"); } } ); //handel exit 按钮操作 view.exit.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { System.exit(0); } } ); //处理从键盘输入 view.messageField.addKeyListener( new KeyAdapter(){ public void keyPressed(KeyEvent e){ if(helpMessageCount > 0){ model.addMessage("提示:用\"tab\"键可以自由切换于控制界面和对话界面"); model.addMessage("提示:按回车键可以直接发送您的对话"); helpMessageCount--; } if(e.getKeyCode()==e.VK_ENTER){ if(!view.messageField.getText().equals("")){ model.addMessage("用户端玩家说:" + view.messageField.getText()); model.playerTypedMessage += "e" + view.messageField.getText() + ";"; view.messageField.setText(""); }else{ model.addMessage("对话内容不能为空"); } } } }); JPanel temp = view.mainPanel; temp.addKeyListener( new KeyAdapter(){ public void keyPressed(KeyEvent e){ if(e.getKeyCode() == KeyEvent.VK_UP){ model.moveUp = true; model.moveDown = false; model.moveLeft = false; model.moveRight = false; } if(e.getKeyCode() == KeyEvent.VK_DOWN ){ model.moveDown = true; model.moveUp = false; model.moveLeft = false; model.moveRight = false; } if(e.getKeyCode() == KeyEvent.VK_LEFT ){ model.moveLeft = true; model.moveUp = false; model.moveDown = false; model.moveRight = false; } if(e.getKeyCode() == KeyEvent.VK_RIGHT ){ model.moveLeft = false; model.moveUp = false; model.moveDown = false; model.moveRight = true; } if(e.getKeyChar() == 's') model.fire = true; if(e.getKeyCode()==e.VK_ENTER){ if(!view.messageField.getText().equals("")){ model.addMessage("用户端玩家说:" + view.messageField.getText()); model.playerTypedMessage += "e" + view.messageField.getText() + ";"; view.messageField.setText(""); } } if(e.getKeyChar() == 'y' && model.gameOver && !model.clientVoteYes){ model.clientVoteYes = true; model.addMessage("等待主机端玩家回应..."); } if(e.getKeyChar() == 'n' && model.gameOver) model.clientVoteNo = true; } public void keyReleased(KeyEvent e){ if(e.getKeyCode() == KeyEvent.VK_UP) model.moveUp = false; if(e.getKeyCode() == KeyEvent.VK_DOWN ) model.moveDown = false; if(e.getKeyCode() == KeyEvent.VK_LEFT ) model.moveLeft = false; if(e.getKeyCode() == KeyEvent.VK_RIGHT ) model.moveRight = false; if(e.getKeyChar() == 's') model.fire = false; } } ); }
界面
连接主机之后进入游戏
上下左右,控制坦克,S发射 子弹
论文参考
《基于java的坦克大战游戏的设计与实现–毕业论文–【毕业论文】》
https://blog.csdn.net/dearmite/article/details/131962993
配套资源
基于java的坦克大战游戏的设计与实现–源代码–【毕业设计】
client
https://download.csdn.net/download/dearmite/88112811
server