一、系统简介
使用JAVA语言编写一个人机交互的游戏——坦克大战。该游戏由玩家和电脑双方操作,其中玩家有1辆坦克,但是玩家的坦克有三条命,电脑的坦克在第一关有3辆坦克,第二关有5辆坦克并且坦克的移动速度和子弹的移动速度会比第一关加快,因而难度增加,每一辆坦克只有一条生命。玩家可以通过键盘控制坦克进行移动和发射子弹,电脑坦克通过JAVA语言编写的线程和算法来控制它们自由运动并自动发射子弹,并且电脑的坦克不会重叠运动,当检测到电脑坦克中心距离小于h+15时,坦克会根据算法来改变方向。玩家坦克在没有进行任何操作的情况下处于无敌状态,一旦玩家坦克开始移动或者发射子弹的时候,玩家的坦克就取消无敌状态。玩家的坦克被电脑的坦克击中时有爆炸效果并丧失一条命,按下enter键时可以在原地复活玩家的坦克(前提是玩家的坦克三条生命未用尽),当玩家的坦克生命为0时,游戏就结束,当电脑的所有坦克死亡时,自动进入第二关玩家的坦克生命也会重置为3条生命,第二关所有电脑坦克死亡时玩家获得游戏胜利。
二、需求分析
利用JAVA语言实现人机图形交互界面的坦克大战游戏。坦克大战游戏涉及到图片的显示,按键检测,图形界面的设计,图形的设计,算法的设计,多线程操作等技术。
2.1 功能需求分析
游戏由玩家和电脑双方操作不同的坦克,坦克种类分为两种,即敌方坦克与我方坦克。我方坦克与子弹通过键盘来控制,而敌方坦克在存活的情况下,可随机自由移动,其中子弹也随机发射。而且我方坦克与敌方的移动都在活动范围内,敌方坦克将要触碰边界时随机自动转换方向,并且敌方坦克坦克也不能出现重叠的现象,即两坦克距离过近时,分别改变方向。
子弹:子弹也分为玩家坦克子弹和敌方坦克子弹,玩家坦克由玩家控制空格键发射;敌方坦克由敌方坦克随机发射。敌方子弹击中玩家坦克时会有爆炸效果子弹沿直线移动,且超出活动范围时,自动消失。
方向:坦克与子弹均有四个方向「上—0、下—1、左—2、右—3」,并且子弹的方向由坦克的方向决定。
2.2 界面需求分析
坦克大战中,为了能清晰的统计双方坦克的数量和生命,就在边界外画出统计的坦克。并且能让玩家更好的体验和操作,就在里面设计了游戏说明。游戏中为了美观,坦克被击败后能更好体验出爆炸效果,我们就引入图片并把图片画到游戏当中。坦克游戏开始界面也是很重要的,所以我们就设计坦克大战一直闪烁,直到单击开始游戏。
三、系统设计
3.1 游戏设计
3.2 UML类图设计
3.3 界面关系图
四、详细设计
Tank.java
1 package tankgames; 2 3 import java.awt.*; 4 import java.util.ArrayList; 5 6 //创建坦克类 7 public class Tank { 8 int x,y,w,h; 9 int speed; 10 int direct; 11 boolean isLive = true; 12 int life = 3; 13 Color c1,c2,c3; 14 15 public Tank(){ 16 x=250; 17 y=400; 18 w=5; 19 h=60; 20 speed=5; 21 direct=0; 22 23 } 24 25 public Tank(int x, int y, int w, int direct) { 26 super(); 27 this.x = x; 28 this.y = y; 29 this.w = w; 30 this.h =this.w*12; 31 this.speed = 5; 32 this.direct = direct; 33 } 34 } 35 36 //创建我的坦克子类 37 class MyTank extends Tank{ 38 //我的坦克数量 39 public int size = 3; 40 //判斷我的坦克是否处于无敌状态 41 public boolean invincible = true; 42 //创建颜色对象,并设置颜色 43 public MyTank(){ 44 this.c1 = new Color(128,128,128); 45 this.c2 = new Color(0,255,0); 46 this.c3 = new Color(0,0,255); 47 } 48 49 public MyTank(int x, int y, int w, int direct) { 50 super(x, y, w, direct); 51 this.c1 = new Color(128,128,128); 52 this.c2 = new Color(0,255,0); 53 this.c3 = new Color(0,0,255); 54 } 55 //创建子弹集合 56 ArrayList<Shot> ss = new ArrayList<Shot>(); 57 Shot s = null; 58 //创建子弹,并启动 59 public void shotEnemyTank(){ 60 //根据坦克的方向确定子弹方向和位置 61 switch(direct){ 62 case 0: s = new Shot((x-1)+4*w,y,direct);ss.add(s);break; 63 case 1: s = new Shot(x+h,(y-1)+4*w,direct);ss.add(s);break; 64 case 2: s = new Shot((x-1)+4*w,y+h,direct);ss.add(s);break; 65 case 3: s = new Shot(x,(y-1)+4*w,direct);ss.add(s);break; 66 } 67 Thread t = new Thread(s); 68 t.start(); 69 } 70 } 71 72 //敌人坦克类 73 class EnemyTank extends Tank implements Runnable{ 74 //敌人坦克的集合 75 ArrayList<EnemyTank> ets = new ArrayList<EnemyTank>(); 76 //敌人子弹的集合(静态子弹集合) 77 public static ArrayList<Shot> ss = new ArrayList<Shot>(); 78 public EnemyTank(){ 79 this.c1 = new Color(128,128,128); 80 this.c2 = new Color(0,255,0); 81 this.c3 = new Color(0,0,255); 82 } 83 84 public EnemyTank(int x, int y, int w, int direct) { 85 super(x, y, w, direct); 86 this.speed = 3; 87 this.c1 = new Color(200,200,120); 88 this.c2 = new Color(0,255,127); 89 this.c3 = new Color(200,0,0); 90 } 91 //获取MyPanel的敌人坦克集合 92 public void setEts(ArrayList<EnemyTank> ets){ 93 this.ets = ets; 94 } 95 //判断坦克之间有没有接触,有就改变方向 96 public boolean isTouchOtherTank(Tank t){ 97 for(int i=0;i<ets.size();i++){ 98 EnemyTank et = ets.get(i); 99 if(et != this){ 100 //判断et和当前坦克的距离,若距离<h+15,则改变方向 101 if(distance(t,et)<h+15){ 102 //距离小于坦克的长度+10时修改坦克的方向 103 //direct = (direct+1)%4; 104 return true; 105 } 106 } 107 } 108 return false; 109 } 110 //计算两坦克的距离 111 private int distance(Tank t1, Tank t2) { 112 Point p1,p2; 113 p1 = centerPoint(t1); 114 p2 = centerPoint(t2); 115 return (int)(Math.sqrt((p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y))); 116 } 117 //返回坦克的中心点 118 public Point centerPoint(Tank t){ 119 Point p = new Point(0,0); 120 if(t.direct == 0 || t.direct == 2){ 121 p.x = t.x+4*t.w; 122 p.y = t.y+6*t.w; 123 } 124 else if(t.direct == 1 || t.direct == 3){ 125 p.x = t.x+6*t.w; 126 p.y = t.y+4*t.w; 127 } 128 return p; 129 } 130 //让敌人坦克移动的线程 131 @Override 132 public void run() { 133 //让坦克运动 134 int num = 0; 135 Tank t; //t为移动后的坦克 136 while(true){ 137 t = new Tank(x,y,w,direct); 138 switch(t.direct){ 139 case 0:t.y -= this.speed;break; 140 case 1:t.x += this.speed;break; 141 case 2:t.y += this.speed;break; 142 case 3:t.x -= this.speed;break; 143 } 144 if(isTouchOtherTank(t)){ 145 changeDirect(); //若重叠则改变方向 146 } 147 else{ 148 x = t.x; 149 y = t.y; 150 } 151 if(num == 50 || isToBorder()){ 152 //当坦克沿着一个方向移动一段时间或到达边界后,就改变方向 153 num = 0; 154 changeDirect(); //改变坦克方向 155 } 156 num++; 157 try { 158 Thread.sleep(50); 159 } catch (Exception e) {} 160 //添加子弹 161 if(this.isLive && ss.size()<50 && num%10 == 0){ 162 Shot s = null; 163 switch(direct){ 164 case 0:s = new Shot((x-1)+4*w,y,direct);break; 165 case 1:s = new Shot(x+h,(y-1)+4*w,direct);break; 166 case 2:s = new Shot((x-1)+4*w,y+h,direct);break; 167 case 3:s = new Shot(x,(y-1)+4*w,direct);break; 168 } 169 ss.add(s); 170 Thread t1 = new Thread(s); 171 t1.start(); 172 } 173 } 174 } 175 //坦克改变方向 176 private void changeDirect() { 177 int d = (int)(Math.random()*4); 178 if(d == direct){ 179 direct = (direct+1)%4; 180 } 181 else 182 direct = d; 183 } 184 //判断坦克是否到达边界 185 private boolean isToBorder() { 186 switch (direct) { 187 case 0:if(y<4*w)return true;break; 188 case 1:if(x+h>600-4*w)return true;break; 189 case 2:if(y+h>500-4*w)return true;break; 190 case 3:if(x<4*w)return true;break; 191 } 192 return false; 193 } 194 } 195 196 //创建子弹类 197 class Shot implements Runnable{ 198 int x; 199 int y; 200 int direct; 201 int speed = 10; 202 boolean isLive = true; 203 204 public Shot(int x,int y,int direct){ 205 this.x = x; 206 this.y = y; 207 this.direct = direct; 208 } 209 210 //子弹自动移动 211 @Override 212 public void run() { 213 while(true){ 214 //子弹的线程,每50毫秒移动一次 215 try { 216 Thread.sleep(50); 217 } catch (Exception e) {} 218 //判断子弹的方向 219 switch(direct){ 220 case 0:y -= speed;break; 221 case 1:x += speed;break; 222 case 2:y += speed;break; 223 case 3:x -= speed;break; 224 } 225 //判断子弹的存活 226 if(x<=0||y<=0||x>=600||y>=500){ 227 isLive = false; 228 break; 229 } 230 } 231 } 232 }
TankGame.java
1 package tankgames; 2 3 import java.awt.*; 4 import java.awt.event.ActionEvent; 5 import java.awt.event.ActionListener; 6 import java.awt.event.KeyEvent; 7 import java.awt.event.KeyListener; 8 import java.util.ArrayList; 9 import javax.swing.*; 10 11 public class TankGame extends JFrame implements ActionListener{ 12 private static final long serialVersionUID = 1L; 13 14 boolean startnum = false;//判断是否第一次执行开始游戏菜单 15 MyPanel mp; 16 MyStartPanel msp = null; 17 // MyStartPanel myStartPanel = new MyStartPanel(); 18 JMenuBar jmb = null; //菜单条 19 JMenu jm1 = null; //菜单 20 JMenuItem jmi1 = null; //菜单项 21 22 public static void main(String[] args) { 23 new TankGame().setVisible(true); 24 25 } 26 27 public TankGame(){ 28 this.setTitle("坦克大战"); 29 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 30 this.setResizable(false); 31 this.setBounds(200, 50, 750, 650); 32 33 //创建我的开始面板对象,并添加到我的窗体里面 34 msp = new MyStartPanel(); 35 this.add(msp); 36 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 37 this.setVisible(true); 38 Thread t = new Thread(msp); 39 t.start(); 40 41 //创建菜单 42 jmb = new JMenuBar(); 43 jm1 = new JMenu("游戏(G)"); 44 jm1.setMnemonic('G'); //设置快捷键 45 jmi1 = new JMenuItem("开始新游戏(N)"); 46 jmi1.setMnemonic('N'); //快捷键 47 jm1.add(jmi1); //将菜单项添加到菜单中 48 jmb.add(jm1); //将菜单添加到菜单条中 49 this.setJMenuBar(jmb); //将菜单条添加到窗体中 50 51 //注册键盘事件监听 52 // this.addKeyListener(mp); 53 jmi1.addActionListener(this);//为开始新游戏菜单项注册监听 54 jmi1.setActionCommand("newgame");//设置其ActionCommand值为"newgame" 55 } 56 57 @Override 58 public void actionPerformed(ActionEvent e) { 59 if(e.getActionCommand().equals("newgame")){ 60 if(startnum){//如果不是第一次执行,则先清空敌人的坦克及其子弹 61 while(!mp.ets.isEmpty()){ 62 mp.ets.get(0).isLive = false; 63 mp.ets.get(0).life = 0; 64 mp.ets.remove(0); 65 // this.remove(mp); 66 } 67 while(!EnemyTank.ss.isEmpty()){ 68 EnemyTank.ss.get(0).isLive = false; 69 EnemyTank.ss.remove(0); 70 } 71 this.remove(mp);//移除上一次的游戏面板 72 } 73 else{ 74 this.remove(msp);//移除开始面板 75 } 76 startnum = true; 77 mp = new MyPanel(); 78 Thread t = new Thread(mp); 79 t.start(); 80 this.remove(msp); 81 this.add(mp); 82 this.addKeyListener(mp); 83 84 Tank et =mp.ets.get(0); 85 this.setVisible(true); 86 } 87 } 88 } 89 90 //创建开始面板 91 class MyStartPanel extends JPanel implements Runnable{ 92 int times = 0; //用于控制显示 93 public void paint(Graphics g){ 94 super.paint(g); 95 g.fillRect(0, 0, 750, 650); 96 //提示信息 97 if(times%2 == 0){ 98 g.setColor(Color.yellow); 99 //开关信息的字体 100 Font myFont = new Font("华文新魏",Font.BOLD,90); 101 g.setFont(myFont); 102 g.drawString("坦克大战", 180, 290); 103 } 104 } 105 @Override 106 public void run() { 107 while(true){ 108 try { 109 Thread.sleep(150); 110 } catch (Exception e) {} 111 times++; 112 //重画 113 this.repaint(); 114 } 115 } 116 } 117 118 //创建我的面板子类 119 class MyPanel extends JPanel implements KeyListener,Runnable{ 120 private static final long serialVersionUID = 1L; 121 int time = 0; 122 int level = 1;//用于进入第二关 123 int total = 0;//用于统计击中的敌人坦克总数 124 //我的坦克 125 MyTank myTank; 126 //敌人的坦克 127 public static int ensize = 3; 128 public static int ensize2 = 5; 129 ArrayList<EnemyTank> ets = new ArrayList<EnemyTank>(); 130 //爆炸的图片 131 Image image1 = null; 132 Image image2 = null; 133 Image image3 = null; 134 135 //将组件添加到面板容器里 136 public MyPanel(){ 137 this.setLayout(null); 138 //创建我的坦克 139 myTank = new MyTank(); 140 //创建敌人的坦克 141 for(int i=0;i<ensize;i++){ 142 EnemyTank et = new EnemyTank(50+i*150,10,5,2); 143 Thread t = new Thread(et); 144 t.start(); 145 ets.add(et); 146 et.setEts(ets); 147 } 148 //爆炸图片 149 image1 = Toolkit.getDefaultToolkit().getImage(this.getClass().getResource("bomb_1.gif")); 150 image2=Toolkit.getDefaultToolkit().getImage(this.getClass().getResource("bomb_2.gif")); 151 image3=Toolkit.getDefaultToolkit().getImage(this.getClass().getResource("bomb_3.gif")); 152 } 153 154 //在面板容器里画出组件 155 public void paint(Graphics g){ 156 super.paint(g); 157 //画边界 158 g.setColor(new Color(20,20,20)); 159 g.fill3DRect(0, 0, 600, 500, false); 160 //画我的坦克 161 if(myTank.isLive){ 162 drawTank(myTank,g); 163 } 164 else if(myTank.life>0){ 165 drawBomb(myTank, g); 166 } 167 // 画敌人的坦克 168 for (int i = 0; i < ets.size(); i++) { 169 EnemyTank et = ets.get(i); 170 if (et.isLive) { 171 drawTank(et, g); 172 // 画出敌人坦克的子弹 173 for (int j = 0; j < et.ss.size(); j++) { 174 Shot s = et.ss.get(j); 175 if (s.isLive) { 176 g.setColor(new Color(200, 0, 0)); 177 g.fill3DRect(s.x, s.y, 2, 2, false); 178 } else { 179 et.ss.remove(s); 180 } 181 } 182 } else if (et.life > 0) { 183 drawBomb(et, g); 184 } 185 else { 186 ets.remove(et); 187 } 188 } 189 //画出我的坦克子弹 190 for(int i=0;i<myTank.ss.size();i++){ 191 //从子弹集合中取出子弹 192 Shot myShot = myTank.ss.get(i); 193 //若子弹集不空,且子弹没有消失,画出子弹 194 if(myShot != null && myShot.isLive == true){ 195 g.setColor(new Color(0,0,150)); 196 g.draw3DRect(myShot.x, myShot.y, 2, 2, false); 197 } 198 //子弹消失,从子弹集中删除该子弹 199 else if(myShot != null && myShot.isLive == false){ 200 myTank.ss.remove(myShot); 201 } 202 } 203 //画爆炸效果 204 g.drawImage(image1, 0, 0, 1, 1,this); 205 //画出提示信息 206 this.showInfo(g); 207 //游戏说明 208 g.setColor(Color.black); 209 g.drawString("操作说明",615,250); 210 String str[] = { " 退出 ESC"," 向上 ↑ / W", " 向下 ↓ / S", " 向左 ← / A", " 向右 → / D", " 发射子弹 空格"," 原地复活 Enter" }; 211 for(int i=0;i<str.length;i++){ 212 g.drawString(str[i],605,280+30*i); 213 } 214 215 // 如果我的坦克三条命都用完,游戏结束 216 if (myTank.size == 0) { 217 for (int i = 0; i < ets.size(); i++) { 218 ets.remove(i); 219 } 220 g.setColor(Color.black); 221 g.fillRect(0, 0, 600, 500); 222 // 提示信息 223 if (time % 2 == 0)// 通过显示或不显示产生闪光效果 224 { 225 g.setColor(Color.red); 226 // 开关信息的字体 227 Font myFont = new Font("仿宋", Font.BOLD, 50); 228 g.setFont(myFont); 229 g.drawString("Game over!", 200, 250); 230 } 231 } 232 233 // 如果将敌人的坦克都击灭,进入到第二关 234 if (total == ensize && level == 1) { 235 236 myTank = new MyTank(); 237 // 创建敌人的坦克 238 for (int i = 0; i < ensize2; i++) { 239 EnemyTank et = new EnemyTank(15+i*100,10,5,2); 240 et.speed=5; 241 ets.add(et); 242 Thread t = new Thread(et); 243 t.start(); 244 // 将MyPanel的敌人坦克向量交给该敌人坦克 245 et.setEts(ets); 246 } 247 level = 0; 248 } 249 250 if (total == 3 + ensize2) { 251 g.setColor(Color.black); 252 g.fillRect(0, 0, 600, 500); 253 // 提示信息 254 if (time % 2 == 0)// 通过显示或不显示产生闪光效果 255 { 256 g.setColor(Color.CYAN); 257 // 开关信息的字体 258 Font myFont = new Font("仿宋", Font.BOLD, 50); 259 g.setFont(myFont); 260 g.drawString("胜利!!", 200, 250); 261 } 262 } 263 } 264 265 //画坦克 266 public void drawTank(Tank t,Graphics g){ 267 int x = t.x, y = t.y, w = t.w, h = 12*t.w; 268 //画出向上的坦克 269 if(t.direct == 0){ 270 Graphics2D g2d = (Graphics2D)g; 271 g.setColor(t.c1); 272 g.fill3DRect(x, y, w, h, false); 273 g.fill3DRect(x+7*w, y, w, h, false); 274 g.setColor(t.c2); 275 g.fill3DRect(x+w, y+2*w, 6*w, 8*w, false); 276 g.fillOval(x+2*w, y+4*w, 4*w, 4*w); 277 g2d.setColor(t.c3); 278 g2d.setStroke(new BasicStroke(5.0f)); 279 g2d.drawLine(x+4*w, y, x+4*w, y+6*w); 280 } 281 //画出向下的坦克 282 else if(t.direct == 2){ 283 Graphics2D g2d = (Graphics2D)g; 284 g.setColor(t.c1); 285 g.fill3DRect(x, y, w, h, false); 286 g.fill3DRect(x+7*w, y, w, h, false); 287 g.setColor(t.c2); 288 g.fill3DRect(x+w, y+2*w, 6*w, 8*w, false); 289 g.fillOval(x+2*w, y+4*w, 4*w, 4*w); 290 g2d.setColor(t.c3); 291 g2d.setStroke(new BasicStroke(5.0f)); 292 g2d.drawLine(x+4*w, y+6*w, x+4*w, y+12*w); 293 } 294 //画出向左的坦克 295 else if(t.direct == 3){ 296 Graphics2D g2d = (Graphics2D)g; 297 g.setColor(t.c1); 298 g.fill3DRect(x, y, h, w, false); 299 g.fill3DRect(x, y+7*w, h, w, false); 300 g.setColor(t.c2); 301 g.fill3DRect(x+2*w, y+w, 8*w, 6*w, false); 302 g.fillOval(x+4*w, y+2*w, 4*w, 4*w); 303 g2d.setColor(t.c3); 304 g2d.setStroke(new BasicStroke(5.0f)); 305 g2d.drawLine(x, y+4*w, x+6*w, y+4*w); 306 } 307 //画出向右的坦克 308 else if(t.direct ==1){ 309 Graphics2D g2d = (Graphics2D)g; 310 g.setColor(t.c1); 311 g.fill3DRect(x, y, h, w, false); 312 g.fill3DRect(x, y+7*w, h, w, false); 313 g.setColor(t.c2); 314 g.fill3DRect(x+2*w, y+w, 8*w, 6*w, false); 315 g.fillOval(x+4*w, y+2*w, 4*w, 4*w); 316 g2d.setColor(t.c3); 317 g2d.setStroke(new BasicStroke(5.0f)); 318 g2d.drawLine(x+6*w, y+4*w, x+12*w, y+4*w); 319 } 320 } 321 322 //判断子弹是否击中坦克 323 public boolean isHitTank(Shot s,Tank t){ 324 switch(t.direct){ 325 case 0: 326 case 2: 327 if(s.x>t.x&&s.x<t.x+8*t.w&&s.y>t.y&&s.y<t.y+t.h){ 328 s.isLive = false; 329 t.isLive = false; 330 return true; 331 } 332 break; 333 case 1: 334 case 3: 335 if(s.x>t.x&&s.x<t.x+t.h&&s.y>t.y&&s.y<t.y+8*t.w){ 336 s.isLive = false; 337 t.isLive = false; 338 return true; 339 } 340 break; 341 } 342 return false; 343 } 344 345 //判断我的子弹是否击中敌人的坦克 346 public void hitEnemyTank(){ 347 Shot s = null; 348 for(int i=0;i<myTank.ss.size();i++){ 349 s = myTank.ss.get(i); 350 if(s.isLive){ 351 for(int j=0;j<ets.size();j++){ 352 EnemyTank et =ets.get(j); 353 if(et.isLive){ 354 if(this.isHitTank(s, et)){ 355 total++; 356 } 357 } 358 } 359 } 360 } 361 } 362 //判断敌人坦克的子弹是否击中我的坦克 363 public boolean hitMyTank(){ 364 for(int i=0;i<ets.size();i++){ 365 EnemyTank et = ets.get(i); 366 for(int j=0;j<et.ss.size();j++){ 367 Shot s = et.ss.get(j); 368 if(myTank.isLive){ 369 if(isHitTank(s, myTank)){ 370 return true; 371 } 372 } 373 } 374 } 375 return false; 376 } 377 //画爆炸效果方法 378 public void drawBomb(Tank t ,Graphics g){ 379 if(t.life>2){ 380 g.drawImage(image1, t.x, t.y, 90, 90, this); 381 } 382 else if(t.life>1){ 383 g.drawImage(image2, t.x, t.y, 60, 60, this); 384 } 385 else if(t.life>0){ 386 g.drawImage(image3, t.x, t.y, 30, 30, this); 387 } 388 t.life--; 389 } 390 //画出提示信息 391 public void showInfo(Graphics g){ 392 g.drawString("剩余生命值", 10, 560); 393 //敌方tank剩余生命值 394 EnemyTank et=new EnemyTank(80,530,4,0); 395 this.drawTank(et, g); 396 int t = 0; 397 for (int i = 0; i < ets.size(); i++) { 398 EnemyTank et1 = ets.get(i); 399 if (et1.isLive) 400 t++; 401 } 402 g.drawString(t + "", 125, 560); 403 //myTank剩余生命值 404 MyTank mt = new MyTank(300, 530, 4, 0); 405 this.drawTank(mt, g); 406 g.drawString(myTank.size + "", 345, 560); 407 //my得分 408 mt.x = 630; 409 mt.y = 100; 410 this.drawTank(mt, g); 411 g.setColor(Color.red); 412 g.drawString("你的成绩为:", 620, 85); 413 g.drawString(total + "", 645, 180); 414 } 415 @Override 416 public void keyTyped(KeyEvent e) { 417 418 } 419 //我的坦克移动 420 @Override 421 public void keyPressed(KeyEvent e) { 422 //向左移动 423 if(e.getKeyCode() == KeyEvent.VK_LEFT || e.getKeyCode() == KeyEvent.VK_A && myTank.isLive){ 424 if(!(myTank.x<=0)){ 425 myTank.x -= myTank.speed; 426 myTank.direct = 3; 427 myTank.invincible = false; 428 } 429 else{ 430 myTank.x = myTank.x; 431 myTank.direct = 3; 432 } 433 } 434 //向右移动 435 else if(e.getKeyCode() == KeyEvent.VK_RIGHT || e.getKeyCode() == KeyEvent.VK_D && myTank.isLive){ 436 myTank.invincible = false; 437 if(myTank.x<600-myTank.h){ 438 myTank.x += myTank.speed; 439 myTank.direct = 1; 440 } 441 else{ 442 myTank.x = myTank.x; 443 myTank.direct = 1; 444 } 445 } 446 //向上移动 447 else if(e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_W && myTank.isLive){ 448 myTank.invincible = false; 449 if(!(myTank.y<=0)){ 450 myTank.y -= myTank.speed; 451 myTank.direct =0; 452 } 453 else{ 454 myTank.y = myTank.y; 455 myTank.direct = 0; 456 } 457 } 458 //向下移动 459 else if(e.getKeyCode() == KeyEvent.VK_DOWN || e.getKeyCode() == KeyEvent.VK_S && myTank.isLive){ 460 myTank.invincible = false; 461 if(myTank.y<500-myTank.h){ 462 myTank.y += myTank.speed; 463 myTank.direct = 2; 464 } 465 else{ 466 myTank.y = myTank.y; 467 myTank.direct = 2; 468 } 469 } 470 //发射子弹 471 else if(e.getKeyCode() == KeyEvent.VK_SPACE && myTank.isLive){ 472 //最多可连发5枚子弹 473 if(myTank.ss.size() < 5){ 474 myTank.shotEnemyTank(); 475 myTank.invincible = false; 476 } 477 } 478 //关闭游戏 479 else if(e.getKeyCode() == KeyEvent.VK_ESCAPE){ 480 System.exit(0); 481 } 482 //按回車鍵,我的坦克原地復活 483 else if(e.getKeyCode() == KeyEvent.VK_ENTER && myTank.isLive == false && myTank.size>0){ 484 myTank.isLive = true; 485 myTank.life = 3; 486 myTank.invincible = true; 487 } 488 //刷新图形 489 this.repaint(); 490 } 491 492 @Override 493 public void keyReleased(KeyEvent e) {} 494 495 @Override 496 public void run() { 497 while(true){ 498 try { 499 Thread.sleep(100); 500 } catch (Exception e) {} 501 if(myTank.isLive && myTank.invincible == false){ 502 //击中目标坦克 503 this.hitEnemyTank(); 504 //敌人坦克击中我的坦克 505 if(this.hitMyTank()){ 506 myTank.size--; 507 } 508 } 509 time++; 510 //重绘 511 this.repaint(); 512 } 513 } 514 }
五、运行结果
github下载地址:https://github.com/HCychao