Tank.java (17243B)
1 import java.awt.Color; 2 import java.awt.Image; 3 import java.awt.Point; 4 import java.awt.event.KeyEvent; 5 import java.awt.event.KeyListener; 6 7 import javax.swing.JFrame; 8 9 /* Copyright (c) Mary Percival 2002 */ 10 /* Tank game Created October 2002 */ 11 12 public class Tank extends JFrame implements KeyListener, Runnable { 13 private static final long serialVersionUID = 2750159877444817519L; 14 // all member variables 'static' because shared with the enemy action thread 15 private static TankArea area; 16 private static boolean ingame = false; 17 private boolean juststarted = false; 18 private static int level = 1; 19 private static int enemiesRemaining; 20 protected static Point[] enemyPositions; 21 protected static Point playerPosition; 22 protected static Point[] pitPositions; 23 private static Thread enemies; 24 25 protected static int pitNumber = 15; 26 protected static int enemyNumber = 1; 27 protected static int RIGHTEDGE = 1200; 28 protected static final int LEFTEDGE = 0; 29 protected static final int TOPEDGE = 0; 30 protected static int BOTTOMEDGE = 1000; 31 protected static int XAMOUNT = 5; 32 protected static int YAMOUNT = 5; 33 private static final int X = 1; 34 private static final int Y = 2; 35 private static final int NOT = 3; 36 private static final int DELAY = 125; 37 protected int explosionx = -1, explosiony = -1; 38 39 // tank game stuff 40 boolean up = true, down = false, left = false, right = false, shooting = false; 41 static int NOTSHOOTING = 0; 42 static int SHOOTING = 1; 43 static int FIRSTUP = 0; 44 static int FIRSTDOWN = 2; 45 static int FIRSTLEFT = 4; 46 static int FIRSTRIGHT = 6; 47 int goodImageNo = FIRSTUP; // TODO - randomise 48 int[] enemyImageNo; 49 boolean[] enemyShooting; 50 Image[][] goodImages = new Image[8][2]; // up up2 down down2 left left2 right right2 x SHOOTING and NON_SHOOTING 51 Image[][] badImages = new Image[8][2]; // up up2 down down2 left left2 right right2 x SHOOTING and NON_SHOOTING 52 53 public static void main(String[] args) { 54 Tank tank = new Tank(); 55 tank.setLayout(null); 56 tank.setBackground(Color.gray); 57 tank.setSize(RIGHTEDGE, BOTTOMEDGE); 58 tank.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 59 tank.setTitle("Tank"); 60 61 area = new TankArea(tank); 62 tank.add(area); 63 //RIGHTEDGE = tank.getBounds().width - 1; 64 //BOTTOMEDGE = tank.getBounds().height - 1; 65 XAMOUNT = 12; 66 YAMOUNT = 12; 67 tank.setVisible(true); 68 area.setBounds(0, 0, RIGHTEDGE, BOTTOMEDGE); 69 area.setVisible(true); 70 71 tank.addKeyListener(tank); 72 area.addKeyListener(tank); 73 area.requestFocus(); 74 75 tank.goodImages[FIRSTUP][NOTSHOOTING] = area.tankup; 76 tank.goodImages[FIRSTUP + 1][NOTSHOOTING] = area.tankup2; 77 tank.goodImages[FIRSTUP][SHOOTING] = area.tankupshoot; 78 tank.goodImages[FIRSTUP + 1][SHOOTING] = area.tankupshoot2; 79 80 tank.goodImages[FIRSTDOWN][NOTSHOOTING] = area.tankdown; 81 tank.goodImages[FIRSTDOWN + 1][NOTSHOOTING] = area.tankdown2; 82 tank.goodImages[FIRSTDOWN][SHOOTING] = area.tankdownshoot; 83 tank.goodImages[FIRSTDOWN + 1][SHOOTING] = area.tankdownshoot2; 84 85 tank.goodImages[FIRSTLEFT][NOTSHOOTING] = area.tankleft; 86 tank.goodImages[FIRSTLEFT + 1][NOTSHOOTING] = area.tankleft2; 87 tank.goodImages[FIRSTLEFT][SHOOTING] = area.tankleftshoot; 88 tank.goodImages[FIRSTLEFT + 1][SHOOTING] = area.tankleftshoot2; 89 90 tank.goodImages[FIRSTRIGHT][NOTSHOOTING] = area.tankright; 91 tank.goodImages[FIRSTRIGHT + 1][NOTSHOOTING] = area.tankright2; 92 tank.goodImages[FIRSTRIGHT][SHOOTING] = area.tankrightshoot; 93 tank.goodImages[FIRSTRIGHT + 1][SHOOTING] = area.tankrightshoot2; 94 95 tank.badImages[FIRSTUP][NOTSHOOTING] = area.badtankup; 96 tank.badImages[FIRSTUP + 1][NOTSHOOTING] = area.badtankup2; 97 tank.badImages[FIRSTUP][SHOOTING] = area.badtankupshoot; 98 tank.badImages[FIRSTUP + 1][SHOOTING] = area.badtankupshoot2; 99 100 tank.badImages[FIRSTDOWN][NOTSHOOTING] = area.badtankdown; 101 tank.badImages[FIRSTDOWN + 1][NOTSHOOTING] = area.badtankdown2; 102 tank.badImages[FIRSTDOWN][SHOOTING] = area.badtankdownshoot; 103 tank.badImages[FIRSTDOWN + 1][SHOOTING] = area.badtankdownshoot2; 104 105 tank.badImages[FIRSTLEFT][NOTSHOOTING] = area.badtankleft; 106 tank.badImages[FIRSTLEFT + 1][NOTSHOOTING] = area.badtankleft2; 107 tank.badImages[FIRSTLEFT][SHOOTING] = area.badtankleftshoot; 108 tank.badImages[FIRSTLEFT + 1][SHOOTING] = area.badtankleftshoot2; 109 110 tank.badImages[FIRSTRIGHT][NOTSHOOTING] = area.badtankright; 111 tank.badImages[FIRSTRIGHT + 1][NOTSHOOTING] = area.badtankright2; 112 tank.badImages[FIRSTRIGHT][SHOOTING] = area.badtankrightshoot; 113 tank.badImages[FIRSTRIGHT + 1][SHOOTING] = area.badtankrightshoot2; 114 115 enemies = new Thread(tank); 116 enemies.start(); 117 } 118 119 public void doLevel(int level) { 120 // this runs one 'level' 121 // create arrays of pits and enemies here. 122 // Maybe each level will have different numbers? 123 juststarted = true; 124 Point temppoint; 125 pitPositions = new Point[pitNumber]; 126 enemyPositions = new Point[enemyNumber]; 127 for (int i = 0; i < enemyNumber; i++) 128 enemyPositions[i] = new Point(0, 0); 129 for (int i = 0; i < pitNumber; i++) 130 pitPositions[i] = new Point(0, 0); 131 132 enemyImageNo = new int[enemyNumber]; 133 enemyShooting = new boolean[enemyNumber]; 134 for (int i = 0; i < enemyNumber; i++) { 135 enemyShooting[i] = false; 136 enemyImageNo[i] = FIRSTUP; // TODO - randomise 137 } 138 System.out.println("Started level " + level + ": " + enemyNumber + " enemies and " + pitNumber + " pits"); 139 140 // randomly position 1 player, x enemies and y pits 141 playerPosition = randomPosition(); 142 143 for (int i = 0; i < enemyNumber; i++) { 144 temppoint = randomPosition(); 145 while (isPlayerPosition(temppoint) || isTankPosition(temppoint)) { 146 // don't position any enemy on the player or on top of another enemy 147 temppoint = randomPosition(); 148 } 149 enemyPositions[i] = temppoint; 150 } 151 152 for (int i = 0; i < pitNumber; i++) { 153 temppoint = randomPosition(); 154 while (isPlayerPosition(temppoint) || isPitPosition(temppoint) || isTankPosition(temppoint)) { 155 // don't position any enemy at the player, an enemy or another pit 156 temppoint = randomPosition(); 157 } 158 pitPositions[i] = temppoint; 159 } 160 161 enemiesRemaining = enemyNumber; 162 // paint the panel here 163 area.repaint(); 164 ingame = true; 165 } 166 167 synchronized void incrementImageNo() { 168 goodImageNo++; 169 if ((goodImageNo % 2) == 0) 170 goodImageNo -= 2; 171 } 172 173 synchronized void incrementImageNo(int enemyNo) { 174 enemyImageNo[enemyNo]++; 175 if ((enemyImageNo[enemyNo] % 2) == 0) 176 enemyImageNo[enemyNo] -= 2; 177 } 178 179 void goLeft(int enemyno) { 180 if (enemyImageNo[enemyno] == FIRSTLEFT || enemyImageNo[enemyno] == FIRSTLEFT + 1) { 181 incrementImageNo(enemyno); 182 } else 183 enemyImageNo[enemyno] = FIRSTLEFT; 184 } 185 186 void goLeft() { 187 if (goodImageNo == FIRSTLEFT || goodImageNo == FIRSTLEFT + 1) { 188 incrementImageNo(); 189 } else 190 goodImageNo = FIRSTLEFT; 191 } 192 193 void goRight(int enemyno) { 194 if (enemyImageNo[enemyno] == FIRSTRIGHT || enemyImageNo[enemyno] == FIRSTRIGHT + 1) { 195 incrementImageNo(enemyno); 196 } else 197 enemyImageNo[enemyno] = FIRSTRIGHT; 198 } 199 200 void goRight() { 201 if (goodImageNo == FIRSTRIGHT || goodImageNo == FIRSTRIGHT + 1) { 202 incrementImageNo(); 203 } else 204 goodImageNo = FIRSTRIGHT; 205 } 206 207 void goUp(int enemyno) { 208 if (enemyImageNo[enemyno] == FIRSTUP || enemyImageNo[enemyno] == FIRSTUP + 1) { 209 incrementImageNo(enemyno); 210 } else 211 enemyImageNo[enemyno] = FIRSTUP; 212 } 213 214 void goUp() { 215 if (goodImageNo == FIRSTUP || goodImageNo == FIRSTUP + 1) { 216 incrementImageNo(); 217 } else 218 goodImageNo = FIRSTUP; 219 } 220 221 void goDown(int enemyno) { 222 if (enemyImageNo[enemyno] == FIRSTDOWN || enemyImageNo[enemyno] == FIRSTDOWN + 1) { 223 incrementImageNo(enemyno); 224 } else 225 enemyImageNo[enemyno] = FIRSTDOWN; 226 } 227 228 void goDown() { 229 if (goodImageNo == FIRSTDOWN || goodImageNo == FIRSTDOWN + 1) { 230 incrementImageNo(); 231 } else 232 goodImageNo = FIRSTDOWN; 233 } 234 235 private Point randomPosition() { 236 return new Point((int) (Math.random() * RIGHTEDGE) / XAMOUNT * XAMOUNT, 237 (int) (Math.random() * BOTTOMEDGE) / YAMOUNT * YAMOUNT); 238 } 239 240 private boolean isPlayerPosition(Point p) { 241 return (p.x == playerPosition.x && p.y == playerPosition.y); 242 } 243 244 private boolean isTankPosition(Point p) { 245 for (int i = 0; i < enemyNumber; i++) { 246 if (p.x == enemyPositions[i].x && p.y == enemyPositions[i].y) 247 return (true); 248 } 249 return (false); 250 } 251 252 private int isInline(Point p) { 253 // is the new position in the same row as the player? 254 if (Math.abs(p.x - playerPosition.x) < XAMOUNT) { 255 // see whether there is another enemy between this position and the player 256 if (playerPosition.y > p.y) { 257 for (int i = 0; i < enemyNumber; i++) { 258 if (p.x == enemyPositions[i].x && p.y < enemyPositions[i].y) 259 return (X); 260 } 261 } else { // playerPosition y < p.y 262 for (int i = 0; i < enemyNumber; i++) { 263 if (p.x == enemyPositions[i].x && p.y > enemyPositions[i].y) 264 return (X); 265 } 266 } 267 } else if (Math.abs(p.y - playerPosition.y) < YAMOUNT) { 268 // see whether there is another enemy between this position and the player 269 if (playerPosition.x > p.x) { 270 for (int i = 0; i < enemyNumber; i++) { 271 if (p.y == enemyPositions[i].y && p.x < enemyPositions[i].x) 272 return (Y); 273 } 274 } else { // playerPosition x < p.x 275 for (int i = 0; i < enemyNumber; i++) { 276 if (p.y == enemyPositions[i].y && p.x > enemyPositions[i].x) 277 return (Y); 278 } 279 } 280 } 281 return (NOT); 282 } 283 284 private boolean isPitPosition(Point p) { 285 for (int i = 0; i < pitNumber; i++) { 286 if (p.x == pitPositions[i].x && p.y == pitPositions[i].y) 287 return (true); 288 } 289 return (false); 290 } 291 292 private Point moveCloser(int enemyNo, Point original, Point target) { 293 Point result = new Point(original); 294 int inlineType = isInline(original); 295 // allowed to move EITHER X or Y but not both 296 if (Math.random() >= 0.5) { 297 // move in X direction 298 if (inlineType != X) { 299 if (original.x < target.x) { 300 result.x = original.x + (XAMOUNT / 2); 301 goRight(enemyNo); 302 } else if (original.x > target.x) { 303 result.x = original.x - (XAMOUNT / 2); 304 goLeft(enemyNo); 305 } 306 } 307 } else { 308 // move in Y direction 309 if (inlineType != Y) { 310 if (original.y < target.y) { 311 result.y = original.y + (YAMOUNT / 2); 312 goDown(enemyNo); 313 } else if (original.y > target.y) { 314 result.y = original.y - (YAMOUNT / 2); 315 goUp(enemyNo); 316 } 317 } 318 } 319 /* 320 * if (isTankPosition(result)) { if (isTankPosition(new Point(result.x, 321 * original.y))) { if (isTankPosition(new Point(original.x, result.y))) result = 322 * original; else result = new Point(original.x, result.y); } else result = new 323 * Point(result.x, original.y); } 324 */ 325 inlineType = isInline(result); 326 if (inlineType == X) { 327 // fire along the X axis 328 } else if (inlineType == Y) { 329 // fire along the Y axis 330 } 331 return (result); 332 } 333 334 /* 335 * private int randomMove() { // return + or - value (randomly) if 336 * (Math.random() >= 0.5) return(24); else return(-24); } 337 */ 338 339 // this class will use just the key pressed event 340 @Override 341 public void keyPressed(KeyEvent e) { 342 if (ingame) { 343 if (!((e.getKeyCode() == KeyEvent.VK_DOWN && playerPosition.y >= (BOTTOMEDGE - YAMOUNT)) 344 || (e.getKeyCode() == KeyEvent.VK_UP && playerPosition.y <= (TOPEDGE + YAMOUNT)) 345 || (e.getKeyCode() == KeyEvent.VK_LEFT && playerPosition.x <= (LEFTEDGE + XAMOUNT)) 346 || (e.getKeyCode() == KeyEvent.VK_RIGHT && playerPosition.x >= (RIGHTEDGE - XAMOUNT)))) { 347 // valid move: move the player and then move the enemies 348 if (e.getKeyCode() == KeyEvent.VK_DOWN) { 349 playerPosition.y += YAMOUNT; 350 goDown(); 351 } else if (e.getKeyCode() == KeyEvent.VK_UP) { 352 playerPosition.y -= YAMOUNT; 353 goUp(); 354 } else if (e.getKeyCode() == KeyEvent.VK_LEFT) { 355 playerPosition.x -= XAMOUNT; 356 goLeft(); 357 } else if (e.getKeyCode() == KeyEvent.VK_RIGHT) { 358 playerPosition.x += XAMOUNT; 359 goRight(); 360 } 361 if (isTankPosition(playerPosition)) { 362 System.out.println("The Player ran into an enemy!! Press the Enter key to restart the level"); 363 ingame = false; 364 } 365 if (isPitPosition(playerPosition)) { 366 System.out.println("The Player ran into a pit!! Press the Enter key to restart the level"); 367 ingame = false; 368 } 369 area.repaint(); 370 } // if valid key press 371 } else if (e.getKeyCode() == KeyEvent.VK_ENTER) { 372 doLevel(level++); 373 } 374 } 375 376 @Override 377 public void run() { 378 while (true) { 379 if (juststarted) { 380 try { 381 Thread.sleep(750); 382 } catch (Exception e) { 383 } 384 juststarted = false; 385 } 386 try { 387 Thread.sleep(DELAY); 388 } catch (InterruptedException e) { 389 } 390 if (ingame) { 391 // for each enemy, move the enemy closer to the player 392 for (int i = 0; i < enemyPositions.length; i++) { 393 if (!deadTank(enemyPositions[i])) { 394 enemyPositions[i] = moveCloser(i, enemyPositions[i], playerPosition); 395 } 396 // if there is a pit at that position, fall into it and decrement count of 397 // enemies 398 // and set that enemy's position to -1, -1 399 if (isPitPosition(enemyPositions[i])) { 400 System.out.println("an enemy fell into a pit"); 401 explosionx = enemyPositions[i].x; 402 explosiony = enemyPositions[i].y; 403 404 enemyPositions[i] = new Point(-1, -1); 405 enemiesRemaining--; 406 System.out.println(enemyNumber - enemiesRemaining + " down, " + enemiesRemaining + " to go..."); 407 } 408 // if player is caught by an enemy or all enemies are gone, end the game 409 if (isPlayerPosition(enemyPositions[i])) { 410 System.out.println( 411 ""Mmm! Brains...". The Player is dead. Press the Enter key to restart the level"); 412 level--; // because it will be incremented in a minute and we want to stay on the same 413 // 'level' 414 ingame = false; 415 } 416 } 417 if (enemiesRemaining == 0) { 418 System.out.println( 419 "All the enemies are gone -- you won!! Press the Enter key to start the next level"); 420 enemyNumber++; 421 if (pitNumber > 2) 422 pitNumber--; 423 ingame = false; 424 } else 425 area.repaint(); 426 } 427 } 428 } 429 430 private boolean deadTank(Point p) { 431 return (p.x == -1 && p.y == -1); 432 } 433 434 @Override 435 public void keyReleased(KeyEvent e) { 436 } 437 438 @Override 439 public void keyTyped(KeyEvent e) { 440 } 441 }