// Code by Sergio Fanchiotti (c) 1997 // // Free to use and copy for any purpose. // // No responsability for any mis-use or problems // due to the usage of this code on any device. // (i.e. crashing your browser and/or your OS) // import java.awt.*; import java.applet.*; import java.util.*; public class UFO_Attack extends Applet implements Runnable { Image buffer = null ; // Temporary image buffer Image backdrop = null ; // Backdrop image Image bgimg = null ; // Original backdrop image Image ufostrip = null ; // UFO Sequence Image missile = null ; // Misile Sequence Image missile_explosion = null ; // Misile Esplosion Sequence MediaTracker tracker = null ; Graphics buf_g = null ; // Buffer graphics object Graphics bkd_g = null ; // Backdrop graphics object Dimension window_size = null; Font font ; Font font_s ; AudioClip explosion = null ; AudioClip newufo = null ; AudioClip missile_launch = null ; Thread game = null ; boolean game_over = true ; int mouse_x = 100 ; Rectangle paint_area = new Rectangle() ; Rectangle new_area = new Rectangle() ; Launcher L = null ; Missile M = null ; Vector UV = new Vector() ; Vector EV = new Vector() ; int NU = 1 ; int score = 0 ; // Colors Color gunColor; Color mColor; Color ufoColor; Color scoreColor; Color bgColor; public void init() { System.out.println("UFO Attack: A game by Sergio Fanchiotti") ; tracker = new MediaTracker(this) ; bgimg = getImage(this.getCodeBase(),"bgimg.gif") ; tracker.addImage(bgimg,0) ; ufostrip = getImage(this.getCodeBase(),"ufostrip.gif") ; tracker.addImage(ufostrip,0) ; missile = getImage(this.getCodeBase(),"missile.gif") ; tracker.addImage(missile,0) ; missile_explosion = getImage(this.getCodeBase(),"explosionstrip.gif") ; tracker.addImage(missile_explosion,0) ; font = new Font("Helvetica", Font.BOLD, 24) ; font_s = new Font("Helvetica", Font.BOLD, 14) ; // Define the colors to use bgColor = new Color(0,0,128); gunColor = new Color(0,88,0); mColor = new Color(255,255,255); ufoColor = new Color(255,0,0); scoreColor = new Color(0,0,255); } public void start() { // Change the cursor getFrame(this).setCursor(Frame.CROSSHAIR_CURSOR) ; window_size = size(); buffer = null; buffer = createImage(window_size.width, window_size.height); backdrop = null; backdrop = createImage(window_size.width, window_size.height); buf_g = buffer.getGraphics(); buf_g.setColor(bgColor); buf_g.fillRect(0, 0, window_size.width, window_size.height); // Display initial message set_say_font(font) ; set_say_mode(CENTER) ; set_say_style(SHADOW) ; say("UFO",10,80) ; say("ATTACK") ; set_say_font(font_s) ; set_say_style(NORMAL) ; say("") ; say("Click to start") ; say("a game") ; //repaint() ; Graphics g = getGraphics() ; g.drawImage(buffer,0,0,this) ; // Initialize the launcher mouse_x = window_size.width/2 ; L = new Launcher(this) ; L.set_color(gunColor) ; // Initialize the missile M = new Missile(this) ; M.set_color(mColor) ; // Load the sound files now if (explosion == null) explosion = getAudioClip(getCodeBase(),"explosion.au") ; if (newufo == null) newufo = getAudioClip(getCodeBase(),"sonar.au") ; if (missile_launch == null) missile_launch = getAudioClip(getCodeBase(),"rocket.au") ; game_over = true ; newufo.play() ; // Play sounds missile_launch.play() ; explosion.play() ; } public void stop() { // Stop the game if running if (game != null) { game.stop() ; game = null ; // and eliminate the thread } // Reset the cursor getFrame(this).setCursor(Frame.DEFAULT_CURSOR) ; } // The main game thread public void run() { // Define some local variables UFO U ; Explosion E ; long count = 0 ; long ti = 0 ; // Wait for the images to load Graphics g = getGraphics() ; g.setColor(Color.red) ; g.drawString("Starting Game...", 20,20) ; while (tracker.checkAll(true) == false) { if ((ti++ % 2) == 0) g.setColor(Color.red) ; else g.setColor(Color.green) ; g.drawString("*", 10,22) ; try {Thread.sleep(50);} catch (InterruptedException e) { } ; if (ti > 1000) break ; } if (tracker.isErrorAny()) { showStatus("Error getting images") ; return ; } showStatus("Loading completed") ; g.dispose() ; // Paint the backdrop buffer buf_g = backdrop.getGraphics(); buf_g.drawImage(bgimg,0,0,window_size.width,window_size.height,this) ; // Paint the screen buf_g = getGraphics(); buf_g.drawImage(backdrop,0,0,this) ; // Paing the buffer buf_g = buffer.getGraphics(); buf_g.drawImage(bgimg,0,0,window_size.width,window_size.height,this) ; // Display the buffer repaint() ; // Display the initial setup display_score() ; L.draw() ; showStatus("UFO ATTACK") ; // Action loop for (;;) { ti = System.currentTimeMillis() ; // If there is place for one more UFO, try to add one // with some probability if ((UV.size() < NU) && (Math.random() > (UV.size() == 0 ? 0.90 : 0.98))) { newufo.play() ; // Play a bell U = new UFO(this) ; U.set_color(ufoColor) ; // Set the UFO to fast descent if: if (score > 10 && Math.random() > 0.7) U.vy -= 1 ; // Add UFO to the list UV.addElement(U) ; } // Draw the explosion in the backdrop // and eliminate it from the list if ended for (int j=EV.size()-1; j>=0 ; --j) { E = (Explosion) EV.elementAt(j) ; if (E.active) { // System.out.println("Drawing Explosion " + j) ; E.draw() ; } else { // System.out.println("Ending Explosion " + j) ; E.erase() ; EV.removeElementAt(j) ; } } // Move the launcher and the missile L.move() ; if (M.active() == true) M.move() ; // Move each UFO for (int i=0; i < UV.size(); ++i) { U = (UFO) UV.elementAt(i) ; U.move() ; } // Check for collision between UFO and missile for (int i=(UV.size()-1); i >=0 ; --i) { U = (UFO) UV.elementAt(i) ; if (U.active() && M.active() && U.collision(M)) { ++score ; explosion.stop() ; display_score() ; explosion.play() ; // Increase the max # of UFOs every 10 destroyed // till we reach a max of 5 attacking if ((NU < 5) && (score % 10) == 1) ++NU ; // Erase the missile and deactivate it M.active(false) ; M.erase() ; // Erase and deactivate the UFO hit U.active(false) ; U.erase() ; // Display an explosion E = new Explosion(this,U.px,U.py) ; // System.out.println("Adding Explosion") ; EV.addElement(E) ; } // Draw the UFO or eliminate it from the list if (U.active()) U.draw() ; else UV.removeElementAt(i) ; // If a UFO reaches the floor then you've lost if ((U.py - U.h/2) <=0) { game_over = true ; display_game_over() ; return ; } } // If the launcher moves... redraw if (L.has_moved() || ((M.py-M.h) < (L.py+L.h)) || (! M.active()) ) L.draw() ; // If active redraw the missile if (M.active() == true) M.draw() ; // Make the loop last 20ms in case the CPU is too fast... ti = System.currentTimeMillis() - ti ; ti = 20 - ti ; ti = ti > 0 ? 10 + ti : 10 ; // At least sleep por 10ms Thread.yield() ; // Let the GC work? try {Thread.sleep(ti);} catch (InterruptedException e) { } ; // Repaint every 100 cycles... just in case if ((count = ++count % 500) == 0) { repaint() ; // g.drawImage(buffer,0,0,this) ; } } } public void display_score() { Graphics bkd_g = backdrop.getGraphics(); bkd_g.clipRect(window_size.width/2, 0, window_size.width/2, 40); bkd_g.drawImage(bgimg,0,0,window_size.width,window_size.height,this) ; bkd_g.setColor(Color.red) ; bkd_g.setFont(font) ; String aux = score > 9 ? "" : "0" ; bkd_g.drawString(aux+score, window_size.width - 60,30) ; bkd_g.dispose() ; // bkd_g = null ; Graphics bg = buffer.getGraphics() ; bg.clipRect(0, 0, window_size.width, 40); bg.drawImage(backdrop,0,0,this) ; bg.dispose() ; // bg = null ; Graphics g = getGraphics() ; g.clipRect(0, 0, window_size.width, 40); g.drawImage(buffer,0,0,this) ; g.dispose() ; // g = null ; } public void display_game_over() { set_say_font(font) ; set_say_mode(CENTER) ; set_say_style(SHADOW) ; set_say_pos(10,80) ; say("GAME OVER") ; set_say_font(font_s) ; set_say_style(NORMAL) ; say("(click to start)") ; repaint() ; try {Thread.sleep(500);} catch (InterruptedException e) { } ; } public boolean mouseMove(Event e, int x, int y) { // showStatus("mouse at: (" + x + ", " + y + ")"); mouse_x = x ; return true; } // Capture the mouse clicks public boolean mouseDown(Event e, int x, int y) { if (game_over) { game_over = false ; if (game != null) { game.stop() ; game = null ; } NU = 1 ; score = 0 ; M.active(false) ; UV.removeAllElements() ; EV.removeAllElements() ; game = new Thread(this) ; game.setPriority(Thread.MIN_PRIORITY) ; game.start() ; buf_g.dispose() ; return true ; } if (M != null && ! M.active()) { missile_launch.stop() ; missile_launch.play() ; M.set_pos(L.px,L.py) ; M.active(true) ; } return true; } // The paint methos just draws the buffer public void paint(Graphics g) { if (buffer != null) g.drawImage(buffer, 0, 0, this); } // Makes an animation smoother public void update(Graphics g) { paint(g) ; } // Get the Frame of this applet public Frame getFrame(Component c) { while( c != null && !(c instanceof java.awt.Frame) ) c = c.getParent(); return (Frame) c; } // Text Display Constants public static final int CENTER = 1 ; // Modes: Centered public static final int LEFT = 2 ; // Left Justified public static final int RIGHT = 3 ; // Right Justified public static final int FREE = 0 ; // At x,y public static final int NORMAL = 0 ; // Styles: Normal public static final int SHADOW = 1 ; // Shadowed // Text Display Variables private int say_pos_y = 0 ; private int say_pos_x = 0 ; private int say_mode = -1 ; private int say_style = -1 ; private int say_margin = 10 ; private Font say_font = null ; // Text Print Methods public void say(String s, int x, int y) { set_say_pos(x, y) ; say(s) ; } public void say(String s) { FontMetrics fm = getFontMetrics(say_font) ; // Compute the x position switch(say_mode) { case CENTER: say_pos_x = (window_size.width - fm.stringWidth(s))/2 ; break ; case RIGHT: say_pos_x = window_size.width - fm.stringWidth(s) - say_margin ; break ; case LEFT: default : say_pos_x = say_margin ; break ; } Graphics bg = buffer.getGraphics() ; bg.setFont(say_font) ; // Print style extras if (say_style == SHADOW) { bg.setColor(new Color(150,150,150)) ; bg.drawString(s, say_pos_x+2,say_pos_y+1) ; } // Print string bg.setColor(Color.white) ; bg.drawString(s, say_pos_x,say_pos_y) ; // Shift y position to next line say_pos_y += (int) (1.2 * fm.getHeight()) ; // Free some resources bg.dispose() ; } public void set_say_mode(int m) { say_mode = m ; } public void set_say_style(int s) { say_style = s ; } public void set_say_font(Font f) { say_font = f ; } public void set_say_margin(int margin) { say_margin = margin ; } public void set_say_pos(int x, int y) { say_pos_x = x ; say_pos_y = y ; } } class Piece { UFO_Attack a ; int px,py ; int opx,opy ; int w,h ; int vx,vy ; Color c ; boolean active = false ; Image img = null ; public void set_pos(int x, int y) { px = opx = x ; py = opy = y ; } public void set_vel(int x,int y) { vx = x ; vy = y ; } public void set_size(int x,int y) { w = x ; h = y ; } public void set_color(Color c) { this.c = c ; } public void set_draw_rectangles(Rectangle o, Rectangle n) { int sh = a.window_size.height ; int x = px - w/2 ; int y = (sh - py) - h/2 ; int ox = opx - w/2 ; int oy = (sh - opy) - h/2 ; o.reshape(ox,oy,w,h) ; n.reshape(x,y,w,h) ; } public boolean active() { return active ; } public void active(boolean s) { active = s ; } public boolean collision(Piece p) { int dpx = Math.abs(px - p.px) ; int dpy = Math.abs(py - p.py) ; if ((dpx < (Math.max(w/2,p.w/2))+1) && (dpy < (Math.max(h/2,p.h/2)+1))) return true ; return false ; } public void draw() { set_draw_rectangles(a.paint_area, a.new_area) ; // a.buf_g.setColor(a.bgColor); // a.buf_g.fillRect(a.paint_area.x, a.paint_area.y, w, h); Graphics bg = a.buffer.getGraphics() ; bg.clipRect(a.paint_area.x, a.paint_area.y, w, h); bg.drawImage(a.backdrop,0,0,a) ; bg.dispose() ; // bg = null ; a.buf_g.setColor(c); a.buf_g.fillRect(a.new_area.x, a.new_area.y, w, h); a.paint_area.add(a.new_area) ; Graphics g = a.getGraphics() ; g.clipRect(a.paint_area.x ,a.paint_area.y, a.paint_area.width, a.paint_area.height); g.drawImage(a.buffer, 0, 0, a); g.dispose() ; // g = null ; } public void erase() { set_draw_rectangles(a.paint_area, a.new_area) ; a.paint_area.add(a.new_area) ; // Copy the backdrop into the buffer Graphics bg = a.buffer.getGraphics() ; bg.clipRect(a.paint_area.x, a.paint_area.y, a.paint_area.width, a.paint_area.height); bg.drawImage(a.backdrop,0,0,a) ; bg.dispose() ; // Paint the change into the screen Graphics g = a.getGraphics() ; g.clipRect(a.paint_area.x,a.paint_area.y,a.paint_area.width,a.paint_area.height); g.drawImage(a.buffer,0,0, a); g.dispose() ; } } class Launcher extends Piece { public Launcher (UFO_Attack a) { this.a = a ; w = 12 ; h = 22 ; px = opx = a.window_size.width/2 ; py = opy = w/2+1 ; active = true ; img = a.missile ; } public void move() { opx = px ; opy = py ; int dx = a.mouse_x - px ; int abs_dx = Math.abs(dx) ; int step = 1 ; if (abs_dx > 10) step = 5 ; else if (abs_dx > 1) step = abs_dx/2 ; if (dx != 0) { px += step*(dx/abs_dx) ; if (px < w/2) px = w/2 ; else if (px > (a.window_size.width - w/2)) px = a.window_size.width - w/2 ; } } public boolean has_moved() { if ((px - opx) != 0) return true ; return false ; } public void draw() { set_draw_rectangles(a.paint_area, a.new_area) ; // a.buf_g.setColor(a.bgColor); // a.buf_g.fillRect(a.paint_area.x, a.paint_area.y, w, h); Graphics bg = a.buffer.getGraphics() ; bg.clipRect(a.paint_area.x, a.paint_area.y, w, h); bg.drawImage(a.backdrop,0,0,a) ; bg.dispose() ; // bg = null ; if (a.M.active()) { a.buf_g.setColor(c); a.buf_g.fillRect(a.new_area.x, a.new_area.y, w, h); } else { bg = a.buffer.getGraphics() ; bg.clipRect(a.new_area.x, a.new_area.y, w, h); bg.drawImage(img,a.new_area.x,a.new_area.y,a) ; bg.dispose() ; // bg = null ; } a.paint_area.add(a.new_area) ; Graphics g = a.getGraphics() ; g.clipRect(a.paint_area.x ,a.paint_area.y, a.paint_area.width, a.paint_area.height); g.drawImage(a.buffer, 0, 0, a); g.dispose() ; // g = null ; } } class Missile extends Piece { public Missile (UFO_Attack a) { this.a = a ; px = opx = 0 ; py = opy = 0 ; vx = 0 ; vy = 7 ; w = 12 ; h = 22 ; active = false ; img = a.missile ; } public void move() { opx = px ; opy = py ; px = a.L.px ; // Try to make the speed more realistic int dx = px - opx ; int nvy = vy*vy - dx*dx ; if (nvy > 0) nvy = (int) Math.sqrt(nvy) ; // Should exceptions if (nvy < 1) nvy = 1 ; py += nvy ; if (py > a.window_size.height + 2*h) active = false ; } int seq = 0 ; // int seq2 = 0 ; public void draw() { set_draw_rectangles(a.paint_area, a.new_area) ; // a.buf_g.setColor(a.bgColor); // a.buf_g.fillRect(a.paint_area.x, a.paint_area.y, w, h); Graphics bg = a.buffer.getGraphics() ; bg.clipRect(a.paint_area.x, a.paint_area.y, w, h); bg.drawImage(a.backdrop,0,0,a) ; bg.dispose() ; // bg = null ; // if ((++seq2 % 4) == 0) seq = ++seq % 1 ; int dx = px - opx ; seq = 0 ; if (dx > 0) seq = 1 ; else if (dx < 0) seq = 2 ; bg = a.buffer.getGraphics() ; bg.clipRect(a.new_area.x, a.new_area.y, w, h); bg.drawImage(img,a.new_area.x-w*seq,a.new_area.y,a) ; bg.dispose() ; // bg = null ; a.paint_area.add(a.new_area) ; Graphics g = a.getGraphics() ; g.clipRect(a.paint_area.x ,a.paint_area.y, a.paint_area.width, a.paint_area.height); g.drawImage(a.buffer, 0, 0, a); g.dispose() ; // g = null ; } } class UFO extends Piece { public UFO (UFO_Attack a) { this.a = a ; vx = (Math.random() > 0.5 ? 1 : -1) ; vy = -2 ; w = 20 ; h = 8 ; int aw = a.window_size.width ; px = opx = (int) (w/2+1 + (aw-w-2)* Math.random()) ; py = opy = a.window_size.height + h/2 + 1 ; active = true ; img = a.ufostrip ; } public void move() { opx = px ; opy = py ; px += vx ; py += vy ; if (py < -h/2) active = false ; if ((px <= w/2) || (px >= (a.window_size.width - w/2)) || (Math.random() > 0.96)) { vx = -vx ; } } int seq = 0 ; int seq2 = 0 ; public void draw() { set_draw_rectangles(a.paint_area, a.new_area) ; // Clear the old image Graphics bg = a.buffer.getGraphics() ; bg.clipRect(a.paint_area.x, a.paint_area.y, w, h); bg.drawImage(a.backdrop,0,0,a) ; bg.dispose() ; // bg = null ; // Choose the image sequence (every 4 draws change frame) if ((++seq2 % 4) == 0) seq = ++seq % 4 ; // Paint new region into buffer bg = a.buffer.getGraphics() ; bg.clipRect(a.new_area.x, a.new_area.y, w, h); bg.drawImage(img,a.new_area.x-w*seq,a.new_area.y,a) ; bg.dispose() ; // Add old and new areas for updating a.paint_area.add(a.new_area) ; // Paint changes into screen buffer Graphics g = a.getGraphics() ; g.clipRect(a.paint_area.x ,a.paint_area.y, a.paint_area.width, a.paint_area.height); g.drawImage(a.buffer, 0, 0, a); g.dispose() ; } } class Explosion extends Piece { public Explosion (UFO_Attack a, int x, int y) { this.a = a ; w = 30 ; h = 30 ; px = opx = x ; py = opy = y ; active = true ; img = a.missile_explosion ; } int seq = 0 ; int seq2 = 0 ; public void draw() { set_draw_rectangles(a.paint_area, a.new_area) ; // Clear the old image Graphics bkd_g = a.backdrop.getGraphics(); bkd_g.clipRect(a.paint_area.x, a.paint_area.y, w, h); bkd_g.drawImage(a.bgimg,0,0,a.window_size.width,a.window_size.height,a) ; // Choose the image sequence (every 4 draws change frame) if ((++seq2 % 4) == 0) seq = ++seq % 5 ; // Deactivate after drawing the last explosion frame if (seq == 4) active = false ; // Paint new region into buffer bkd_g.clipRect(a.new_area.x, a.new_area.y, w, h); bkd_g.drawImage(img,a.new_area.x-w*seq,a.new_area.y,a) ; bkd_g.dispose() ; // Paint changes into the buffer Graphics bg = a.buffer.getGraphics() ; bg.clipRect(a.new_area.x,a.new_area.y,w,h); bg.drawImage(a.backdrop,0,0,a) ; bg.dispose() ; // Paint changes into screen buffer Graphics g = a.getGraphics() ; g.clipRect(a.paint_area.x ,a.paint_area.y, a.paint_area.width, a.paint_area.height); g.drawImage(a.buffer, 0, 0, a); g.dispose() ; } public void erase() { set_draw_rectangles(a.paint_area, a.new_area) ; // Clear the old image Graphics bkd_g = a.backdrop.getGraphics(); bkd_g.clipRect(a.paint_area.x, a.paint_area.y, w, h); bkd_g.drawImage(a.bgimg,0,0,a.window_size.width,a.window_size.height,a) ; bkd_g.dispose() ; // Do the same for the buffer and the screen // It will flicker any UFO on top... super.erase() ; } }