// CopyCat Battle Tank Simulation Game // // Author Matthew Caryl // Created 26.3.97 package CopyCat; import java.awt.*; import ADT.*; import java.net.*; import java.lang.*; import java.applet.*; import java.io.*; public final class Game extends Applet implements Runnable { // // Private interface // private Thread animation; private Graphics graphics; private Random random = new Random(); private MediaTracker tracker; private int image_count = 0; private boolean loaded; private MessageBoard message_board; private EnergyBar gun_bar; private EnergyBar shield_bar; // // renderer system // private Image renderImage; private Graphics renderGraphics; private CameraMan cam; private Universe world; private Light light; private Image clouds; private void initialiseRender() { try { URL u = new URL(getDocumentBase(), "copycatpictures/clouds.gif"); clouds = getImage(u); tracker.addImage(clouds, image_count++); } catch (MalformedURLException e) { System.err.println("report to programmer - initialise render"); } Entity[] objs = new Entity[0]; light = new Light(0.3f, 0.7f); light.moveTo(1000f, 1000f, 5120f); int[] keys = new int[4]; keys[Tank.FORWARD] = Event.UP; keys[Tank.BACKWARD] = Event.DOWN; keys[Tank.CLOCKWISE] = Event.LEFT; keys[Tank.ANTICLOCKWISE] = Event.RIGHT; tank_controls = new KeyControls(keys); tank = new Tank(tank_controls); keys = new int[15]; keys[CameraMan.FORWARD] = '8'; keys[CameraMan.BACKWARD] = '2'; keys[CameraMan.LEFT] = '4'; keys[CameraMan.RIGHT] = '6'; keys[CameraMan.UP] = '7'; keys[CameraMan.DOWN] = '1'; keys[CameraMan.PAN_CLOCKWISE] = '0'; keys[CameraMan.PAN_ANTICLOCKWISE] = '.'; keys[CameraMan.TILT_UP] = '9'; keys[CameraMan.TILT_DOWN] = '3'; keys[CameraMan.AUTOMATIC] = 'a'; keys[CameraMan.BIRDSEYE] = 'b'; keys[CameraMan.MANUAL] = 'm'; keys[CameraMan.WIDEN] = '+'; keys[CameraMan.NARROW] = '-'; camera_controls = new KeyControls(keys); cam = new CameraMan(camera_controls, tank, 0f, 0f, 5120f, 0f, 0f); Dimension d = new Dimension(474, 198); world = new Universe(d.width, d.height, cam, light); addRender(tank); renderImage = this.createImage(d.width, d.height); renderGraphics = renderImage.getGraphics(); } private void destroyRender() { // do nothing } private void screenRender() { renderGraphics.drawImage(clouds, 0, 0, this); world.render(renderGraphics); } private void addRender(Entity o) { world.addEntity(o); } private Entity polygonsToObject() { Vector[] vs = new Vector[5 * 5]; int[] ts = new int[3 * 2 * 4 * 4]; Color[] cs = new Color[2 * 4 * 4]; int o; o = 5 * 5 - 1; for (int y = 4; y >= 0; y--) for (int x = 4; x >= 0; x--) vs[o--] = new Vector((float) (-2560 + x * 1280), (float) (-2560 + y * 1280), 0f); o = 2 * 4 * 4 - 1; for (int y = 3; y >= 0; y--) for (int x = 3; x >= 0; x--) { ts[3 * o + 0] = 5 * y + x; ts[3 * o + 1] = 5 * y + (x + 1); ts[3 * o + 2] = 5 * (y + 1) + (x + 1); cs[o--] = Color.white; ts[3 * o + 0] = 5 * (y + 1) + (x + 1); ts[3 * o + 1] = 5 * (y + 1) + x; ts[3 * o + 2] = 5 * y + x; cs[o--] = Color.white; } return new Entity(vs, ts, cs, null); } private void overlayRender(Image image, int x, int y) { renderGraphics.drawImage(image, x, y, this); } // // display system // private Image frame; private Image frame_corner; private void initialiseDisplay() { try { URL u1 = new URL(getDocumentBase(), "copycatpictures/frame.gif"); frame = getImage(u1); tracker.addImage(frame, image_count++); URL u2 = new URL(getDocumentBase(), "copycatpictures/framecorner.gif"); frame_corner = getImage(u2); tracker.addImage(frame_corner, image_count++); } catch (MalformedURLException e) { System.err.println("report to programmer - initialise display"); } } private void destroyDisplay() { // do nothing } private void prepaintDisplay() { graphics.setColor(Color.black); graphics.fillRect(0, 0, size().width, size().height); message_board.paint(graphics, 12, 230); } private void paintDisplay() { synchronized (frame_corner) { graphics.drawImage(frame, 0, 0, this); gun_bar.paint(graphics, 255, 210); shield_bar.paint(graphics, 255, 230); renderGraphics.drawImage(frame_corner, 224, 278, this); graphics.drawImage(renderImage, 19, 19, this); message_board.paint(graphics, 12, 230); } } private void updateDisplay() { synchronized (frame_corner) { renderGraphics.drawImage(frame_corner, 224, 178, this); graphics.drawImage(renderImage, 19, 19, this); if (message_board.dirty()) message_board.paint(graphics, 12, 230); if (gun_bar.dirty()) gun_bar.paint(graphics, 255, 210); if (shield_bar.dirty()) shield_bar.paint(graphics, 255, 230); } } // // Package interface // // // Public world interface // private BSPT bspt; private Polygon[] polygons; private static final int DESIRED_FRAME_TIME = 20; private static final String FRAMES_PER_SECOND = "fps"; private Tank tank; private KeyControls tank_controls; private KeyControls camera_controls; private int fps_message; public void init() { super.init(); // save graphics context for later // note: this seems to reduce garbage collection problems graphics = this.getGraphics(); tracker = new MediaTracker(this); initialiseDisplay(); message_board = new MessageBoard(graphics, 237, 14, this); gun_bar = new EnergyBar(245, 14, Color.black, Color.red, this); shield_bar = new EnergyBar(245, 14, Color.black, Color.green, this); initialiseRender(); Entity model = polygonsToObject(); addRender(model); model.moveTo(0f, 0f, -60f); requestFocus(); // track images int messageID = message_board.post("", true); for (int i = 0; i < image_count; i++) { message_board.update(messageID, i + ((i == 1) ? " image to load" : " images to load")); while (tracker.statusID(i, false) != MediaTracker.COMPLETE) { try { tracker.waitForID(i, DESIRED_FRAME_TIME); } catch (InterruptedException e) { // do nothing } if (tracker.isErrorID(i)) { message_board.post("Error in image, use blank"); break; } } } message_board.delete(messageID); // more initialisation message_board.post("JUST TESTING", true); message_board.post("FORGETTING"); fps_message = message_board.post("null " + FRAMES_PER_SECOND); loaded = true; } public void destroy() { destroyDisplay(); destroyRender(); if (animation != null && animation.isAlive()) animation.stop(); if (graphics != null) graphics.dispose(); super.destroy(); } public void start() { if (animation == null) { animation = new Thread(this); animation.start(); } } public void stop() { if (animation != null && animation.isAlive()) { animation.stop(); animation = null; } } public void run() { paint(graphics); gun_bar.setEnergy(0.5f); shield_bar.setEnergy(0.5f); float de = 0.01f; while (true) { long ticks = System.currentTimeMillis(); if (gun_bar.getEnergy() > 0.9f) de = -de; else if (gun_bar.getEnergy() < 0.1f) de = -de; gun_bar.setEnergy(gun_bar.getEnergy() + de); shield_bar.setEnergy(shield_bar.getEnergy() - de); tank.tick(); cam.tick(); screenRender(); updateDisplay(); try { Thread.sleep(Math.max(0, DESIRED_FRAME_TIME - (System.currentTimeMillis() - ticks))); } catch (InterruptedException e) { // do nothing } message_board.update(fps_message, 1000 / (System.currentTimeMillis() - ticks) + " " + FRAMES_PER_SECOND); } } public void paint(Graphics g) { if (loaded) paintDisplay(); else prepaintDisplay(); } public boolean keyDown(Event e, int key) { if (tank_controls.keyEvent(e)) return true; if (camera_controls.keyEvent(e)) return true; return super.keyDown(e, key); } public boolean keyUp(Event e, int key) { if (tank_controls.keyEvent(e)) return true; if (camera_controls.keyEvent(e)) return true; return super.keyDown(e, key); } public String[][] getParameterInfo() { String[][] info = {{"no parameters"}}; return info; } }