最近学习了马士兵老师直播的单机版坦克大战,模仿的做了一个,整理一下思路记录下来,项目git地址:https://github.com/zhuchangli/TankWar/tree/master
视频地址:https://www.bilibili.com/video/av5949029
TankClient类:管理其他类,作为主程序的接口,
1 package cc.openhome; 2 3 import java.awt.*; 4 import java.awt.event.KeyAdapter; 5 import java.awt.event.KeyEvent; 6 import java.awt.event.WindowAdapter; 7 import java.awt.event.WindowEvent; 8 import java.util.ArrayList; 9 import java.util.List; 10 11 12 /** 13 * @Description: 坦克大战主界面 14 * @author zili_zl 15 */ 16 public class TankClient extends Frame{ 17 18 /** 19 * 整个游戏宽度 20 */ 21 public static final int GAME_WIDTH = 800; 22 public static final int GAME_HEIGHT = 600; 23 public final int bknum = 5; 24 25 // 解决画面加载卡顿问题 26 Image offScreenImage = null; 27 28 Tank mytank = new Tank(500,500,true, Tank.Direction.STOP,this); 29 30 Wall wall = new Wall(300,300,this); 31 32 Blood b = new Blood(); 33 // 存储多发炮弹 34 List<Missile> missiles = new ArrayList<Missile>(); 35 // 存储爆炸 36 List<Explode> explodes = new ArrayList<Explode>(); 37 // 存储tank 38 List<Tank> tanks = new ArrayList<Tank>(); 39 40 41 /** 42 * Description 43 * date: 3:57 PM 1/6/19 44 * @param g 画笔显示在屏幕上画出一些对象 45 * @return void 46 * 47 **/ 48 49 public void paint(Graphics g){ 50 51 // 在屏幕上显示一些文字,有提示的文字 52 g.drawString("missiles count: "+missiles.size(),10,60); 53 g.drawString("explodes count: "+explodes.size(),10,80); 54 g.drawString("tanks count: "+tanks.size(),10,100); 55 g.drawString("mytank life: "+mytank.getLife(),10,120); 56 57 // 敌方所有坦克报废后重新生成一批坦克 58 if(tanks.size()<= 0){ 59 for(int i = 0;i < bknum;i++){ 60 Tank tk = new Tank(50 + (i + 1) * 50,100,false, Tank.Direction.D,this); 61 tanks.add(tk); 62 } 63 } 64 65 // 拿出所有的子弹 66 for(int i = 0;i < missiles.size();i++){ 67 Missile m = missiles.get(i); 68 // 子弹击打敌方 69 m.hitTanks(tanks); 70 // 子弹攻击自己 71 m.hitTank(mytank); 72 73 // 判断子弹是否撞墙 74 m.collidesWithWall(wall); 75 // 第一种解决用bool值解决 76 /* 77 if(!m.isLive()){ 78 missiles.remove(m); 79 }else { 80 m.draw(g); 81 } 82 */ 83 // 画出子弹 84 m.draw(g); 85 } 86 87 // 产生爆炸逐个画出来 88 for(int i = 0;i < explodes.size();i++){ 89 Explode ex = explodes.get(i); 90 ex.draw(g); 91 } 92 // 拿出生成的tank 93 for(int i = 0; i < tanks.size();i++){ 94 Tank t = tanks.get(i); 95 // 坦克撞墙 96 t.collidesWithWall(wall); 97 // 同一个tank相遇 98 t.collidesWithTanks(tanks); 99 t.draw(g); 100 } 101 // 画出墙来 102 wall.draw(g); 103 // tank吃血补充生命值 104 mytank.eatBlood(b); 105 mytank.draw(g); 106 b.draw(g); 107 } 108 109 /** 110 * @Description: 使用update方法 实现双缓冲 111 * @param: [g] 112 * @return: void 113 */ 114 115 public void update(Graphics g){ 116 // 保证只生成背景色一次 117 if(offScreenImage == null){ 118 offScreenImage = this.createImage(GAME_WIDTH,GAME_HEIGHT); 119 120 } 121 // 幕后图片,调用paint在画布上作画 122 Graphics gOffScreen = offScreenImage.getGraphics(); 123 124 // 背景重刷, 重擦 125 Color c = gOffScreen.getColor(); // 获取当前颜色 126 gOffScreen.setColor(Color.GREEN); // 设置颜色为颜色绿色 127 gOffScreen.fillRect(0,0,GAME_WIDTH,GAME_HEIGHT); // 画一个 800×600的方块,颜色黑色 128 gOffScreen.setColor(c); // 刷完之后把颜色改回去 129 paint(gOffScreen); 130 //一次把图片画的前面去 131 g.drawImage(offScreenImage,0,0,null); 132 133 } 134 135 /** 136 * @Description: 做一些初始化工作,只调用一次 137 * @param: [] 138 * @return: void 139 */ 140 public void lauchFram(){ 141 142 // 在未画之前开始生成tank 143 for(int i = 0;i < 10;i++){ 144 Tank tk = new Tank(50 + (i + 1) * 50,100,false, Tank.Direction.D,this); 145 tanks.add(tk); 146 } 147 148 this.setLocation(400,300); // 打开画面相对屏幕的坐标位置和屏幕的大小 149 this.setSize(GAME_WIDTH,GAME_HEIGHT); // 设置游戏画面的长度和高度 150 this.setTitle("TankWar"); // 游戏界面标题值 151 152 // 关闭点击叉号起作用的 153 this.addWindowListener(new WindowAdapter() { 154 @Override 155 public void windowClosing(WindowEvent e) { 156 System.exit(0); 157 } 158 }); 159 160 this.setResizable(false); // 固定画面大小,不可以改变大小 161 this.setBackground(Color.GREEN); // 设置草地颜色 162 setVisible(true); // 设置可见性 163 164 // 添加键盘监听 165 this.addKeyListener(new TankClient.KeyMonitor()); 166 167 // 开启一个线程去画一些对象 168 new Thread(new TankClient.PaintThread()).start(); 169 } 170 171 public static void main(String [] args){ 172 TankClient tc = new TankClient(); 173 tc.lauchFram(); 174 } 175 176 /** 177 * @Description: 重画方法,让线程工作 178 * @param: 179 * @return: 180 */ 181 private class PaintThread implements Runnable{ 182 183 @Override 184 public void run() { 185 while (true){ 186 repaint(); 187 try{ 188 Thread.sleep(100); 189 }catch (InterruptedException e){ 190 e.printStackTrace(); 191 } 192 } 193 } 194 } 195 196 /** 197 * @Description: 监听键盘事件 198 * @param: 199 * @return: 200 */ 201 private class KeyMonitor extends KeyAdapter { 202 public void keyPressed(KeyEvent e) { 203 mytank.keyPressed(e); 204 } 205 206 public void keyReleased(KeyEvent e) { 207 mytank.keyReleased(e); 208 } 209 } 210 }
Tank类:
1 package cc.openhome; 2 3 import java.awt.*; 4 import java.awt.event.KeyEvent; 5 import java.util.List; 6 import java.util.Random; 7 8 /** 9 * 10 * @Description 坦克类 11 * @Author zizl_zq 12 * @Date 1/6/19 3:51 PM 13 */ 14 public class Tank { 15 16 // tank 生命值 17 public static final int LIFETIME = 100; 18 // 移动的速度 19 public static final int xSpeed = 5; 20 public static final int ySpeed = 5; 21 22 // tank 的宽度 23 public static final int WIDTH = 30; 24 public static final int HEIGHT = 30; 25 26 int x ,y; 27 private boolean bL = false; 28 private boolean bR = false; 29 private boolean bU = false; 30 private boolean bD = false; 31 enum Direction {L,LU,U,RU,R,RD,D,LD,STOP}; // 有八个移动方向和停止 32 33 private Direction dir = Direction.STOP; // tank的方向 34 private Direction ptdir = Direction.D; // 炮筒的方向 35 36 private TankClient tkc; 37 38 private int oldx,oldy; 39 40 private boolean good; 41 42 private BloodBar bb = new BloodBar(); // 显示声明值进度条 43 44 /** 45 * @Description: tank 分敌方和我方tank 46 * @param: [] 47 * @return: boolean 48 */ 49 public boolean isGood() { 50 return good; 51 } 52 // 产生随机数 static 只产生一份,是共享变量 53 private static Random r = new Random(); 54 55 public void setLive(boolean live) { 56 this.live = live; 57 } 58 59 /** 60 * @Description: 当tank撞在墙上是需要停下来的,在撞见墙的上一步开始停下来改变方向 61 * @param: [] 62 * @return: void 63 */ 64 public void stay(){ 65 x = oldx; 66 y = oldy; 67 } 68 69 public boolean isLive() { 70 return live; 71 } 72 73 private boolean live = true; 74 // 产生移动的步长 75 private int step = r.nextInt(12) + 3; 76 77 // 生命值 78 private int life = 100; 79 80 public int getLife() { 81 return life; 82 } 83 84 public void setLife(int life) { 85 this.life = life; 86 } 87 88 public Tank(int x,int y,boolean good){ 89 this.x = x; 90 this.y = y; 91 this.good = good; 92 } 93 public Tank(int x, int y, boolean good, Direction dir, TankClient tkc){ 94 this(x,y,good); 95 this.dir = dir; 96 this.tkc = tkc; 97 } 98 99 /** 100 * @Description: 画tank 101 * @param: [g] 102 * @return: void 103 */ 104 public void draw(Graphics g){ 105 if(!live) { 106 if(!good){ 107 tkc.tanks.remove(this); 108 } 109 return; 110 } 111 Color c = g.getColor(); // 保存以前颜色 112 if(good) g.setColor(Color.red); // 玩家tank画成红色 113 else g.setColor(Color.blue); // 敌方tank画成蓝色 114 115 // 坐标四个参数,确定图案大小 116 g.fillOval(x,y,WIDTH,HEIGHT); 117 g.setColor(c); 118 119 if(good) bb.draw(g); 120 // 画炮筒 121 switch (ptdir ){ 122 case L: 123 g.drawLine(x+Tank.WIDTH / 2,y + Tank.HEIGHT / 2,x,y + Tank.HEIGHT / 2); 124 break; 125 case LU: 126 g.drawLine(x+Tank.WIDTH / 2,y + Tank.HEIGHT / 2,x,y ); 127 break; 128 case U: 129 g.drawLine(x+Tank.WIDTH / 2,y + Tank.HEIGHT / 2,x + Tank.WIDTH / 2,y); 130 break; 131 case RU: 132 g.drawLine(x+Tank.WIDTH / 2,y + Tank.HEIGHT / 2,x + Tank.WIDTH,y); 133 break; 134 case R: 135 g.drawLine(x+Tank.WIDTH / 2,y + Tank.HEIGHT / 2,x + Tank.WIDTH ,y + Tank.HEIGHT /2); 136 break; 137 case RD: 138 g.drawLine(x+Tank.WIDTH / 2,y + Tank.HEIGHT / 2,x + Tank.WIDTH,y + Tank.HEIGHT ); 139 break; 140 case D: 141 g.drawLine(x+Tank.WIDTH / 2,y + Tank.HEIGHT / 2,x + Tank.WIDTH /2,y + Tank.HEIGHT); 142 break; 143 case LD: 144 g.drawLine(x+Tank.WIDTH / 2,y + Tank.HEIGHT / 2,x,y + Tank.HEIGHT); 145 break; 146 } 147 // 移动 148 move(); 149 } 150 151 /** 152 * @Description: 根据方向来确定行进方向 153 * @param: [] 154 * @return: void 155 */ 156 void move(){ 157 this.oldx = x; 158 this.oldy = y; 159 switch (dir ){ 160 case L: 161 x -= xSpeed; 162 break; 163 case LU: 164 x -= xSpeed; 165 y -= ySpeed; 166 break; 167 case U: 168 y -= ySpeed; 169 break; 170 case RU: 171 x += xSpeed; 172 y -= ySpeed; 173 break; 174 case R: 175 x += xSpeed; 176 break; 177 case RD: 178 x += xSpeed; 179 y += ySpeed; 180 break; 181 case D: 182 y += ySpeed; 183 break; 184 case LD: 185 x -= xSpeed; 186 y += ySpeed; 187 break; 188 case STOP: 189 break; 190 } 191 // 炮筒方向,解决静止也能发炮 192 if(dir != Direction.STOP){ 193 ptdir = dir; 194 } 195 196 // 限制tank 不能越界 197 if(x < 0) x = 0; 198 if(y < 30) y = 30; 199 if(x + Tank.WIDTH > TankClient.GAME_WIDTH) x = TankClient.GAME_WIDTH - Tank.WIDTH; 200 if(y + Tank.HEIGHT > TankClient.GAME_HEIGHT) y = TankClient.GAME_HEIGHT - Tank.HEIGHT; 201 202 // 敌方tank在八个方向里面随机选择方向,找出下一步移动方向 203 if(!good){ 204 // enum 转换为数组 205 Direction [] dirs = Direction.values(); 206 if(step == 0){ 207 step = r.nextInt(12) + 3; 208 int rn = r.nextInt(dirs.length); 209 dir = dirs[rn]; 210 } 211 step--; 212 // 解决子弹发射太快问题 这个条件下发射一枚炮弹 213 if(r.nextInt(40) > 38) fire(); 214 215 } 216 217 } 218 219 /** 220 * @Description: 键盘按下事件 221 * @param: [e] 222 * @return: void 223 */ 224 public void keyPressed(KeyEvent e) { 225 int key = e.getKeyCode(); 226 switch (key){ 227 case KeyEvent.VK_LEFT: 228 bL = true; 229 break; 230 case KeyEvent.VK_RIGHT: 231 bR = true; 232 break; 233 case KeyEvent.VK_UP: 234 bU = true; 235 break; 236 case KeyEvent.VK_DOWN: 237 bD = true; 238 break; 239 } 240 locateDirection(); 241 } 242 243 /** 244 * @Description: 处理松开按键事件 245 * @param: [e] 246 * @return: void 247 */ 248 public void keyReleased(KeyEvent e){ 249 int key = e.getKeyCode(); 250 switch (key){ 251 case KeyEvent.VK_F2: 252 if(good){ 253 this.live = true; 254 this.life = LIFETIME; 255 } 256 case KeyEvent.VK_CONTROL: // control键发射炮弹 释放按键时发射炮弹控制 发射频率 257 fire(); 258 break; 259 case KeyEvent.VK_LEFT: 260 bL = false; 261 break; 262 case KeyEvent.VK_RIGHT: 263 bR = false; 264 break; 265 case KeyEvent.VK_UP: 266 bU = false; 267 break; 268 case KeyEvent.VK_DOWN: 269 bD = false; 270 break; 271 case KeyEvent.VK_SPACE: 272 superFire(); 273 break; 274 } 275 locateDirection(); 276 } 277 278 /** 279 * @Description: 根据按下的键盘确定移动方向 280 * @param: [] 281 * @return: void 282 */ 283 void locateDirection(){ 284 if(bL && !bR && !bU && !bD) dir = Direction.L; 285 else if(bL && !bR && bU && !bD) dir = Direction.LU; 286 else if(!bL && !bR && bU && !bD) dir = Direction.U; 287 else if(!bL && bR && bU && !bD) dir = Direction.RU; 288 else if(!bL && bR && !bU && !bD) dir = Direction.R; 289 else if(!bL && bR && !bU && bD) dir = Direction.RD; 290 else if(!bL && !bR && !bU && bD) dir = Direction.D; 291 else if(bL && !bR && !bU && bD) dir = Direction.LD; 292 else if(!bL && !bR && !bU && !bD) dir = Direction.STOP; 293 } 294 295 /** 296 * @Description: 开火打出一发子弹 297 * @param: [] 298 * @return: cc.openhome.Missile 299 */ 300 public Missile fire(){ 301 int x = this.x + (Tank.WIDTH - Missile.WIDTH) / 2; 302 int y = this.y + (Tank.HEIGHT - Missile.HEIGHT) / 2; 303 Missile m = new Missile(x,y,good,ptdir,this.tkc); 304 tkc.missiles.add(m); 305 return m; 306 } 307 308 /** 309 * @Description: 朝固定方向打出一颗子弹 310 * @param: [dir] 311 * @return: cc.openhome.Missile 312 */ 313 public Missile fire(Direction dir){ 314 int x = this.x + (Tank.WIDTH - Missile.WIDTH) / 2; 315 int y = this.y + (Tank.HEIGHT - Missile.HEIGHT) / 2; 316 Missile m = new Missile(x,y,good,dir,this.tkc); 317 tkc.missiles.add(m); 318 return m; 319 } 320 321 /** 322 * @Description: 获取子弹的方块 323 * @param: [] 324 * @return: java.awt.Rectangle 325 */ 326 public Rectangle getRect(){ 327 return new Rectangle(x,y,WIDTH,HEIGHT); 328 } 329 330 /** 331 * @Description: tank 撞见墙了作处理 332 * @param: [w] 333 * @return: boolean 334 */ 335 public boolean collidesWithWall(Wall w){ 336 // 撞见墙 让坦克掉头,或停下来 337 if(this.getRect().intersects(w.getRect())){ 338 this.stay(); 339 return true; 340 } 341 return false; 342 } 343 344 /** 345 * @Description: 处理tank遇见tank时 346 * @param: [tanks] 347 * @return: boolean 348 */ 349 public boolean collidesWithTanks(List<Tank> tanks){ 350 for(int i = 0;i < tanks.size();i++){ 351 Tank t = tanks.get(i); 352 if(this != t){ 353 if(this.live && t.isLive() && this.getRect().intersects(t.getRect())){ 354 this.stay(); 355 t.stay(); 356 return true; 357 } 358 } 359 360 } 361 return false; 362 } 363 364 /** 365 * @Description: 超级子弹 一次可以朝多个方向打出子弹 366 * @param: [] 367 * @return: void 368 */ 369 public void superFire(){ 370 Direction [] dirs = Direction.values(); 371 for(int i = 0;i < 8;i++){ 372 fire(dirs[i]); 373 } 374 } 375 376 /** 377 * @Description: 成tank的生命值 378 * @param: 379 * @return: 380 */ 381 private class BloodBar{ 382 public void draw(Graphics g){ 383 Color c = g.getColor(); 384 g.setColor(Color.red); 385 g.drawRect(x,y - 15,WIDTH,10); 386 int w = WIDTH * life / 100; 387 g.fillRect(x,y - 15,w,10); 388 g.setColor(c); 389 } 390 } 391 392 /** 393 * @Description: 给tank补充生命值 394 * @param: [b] 395 * @return: boolean 396 */ 397 public boolean eatBlood(Blood b){ 398 // 当前tank活着,还有血,子弹和血块相撞 399 if(this.live && b.isLive() && this.getRect().intersects(b.getRect())){ 400 if(life < LIFETIME){ 401 life += 20; 402 } 403 b.setLive(false); 404 return true; 405 } 406 return false; 407 } 408 }
Missile类:
1 package cc.openhome; 2 3 import cc.openhome.Explode; 4 import cc.openhome.Wall; 5 6 import java.awt.*; 7 import java.util.List; 8 /** 9 * @descpition 子弹类 10 * @author zizl_zq 11 * @date 1/6/19 3:51 PM 12 */ 13 public class Missile { 14 15 // 子弹的移动速度 16 public static final int xSpeed = 10; 17 public static final int ySpeed = 10; 18 19 // 子弹的宽度,高度 20 public static final int WIDTH = 10; 21 public static final int HEIGHT = 10; 22 private int x,y; 23 private Tank.Direction dir; 24 25 private boolean good; 26 private TankClient tc; 27 28 29 private boolean live = true; 30 31 public Missile(int x, int y, Tank.Direction dir) { 32 this.x = x; 33 this.y = y; 34 this.dir = dir; 35 } 36 37 public Missile(int x, int y, Boolean good, Tank.Direction dir, TankClient tc){ 38 this(x,y,dir); 39 this.good = good; 40 this.tc = tc; 41 } 42 43 public boolean isLive() { 44 return live; 45 } 46 public void setLive(boolean live) { 47 this.live = live; 48 } 49 50 51 public void draw(Graphics g){ 52 if(!live) 53 { 54 tc.missiles.remove(this); 55 return; 56 } 57 Color c = g.getColor(); 58 if(!good){ 59 g.setColor(Color.blue); 60 } 61 if(good){ 62 g.setColor(Color.black); 63 } 64 // 坐标四个参数,确定图案大小 65 g.fillOval(x,y,WIDTH,HEIGHT); 66 g.setColor(c); 67 68 // 移动 69 move(); 70 } 71 72 /** 73 * @Description 子弹移动方法 74 * @Param [] 75 * @return void 76 */ 77 void move(){ 78 switch (dir ){ 79 case L: 80 x -= xSpeed; 81 break; 82 case LU: 83 x -= xSpeed; 84 y -= ySpeed; 85 break; 86 case U: 87 y -= ySpeed; 88 break; 89 case RU: 90 x += xSpeed; 91 y -= ySpeed; 92 break; 93 case R: 94 x += xSpeed; 95 break; 96 case RD: 97 x += xSpeed; 98 y += ySpeed; 99 break; 100 case D: 101 y += ySpeed; 102 break; 103 case LD: 104 x -= xSpeed; 105 y += ySpeed; 106 break; 107 } 108 // 判断炮弹出界 109 if(x < 0 || y < 0 || x > TankClient.GAME_WIDTH || y > TankClient.GAME_HEIGHT){ 110 live = false; 111 } 112 } 113 114 // 获取子弹的方块 115 public Rectangle getRect(){ 116 return new Rectangle(x,y,WIDTH,HEIGHT); 117 118 } 119 /** 120 * @Description 子弹打击tank 121 * @Param [tk] 122 * @return boolean 123 */ 124 public boolean hitTank(Tank tk){ 125 // 1,判断子弹是否活着 2,判断是否击中,3,判断坦克是否活着,4,判断是否是一伙的 126 if(this.live && this.getRect().intersects(tk.getRect()) && tk.isLive() && this.good != tk.isGood()){ 127 if(tk.isGood()){ 128 tk.setLife(tk.getLife() - 20); 129 if(tk.getLife() <= 0){ 130 tk.setLive(false); 131 } 132 133 }else { 134 tk.setLive(false); 135 } 136 this.setLive(false); 137 Explode e = new Explode(x,y,tc); 138 tc.explodes.add(e); 139 return true; 140 } 141 return false; 142 } 143 144 /** 145 * @Description 击打所有的tank 146 * @Param [tanks] 147 * @return boolean 148 */ 149 public boolean hitTanks(List<Tank> tanks){ 150 for(int i = 0;i < tanks.size();i++){ 151 if(hitTank(tanks.get(i))){ 152 return true; 153 } 154 } 155 return false; 156 } 157 158 /** 159 * @Description 子弹撞在墙上 160 * @Param [w] 161 * @return boolean 162 */ 163 public boolean collidesWithWall(Wall w){ 164 // 子弹撞到墙上,让它消失 165 if(this.getRect().intersects(w.getRect())){ 166 setLive(false); 167 return true; 168 } 169 return false; 170 } 171 }
Blood类:
1 package cc.openhome; 2 3 import java.awt.*; 4 5 /** 6 *@ClassName cc.openhome.Blood 7 *@Description 血块类 8 *@Author zizl_zq 9 *@Date 1/6/19 3:51 PM 10 */ 11 public class Blood { 12 13 int x,y,w,h; // 血块出现的位置,长和宽 14 private int step = 0; 15 TankClient tc; 16 // 血块按照指定的这几个点移动 17 int [][] positions = { 18 {430,440},{430,450},{440,460},{460,470},{470,450},{450,440},{440,430} 19 }; 20 21 /** 22 * @Description 判断血块是否活着,如果被坦克吃掉了就消失 23 * @Param [] 24 * @return boolean 25 */ 26 public boolean isLive() { 27 return live; 28 } 29 30 /** 31 * @Description 设置血块的生命 32 * @Param [live] 33 * @return void 34 */ 35 public void setLive(boolean live) { 36 this.live = live; 37 } 38 39 private boolean live = true; 40 41 public Blood(){ 42 x = positions[0][0]; 43 y = positions[0][1]; 44 w = 10; 45 h = 10; 46 } 47 48 /** 49 * @Description 按着这个步子在移动的 50 * @Param [] 51 * @return void 52 */ 53 public void move(){ 54 55 if(step == positions.length){ 56 step = 0; 57 } 58 x = positions[step][0]; 59 y = positions[step][1]; 60 step++; 61 } 62 63 /** 64 * @Description 画出血块 65 * @Param [g] 66 * @return void 67 */ 68 public void draw(Graphics g){ 69 if(!live){ 70 return; 71 } 72 Color c = g.getColor(); 73 g.setColor(Color.magenta); 74 g.fillRect(x,y,w,h); 75 g.setColor(c); 76 move(); 77 } 78 79 /** 80 * @Description 获取自身位置,为碰撞做准备 81 * @Param [] 82 * @return java.awt.Rectangle 83 */ 84 public Rectangle getRect(){ 85 return new Rectangle(x,y,w,h); 86 } 87 }
Wall 类:
1 package cc.openhome; 2 3 import java.awt.*; 4 /** 5 *@Description 增加游戏好玩度,增加一堵墙 6 *@Author zizl_zq 7 *@Date 1/6/19 3:51 PM 8 */ 9 public class Wall { 10 public static final int WIDTH = 200; 11 public static final int HEIGHT = 10; 12 13 int x,y; 14 private TankClient tc; 15 public Wall(int x, int y, TankClient tc) { 16 this.x = x; 17 this.y = y; 18 this.tc = tc; 19 } 20 21 /** 22 * @Description 画出一个tank 23 * @Param [g] 24 * @return void 25 **/ 26 public void draw(Graphics g){ 27 Color c = g.getColor(); 28 g.setColor(Color.black); 29 g.fillRect(x,y,WIDTH,HEIGHT); 30 g.setColor(c); 31 } 32 33 /** 34 * @Description 获取墙的位置 35 * @Param [] 36 * @return java.awt.Rectangle 37 **/ 38 public Rectangle getRect(){ 39 return new Rectangle(x,y,WIDTH,HEIGHT); 40 } 41 42 }
Explode类:
1 package cc.openhome; 2 3 import java.awt.*; 4 5 /** 6 *@ClassName cc.openhome.Explode 7 *@Description 爆炸类 8 *@Author zizl_zq 9 *@Date 1/6/19 3:51 PM 10 */ 11 public class Explode { 12 int x,y; 13 private boolean live = true; 14 private TankClient tc; 15 16 int [] diameter = {4,7,12,18,26,32,49,60,30,14,6}; 17 int step = 0; 18 19 public Explode(int x, int y, TankClient tc){ 20 this.x = x; 21 this.y = y; 22 this.tc = tc; 23 } 24 25 public void draw(Graphics g){ 26 27 if(!live) { 28 tc.explodes.remove(this); 29 return; 30 } 31 32 if(step == diameter.length){ 33 live = false; 34 step = 0; 35 return; 36 } 37 Color c = g.getColor(); 38 g.setColor(Color.yellow); 39 g.fillOval(x,y,diameter[step],diameter[step]); 40 g.setColor(c); 41 42 step++; 43 } 44 }
运行结果:
总结 :
进一步理解了面向对象的思想,处理问题是,首要考虑解决这个问题需要什么对象,这些对象需要有那些属性,用这些属性来解决什么问题。
使用IDEA生成api文档。生成jar包。
新学到的知识点:继承Fram类,paint,lauchFram,uptate方法,里面用于图像处理的几个方法。键盘监听事件,继承KeyAdapter类,keyPressed,KeyReleased方法。键盘可以控制画面上的图像运动。
不足之处:页面很简陋,没运用多态方法,功能还很单一,可以使用一个标志值来控制重画线程的结束,线程的使用不够熟练。
原文:https://www.cnblogs.com/changlili/p/10230799.html