import java.applet.*; import java.awt.*; import java.awt.event.*; public abstract class RetroApplet extends Applet implements Runnable, KeyListener { private Image offScrImage = null; private Graphics offScrGr = null; private volatile Thread mainThread = null; private boolean UP = false, DOWN = false, LEFT = false, RIGHT = false; private boolean FIRE = false; private boolean PAUSED = false; private boolean showFPS = false; private int lastKey = -1; public static final int FIRE_KEY = 0, LEFT_KEY = 1, RIGHT_KEY = 2, UP_KEY = 3, DOWN_KEY = 4; public void keyPressed( KeyEvent ke ) { int key = ke.getKeyCode(); switch( key ) { case KeyEvent.VK_UP: UP = true; lastKey = UP_KEY; break; case KeyEvent.VK_DOWN: DOWN = true; lastKey = DOWN_KEY; break; case KeyEvent.VK_LEFT: LEFT = true; lastKey = LEFT_KEY; break; case KeyEvent.VK_RIGHT: RIGHT = true; lastKey = RIGHT_KEY; break; case KeyEvent.VK_SPACE: FIRE = true; lastKey = FIRE_KEY; break; } } public void keyReleased( KeyEvent ke ) { switch( ke.getKeyCode() ) { case KeyEvent.VK_UP: UP = false; break; case KeyEvent.VK_DOWN: DOWN = false; break; case KeyEvent.VK_LEFT: LEFT = false; break; case KeyEvent.VK_RIGHT: RIGHT = false; break; case KeyEvent.VK_SPACE: FIRE = false; break; case KeyEvent.VK_P: PAUSED = !PAUSED; break; case KeyEvent.VK_F: showFPS = !showFPS; break; } } public void keyTyped( KeyEvent ke ) {} public int lastKeyPressed() { return lastKey; } // key states public boolean up() { return UP; } public boolean down() { return DOWN; } public boolean left() { return LEFT; } public boolean right() { return RIGHT; } public boolean fire() { return FIRE; } public void init() { Dimension size = getSize(); offScrImage = createImage( size.width, size.height ); offScrGr = offScrImage.getGraphics(); addKeyListener( this ); addMouseListener( new MouseAdapter() { public void mouseReleased( MouseEvent me ) { requestFocus(); } } ); } public Graphics getBackBuffer() { return offScrGr; } private Font fpsFont = new Font( "SansSerif", Font.PLAIN, 12 ); public void flipBuffer() { Graphics g = getGraphics(); if ( showFPS ) { offScrGr.setFont( fpsFont ); offScrGr.setColor( Color.black ); offScrGr.drawString( "fps: " + fps, 5, 20 ); } if ( g != null ) g.drawImage( offScrImage, 0, 0, this ); } private Font pausedFont = new Font( "SansSerif", Font.BOLD, 20 ); private void showPaused() { String str = "Paused"; Dimension size = getSize(); offScrGr.setFont( pausedFont ); FontMetrics metrics = offScrGr.getFontMetrics(); int w = metrics.stringWidth( str ); int h = metrics.getHeight(); int a = metrics.getAscent(); offScrGr.setColor( Color.black ); offScrGr.fillRect( (size.width - w)>>1, (size.height>>1) -a-1, w, h+1 ); offScrGr.setColor( Color.white ); offScrGr.drawString( str, (size.width - w)>>1, size.height>>1 ); flipBuffer(); } public void start() { (mainThread = new Thread( this )).start(); } protected float fps = 0; public void run() { while( mainThread == Thread.currentThread() ) { long s = System.currentTimeMillis(); for ( int i = 0; i < 25; i++ ) { long start = System.currentTimeMillis(); if ( !PAUSED ) tick(); else showPaused(); long end = System.currentTimeMillis(); int time = 40 - (int)(end-start); time = time > 0? time : 0; try { Thread.sleep( time ); } catch( InterruptedException ie ) {} } long e = System.currentTimeMillis(); fps = 25000.0f/(e-s); } } public void stop() { mainThread = null; } public abstract void tick(); public void update( Graphics g ) { paint( g ); }; public void paint( Graphics g ) { if ( offScrImage != null ) g.drawImage( offScrImage, 0, 0, this ); } }