package Engine; import Sprites.*; import javax.swing.*; import java.applet.Applet; import java.applet.AudioClip; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.image.BufferedImage; import java.net.URL; import java.util.Random; import java.util.Vector; /** * Created by sagi on 12/18/15. */ public class GameEngine implements KeyListener { private final int LARGE=100, MEDIUM=50, SMALL=25, NUM_OF_LIVES = 3, LASER_SPEED = 10, ASTROID_SPEED = 3, FOG_COUNT = 4, MINI_SHIP_SIZE = 30; private final int STOP=0, UP=1, DOWN=-1; //Movement directions public boolean gameOn,fireLock, gameOver, isFirstGame; private Ship player; private Vector astroidsSprites,laserSprites; //will save all laser shots and asteroids which are currently on the screen. private int pWidth, pHeight; //panel dimensions private Timer astroidTimer, fireTimer, startTime; private Random r; private int score, countDown; private Vector lives, fogs; private AudioClip laserAudioClip; private BufferedImage sceneImage; private AudioClip themeAudioClip; private final URL laserURL= getClass().getResource("/Sounds/laser.wav"); private final URL themeURL= getClass().getResource("/Sounds/theme.wav"); public GameEngine(int width, int height){ //initialize variables and load audio\image files. this.isFirstGame = true; this.gameOver = true; this.pWidth = width; this.pHeight = height; try { laserAudioClip = Applet.newAudioClip(laserURL); themeAudioClip = Applet.newAudioClip(themeURL); }catch (Exception e){ laserAudioClip = null; themeAudioClip = null; } if(themeAudioClip != null) themeAudioClip.loop(); fogs = new Vector<>(); r = new Random(); sceneImage = new BufferedImage(width, height, Image.SCALE_SMOOTH); initFogs(); //create fog sprites moving on screen. startNewGame(); } /** * creates FOG_COUNT amount of fog sprites to roam the screen. (currently set to 4) */ private void initFogs(){ for(int i = 0 ; i < FOG_COUNT ; i++){ fogs.add(new Fog((-1)*r.nextInt(),(-1)*r.nextInt(),pWidth,pHeight,1,"Fog.png",r.nextInt(360),pWidth)); } } /** * initialize and reset vars and timers to "new game" configuration. */ private void startNewGame(){ score = 0; lives = new Vector<>(); setupLives(NUM_OF_LIVES); astroidTimer = new Timer(5000, new astroidTimerListener()) ; fireTimer = new Timer(500, new fireTimerListener()) ; startTime = new Timer(1000, new countDownListener()); fogs.remove(fogs.size()-1); initGame(); } /** * clears asteroid and laser arrays, creates new asteroids, starts timers and repositions ship in center of screen. */ private void initGame(){ this.countDown = 3; astroidsSprites = new Vector<>(); laserSprites = new Vector<>(); this.player = new Ship(pWidth/2, pHeight/2,pWidth,pHeight, MEDIUM); gameOn = true; fireTimer.start(); astroidTimer.start(); for (int i =0 ; i<4 ; i++) createAstroid(); } /** * Creates requested amount of ships to "Lives" array (Mini ships to be presented at corner of the screen). * @param num * number of wanted "Lives". */ private void setupLives(int num){ for(int i = 0 ; i < num ; i++){ lives.add(new Ship(pWidth - ((i+1)*MINI_SHIP_SIZE), 15, pWidth, pHeight, MINI_SHIP_SIZE)); } } /** * returns score * @return * int */ public int getScore(){ return score; } /** * returns gameOver flag * @return * boolean */ public boolean isGameOver(){ return this.gameOver; } /** * returns countDown * @return * int */ public int getCountDown(){ return countDown; } /** * Create a new asteroid on a random position. */ private void createAstroid(){ astroidsSprites.add(new Astroid((-1)*r.nextInt(),(-1)*r.nextInt(),pWidth,pHeight,ASTROID_SPEED,"astroid.png",r.nextInt(360),LARGE)); } @Override public void keyTyped(KeyEvent keyEvent) {} @Override public void keyPressed(KeyEvent keyEvent) { if(gameOn) { switch (keyEvent.getKeyCode()) { case KeyEvent.VK_UP: player.setDirection(UP); break; case KeyEvent.VK_DOWN: player.setDirection(DOWN); break; case KeyEvent.VK_LEFT: player.turnShip(DOWN); //Left break; case KeyEvent.VK_RIGHT: player.turnShip(UP); //Right break; case KeyEvent.VK_SPACE: //Fire if (!fireLock && countDown <= 0) { if(laserAudioClip != null) laserAudioClip.play(); //Play audio file //create a new laser from ship towards ship direction. laserSprites.add(new LaserBlast((int) player.getLocX() + (player.getImageWidth() / 2), (int) player.getLocY() + (player.getImageHeight() / 2), pWidth, pHeight, LASER_SPEED, "laser2.gif", player.getAngle(), SMALL)); fireLock = true; //lock for delay in fire speed } break; case KeyEvent.VK_F2: //new game this.isFirstGame = false; gameOver = false; startNewGame(); startTime.start(); break; default: break; } } } @Override public void keyReleased(KeyEvent keyEvent) { if(gameOn){ //stop all movement activity switch (keyEvent.getKeyCode()){ case KeyEvent.VK_UP: case KeyEvent.VK_DOWN: player.setDirection(STOP); break; case KeyEvent.VK_RIGHT: case KeyEvent.VK_LEFT: player.turnShip(STOP); break; // case KeyEvent.VK_SPACE: // laserAudioClip.stop(); // break; default: break; } } } /** * Update all sprites, including collision handling. */ public void update(){ for (Sprite sprite : fogs) { sprite.update(); } if(!gameOver) { if (countDown > 0) return; } else return; player.update(); for (Sprite sprite : astroidsSprites) { sprite.update(); } for (Sprite sprite : laserSprites) { sprite.update(); } // check for collisions collisionHandler(); } /** * Checks if a collision has occurred. * in case of missile hitting an asteroid - they are both removed. * in case of asteroid hitting the ship - round over. */ private void collisionHandler(){ Vector newAstroids = new Vector<>(); Vector removeLasers = new Vector<>(); Vector removeAstroids = new Vector<>(); /* * check for "Laser vs Asteroid" collisions * in case of collision both missile and asteroid are removed, * and 2 smaller asteroids are created (if needed). */ for (int i = 0; i 0) lives.remove(lives.size()-1); initGame(); } } //add new asteroids and remove collisions. astroidsSprites.addAll(newAstroids); laserSprites.removeAll(removeLasers); astroidsSprites.removeAll(removeAstroids); } /** * render buffered image. * @param panel * JPanel */ public void render(JPanel panel){ sceneImage = new BufferedImage(this.pWidth, this.pHeight, Image.SCALE_FAST); renderScene(sceneImage.getGraphics(), panel); } /** * Draws all sprites * @param g * Graphics * @param panel * Jpanel */ public void renderScene(Graphics g, JPanel panel){ if(!gameOver) player.drawSprite(g, panel); try { for (Sprite sprite : astroidsSprites) { sprite.drawSprite(g, panel); } for (Sprite sprite : lives) { sprite.drawSprite(g, panel); } for (Sprite sprite : laserSprites) { sprite.drawSprite(g, panel); } for (Sprite sprite : fogs) { sprite.drawSprite(g, panel); } }catch (Exception e) { } } /** * creates an new asteroid each 5 seconds * */ private class astroidTimerListener implements ActionListener{ @Override public void actionPerformed(ActionEvent actionEvent) { createAstroid(); } } /** * Limits fire speed to 1 second. * */ private class fireTimerListener implements ActionListener{ @Override public void actionPerformed(ActionEvent actionEvent) { fireLock = false; } } /** * Pre game countdown. * */ private class countDownListener implements ActionListener{ @Override public void actionPerformed(ActionEvent actionEvent) { countDown--; } } /** * returns sceneImage * @return * BufferedImage */ public BufferedImage getScene(){ return this.sceneImage; } }