Space Invaders Game Code Java
Posted on by admin
Home Subscribe Java 2D games tutorial. This is Java 2D games tutorial. In this tutorial, you will learn the basics of 2D game programming in Java. The Java 2D games tutorial is suitable for beginners and intermediate programmers. Space Invaders - SoundManager You will need to have lwjgl.jar and lwjglutil.jar on the classpath to satisfy all the imports needed for this game. You will also need the image (.gif) and sound files (.wav) used by this game.
Space Invaders Style Game
PermalinkJoin GitHub today
GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.
Sign up Find file Copy path
jeremangnrMerge double key press problem from branch key-press-fix40bb0e6Apr 17, 2012
1 contributor

packageorg.jere.spaceinvaders; |
importjava.awt.Canvas; |
importjava.awt.Color; |
importjava.awt.Dimension; |
importjava.awt.Graphics2D; |
importjava.awt.event.KeyAdapter; |
importjava.awt.event.KeyEvent; |
importjava.awt.event.WindowAdapter; |
importjava.awt.event.WindowEvent; |
importjava.awt.image.BufferStrategy; |
importjava.util.ArrayList; |
importjava.util.List; |
importjavax.swing.JFrame; |
importjavax.swing.JOptionPane; |
importjavax.swing.JPanel; |
@SuppressWarnings('serial') |
publicclassGameextendsCanvas { |
/** The game's X resolution **/ |
publicstaticfinalintRES_X=800; |
/** The game's Y resolution **/ |
publicstaticfinalintRES_Y=600; |
/** Used to know if debugging is enabled (defaults to false) **/ |
publicstaticfinalbooleanDEBUG_ENABLED=false; |
/** Buffer strategy used to render accelerated graphics **/ |
privateBufferStrategy bufferStrategy; |
/** Ship entity representing the player **/ |
privateEntity ship; |
/** Indicates whether the game is running or not **/ |
privateboolean gameRunning; |
/** Indicates if left key was pressed **/ |
privateboolean leftPressed; |
/** Indicates if right key was pressed **/ |
privateboolean rightPressed; |
/** Indicates if fire key was pressed **/ |
privateboolean firePressed; |
/** True if we are waiting for a key to be pressed (when you lose or pause, for example) **/ |
privateboolean waitingForKeyPress =true; |
/** This will be set to TRUE when a game event requires the whole game world to be updated **/ |
privateboolean logicUpdateRequired =false; |
/** List containing all the present entities **/ |
privateList<Entity> entities =newArrayList<Entity>(); |
/** List containing all the present entities **/ |
privateList<Entity> removeList =newArrayList<Entity>(); |
/** Ship's default move speed (pixels/sec) **/ |
privateint shipMoveSpeed =300; |
/** Amount of aliens currently on screen **/ |
privateint alienCount; |
/** Time when last shot was fired **/ |
privatelong lastFire; |
/** Time allowed between shots (in ms) **/ |
privatelong firingInterval =300; |
/** Message to be shown while waiting for key press **/ |
privateString message =''; |
/** |
* Create new Game instance (sets up display and graphics and runs main game loop) |
* |
*/ |
publicGame() { |
// create frame to contain game |
JFrame container =newJFrame('Space Invaders - Ahrequesi'); |
// get the container panel of the frame to setup the game's resolution |
JPanel panel = (JPanel) container.getContentPane(); |
panel.setPreferredSize(newDimension(RES_X, RES_Y)); |
panel.setLayout(null); |
// setup the canvas size and put it in the content pane |
this.setBounds(0, 0, RES_X, RES_Y); |
panel.add(this); |
// since the canvas we're working with is going to be actively redrawn, |
// we need to prevent AWT from attempting to redraw our surface (we will do it ourselves) |
this.setIgnoreRepaint(true); |
// add key listener |
this.addKeyListener(newKeyInputHandler()); |
// default to exit program on close |
container.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); |
// and let there be light |
container.pack(); |
container.setResizable(false); |
container.setVisible(true); |
// create buffer strategy to use accelerated graphics method, and we are all set |
this.createBufferStrategy(2); |
this.bufferStrategy =this.getBufferStrategy(); |
// set focus on game window |
this.requestFocus(); |
} |
/** |
* Initialize entities (create aliens and ship) |
* |
*/ |
privatevoidinitEntities() { |
// create player entity and place it in the center of the screen |
this.ship =newShipEntity(this, 'sprites/ship.gif', 370, 550); |
entities.add(ship); |
// create a block of aliens (5 rows of 12 aliens each, spaced evenly) |
this.alienCount =0; |
for (int row =0; row <5; row++) { |
for (int x =0; x <12; x++) { |
Entity alien =newAlienEntity(this, 'sprites/alien.gif', 100+ (x*50), (50) + row*30); |
entities.add(alien); |
this.alienCount++; |
} |
} |
} |
privatevoidtryToFire () { |
long currentFiringInterval =System.currentTimeMillis() -this.lastFire; |
// if we are trying to shoot again in less time than allowed, do nothing |
if (currentFiringInterval <this.firingInterval) { |
return; |
} |
// if we're OK to fire, update last fire time to current time |
this.lastFire =System.currentTimeMillis(); |
// create shot entity and add it to entity list |
ShotEntity shot =newShotEntity(this, 'sprites/shot.gif', this.ship.getXPosition() +10, this.ship.getYPosition() -30); |
this.entities.add(shot); |
} |
/** |
* Game world updates take place here (collision-detection, shots, keyboard input, etc.). |
* |
*/ |
privatevoidgameLoop() { |
// we'll store the time difference between each loop here. |
long lastLoopTime =System.currentTimeMillis(); |
while (this.gameRunning) { |
// calculate how long it's been since the last run of the game loop |
long delta =System.currentTimeMillis() - lastLoopTime; |
lastLoopTime =System.currentTimeMillis(); |
// get the current graphics surface and blank it out (black it out, actually) |
Graphics2D graphSurface = (Graphics2D) this.bufferStrategy.getDrawGraphics(); |
graphSurface.setColor(Color.BLACK); |
graphSurface.fillRect(0, 0, RES_X, RES_Y); |
// cycle through the entities and make them move (if necessary) |
if (!this.waitingForKeyPress) { |
for (Entity e :this.entities) { |
e.move(delta); |
} |
} |
// after moving them all, we draw them. |
for (Entity e :this.entities) { |
e.draw(graphSurface); |
} |
// brute force collision check: cycle through the entity list, if two entities collide |
// notify both of them about the collision. |
for (Entity me :this.entities) { |
for (Entity him :this.entities) { |
// we don't want to check if we collide with ourselves :p |
if (me him) { |
continue; |
} |
// notify both entities if we find a collision |
if (me.collidesWith(him)) { |
me.collidedWith(him); |
him.collidedWith(me); |
} |
} |
} |
// remove entities mark for deletion and clear remove list |
this.entities.removeAll(this.removeList); |
this.removeList.clear(); |
// resolve each entities game logic if a logic update was required |
if (this.logicUpdateRequired) { |
for (Entity entity :this.entities) { |
entity.doLogic(); |
} |
// set it back to false, until some other entity needs updating |
this.logicUpdateRequired =false; |
} |
// if we're waiting for an 'any key' press then draw the |
// current message |
if (this.waitingForKeyPress) { |
graphSurface.setColor(Color.white); |
graphSurface.drawString(this.message,(800- graphSurface.getFontMetrics().stringWidth(this.message)) /2,250); |
graphSurface.drawString('Press any key to continue',(800- graphSurface.getFontMetrics().stringWidth('Press any key')) /2,300); |
} |
// this is where accelerated graphics kick in, clear the current surface and draw the new one on screen |
// (we assume at this point that everything that had to be re-drawn, is already re-drawn) |
graphSurface.dispose(); |
this.bufferStrategy.show(); |
// resolve movement of the ship, we'll first assume it isn't moving |
this.ship.setXSpeed(0); |
// if only right is pressed, move right |
if (this.rightPressed &&!this.leftPressed) { |
this.ship.setXSpeed(this.shipMoveSpeed); |
} |
// same for left |
if (!this.rightPressed &&this.leftPressed) { |
this.ship.setXSpeed(-this.shipMoveSpeed); |
} |
// if fire key is pressed, try to fire |
if (this.firePressed) { |
tryToFire(); |
} |
// pause for a bit (this value should keep us at about 100fps) |
try { |
Thread.sleep(10); |
} catch (InterruptedException e) { |
JOptionPane.showMessageDialog(null, |
'The game's main thread was interrupted.', |
'Sorry!', |
JOptionPane.ERROR_MESSAGE); |
if (DEBUG_ENABLED) { |
e.printStackTrace(); |
} |
System.exit(0); |
} |
} |
} |
/** |
* Runs the main game loop. |
* |
*/ |
publicvoidstartGame() { |
this.resetGame(); |
// the game is now running |
this.gameRunning =true; |
// so, we run the game loop |
this.gameLoop(); |
} |
/** |
* Reset game (clear out existing entities and reset key presses, etc) |
* |
*/ |
publicvoidresetGame() { |
// clear out any existing entities and initialize a new set |
entities.clear(); |
initEntities(); |
// blank out any keyboard settings we might currently have |
leftPressed =false; |
rightPressed =false; |
firePressed =false; |
} |
/** |
* Marks an entity to be removed in the next game loop |
* |
* @param entity The entity to be removed |
*/ |
publicvoidremoveEntity(Entityentity) { |
this.removeList.add(entity); |
} |
/** |
* Updates game logic when player is hit by an alien |
* |
*/ |
publicvoidnotifyPlayerDeath() { |
this.message ='Sucker. You are DEAD!'; |
this.waitingForKeyPress =true; |
} |
/** |
* Updates game logic when player wins the game |
* |
*/ |
publicvoidnotifyPlayerWin() { |
this.message ='Lucky bastard. You managed to escape the gay republican aliens!'; |
this.waitingForKeyPress =true; |
} |
/** |
* Updates game logic when an alien gets killed |
* |
*/ |
publicvoidnotifyAlienKilled() { |
this.alienCount--; |
// if we killed all the aliens we've won the game. |
if (this.alienCount 0) { |
this.notifyPlayerWin(); |
return; |
} |
// speed up aliens if there are still any left |
for (Entity entity :this.entities) { |
if (entity instanceofAlienEntity) { |
((AlienEntity) entity).speedUp(); |
} |
} |
} |
/** |
* Called by entities to notify the game world it needs logic updates |
* |
*/ |
publicvoidupdateLogic() { |
this.logicUpdateRequired =true; |
} |
/** |
* Anonymous inner class to handle keyboard input |
* |
* @author jere |
* |
*/ |
privateclassKeyInputHandlerextendsKeyAdapter { |
/** |
* Handles the event of a key being pressed down |
* |
* @param e Class containing the event's information |
*/ |
publicvoidkeyPressed(KeyEvente) { |
if (waitingForKeyPress) { |
return; |
} |
switch(e.getKeyCode()) { |
caseKeyEvent.VK_LEFT: { |
leftPressed =true; |
break; |
} |
caseKeyEvent.VK_RIGHT: { |
rightPressed =true; |
break; |
} |
caseKeyEvent.VK_SPACE: { |
firePressed =true; |
break; |
} |
} |
} |
/** |
* Handles the event of a key being released |
* |
* @param e Class containing the event's information |
*/ |
publicvoidkeyReleased(KeyEvente) { |
if (waitingForKeyPress) { |
return; |
} |
switch(e.getKeyCode()) { |
caseKeyEvent.VK_LEFT: { |
leftPressed =false; |
break; |
} |
caseKeyEvent.VK_RIGHT: { |
rightPressed =false; |
break; |
} |
caseKeyEvent.VK_SPACE: { |
firePressed =false; |
break; |
} |
} |
} |
/** |
* Handles the event of a key being typed (pressed and released) |
* |
* @param e Class containing the event's information |
*/ |
publicvoidkeyTyped(KeyEvente) { |
// if we're waiting for a 'any key to be pressed' then check if we've received any recently. We may |
// have had a keyType() event from the user releasing the shoot or move keys, hence |
// the use of the 'pressCount' counter. |
if (waitingForKeyPress) { |
waitingForKeyPress =false; |
resetGame(); |
} |
// we'll quit the game when escape is typed |
if (e.getKeyChar() 27) { |
System.exit(0); |
} |
} |
} |
} |
Copy lines Copy permalink