// CopyCat // // Intelligent camera // // Author Matthew Caryl // Created 18.4.96 package CopyCat; import java.awt.*; import ADT.*; final class CameraMan extends Camera { private Controller controls; private Tank target; private int state; private float x, y, z; private float pan, tilt; private float birdseye_x, birdseye_y, birdseye_z; private float birdseye_pan, birdseye_tilt; private float automatic_x, automatic_y, automatic_z; private float automatic_pan, automatic_tilt; // angle between first and second angle protected float angle(float first, float second) { float s = second - first; if (s > Math.PI) return s - 2f * (float) Math.PI; else if (s < -Math.PI) return s + 2f * (float) Math.PI; else return s; } private void turn(float p, float t) { switch (state) { case MANUAL: tilt += t; if (tilt < -Math.PI) tilt += 2 * Math.PI; else if (tilt > Math.PI) tilt -= 2 * Math.PI; pan += p; if (pan < -Math.PI) pan += 2 * Math.PI; else if (pan > Math.PI) pan -= 2 * Math.PI; break; case BIRDSEYE: birdseye_tilt += t; if (birdseye_tilt < -Math.PI) birdseye_tilt += 2 * Math.PI; else if (birdseye_tilt > Math.PI) birdseye_tilt -= 2 * Math.PI; birdseye_pan += p; if (birdseye_pan < -Math.PI) birdseye_pan += 2 * Math.PI; else if (birdseye_pan > Math.PI) birdseye_pan -= 2 * Math.PI; break; case AUTOMATIC: automatic_tilt += t; if (automatic_tilt < -Math.PI) automatic_tilt += 2 * Math.PI; else if (automatic_tilt > Math.PI) automatic_tilt -= 2 * Math.PI; automatic_pan += p; if (automatic_pan < -Math.PI) automatic_pan += 2 * Math.PI; else if (pan > Math.PI) automatic_pan -= 2 * Math.PI; break; } } private void move(float forwards, float sideways, float upwards) { switch (state) { case MANUAL: x -= (float) Math.sin(pan) * forwards - (float) Math.cos(pan) * sideways; y -= (float) Math.cos(pan) * forwards + (float) Math.sin(pan) * sideways; z += upwards; break; case BIRDSEYE: birdseye_x -= (float) Math.sin(birdseye_pan) * forwards + (float) Math.cos(birdseye_pan) * sideways; birdseye_y -= (float) Math.cos(birdseye_pan) * forwards + (float) Math.sin(birdseye_pan) * sideways; birdseye_z += upwards; break; case AUTOMATIC: automatic_x -= (float) Math.sin(automatic_pan) * forwards + (float) Math.cos(automatic_pan) * sideways; automatic_y -= (float) Math.cos(automatic_pan) * forwards + (float) Math.sin(automatic_pan) * sideways; automatic_z += upwards; break; } } private void tickAutomatic() { float a = target.heading(); float dx = x - target.x() + (float) (Math.cos(a) * automatic_x - Math.sin(a) * automatic_y); float dy = y - target.y() + (float) (Math.cos(a) * automatic_y + Math.sin(a) * automatic_x); float dz = z - (automatic_z - 0f); float dpan = automatic_pan - angle(pan, target.heading()); float dtilt = tilt - (automatic_tilt - 0f); x -= dx / 10f; y -= dy / 10f; z -= dz / 10f; pan -= dpan / 10f; tilt -= dtilt / 10f; if (pan < -Math.PI) pan += 2 * Math.PI; else if (pan > Math.PI) pan -= 2 * Math.PI; } private void tickBirdseye() { float dx = x + birdseye_x; float dy = y - birdseye_y; float dz = z - birdseye_z; float dpan = pan - birdseye_pan; float dtilt = tilt - birdseye_tilt; x -= dx / 20f; y -= dy / 20f; z -= dz / 20f; pan -= dpan / 20f; tilt -= dtilt / 20f; } private void controlCheck() { float forwards = 0f; if (controls.transfer(FORWARD)) forwards += 50f; if (controls.transfer(BACKWARD)) forwards -= 50f; float upwards = 0f; if (controls.transfer(UP)) upwards += 50f; if (controls.transfer(DOWN)) upwards -= 50f; float sideways = 0f; if (controls.transfer(LEFT)) sideways += 50f; if (controls.transfer(RIGHT)) sideways -= 50f; if (forwards != 0f || sideways != 0f || upwards != 0f) move(forwards, sideways, upwards); float tilt = 0f; if (controls.transfer(TILT_UP)) tilt += 0.03f; if (controls.transfer(TILT_DOWN)) tilt -= 0.03f; float pan = 0f; if (controls.transfer(PAN_CLOCKWISE)) pan += 0.03f; if (controls.transfer(PAN_ANTICLOCKWISE)) pan -= 0.03f; if (pan != 0f || tilt != 0f) turn(pan, tilt); if (controls.transfer(WIDEN)) setViewfield(getViewfield() * 1.1f); else if (controls.transfer(NARROW)) setViewfield(getViewfield() / 1.1f); } // // Public interface // public static final int FORWARD = 0; public static final int BACKWARD = 1; public static final int LEFT = 2; public static final int RIGHT = 3; public static final int UP = 4; public static final int DOWN = 5; public static final int PAN_CLOCKWISE = 6; public static final int PAN_ANTICLOCKWISE = 7; public static final int TILT_UP = 8; public static final int TILT_DOWN = 9; public static final int AUTOMATIC = 10; public static final int BIRDSEYE = 11; public static final int MANUAL = 12; public static final int WIDEN = 13; public static final int NARROW = 14; public CameraMan(Controller C, Tank T, float X, float Y, float Z, float PAN, float TILT) { super(200f); controls = C; target = T; x = birdseye_x = X; y = birdseye_y = Y; z = birdseye_z = Z; pan = birdseye_pan = PAN; tilt = birdseye_tilt = TILT; automatic_x = x - target.x(); automatic_y = y - target.y(); automatic_z = z - 0; automatic_pan = PAN - target.heading(); automatic_tilt = TILT - x; state = MANUAL; } public void tick() { if (controls.transfer(AUTOMATIC)) state = AUTOMATIC; else if (controls.transfer(BIRDSEYE)) state = BIRDSEYE; else if (controls.transfer(MANUAL)) state = MANUAL; controlCheck(); if (state == AUTOMATIC) tickAutomatic(); else if (state == BIRDSEYE) tickBirdseye(); moveTo(x, -y, z); turnTo(tilt, 0f, pan); } public void position(float X, float Y, float Z) { move(-x, -y, -z); move(X, Y, Z); } public void point(float P, float T) { turn(-pan, -tilt); turn(P, T); } }