// Traffic.java, version 1.12, July 4, 2008. // Applet for traffic simulation. // Copyright 1998-2008 by Rick Wagner, all rights reserved. // No use without attribution. import java.applet.*; import java.awt.*; // This is an educational example of object oriented design for a traffic simulation applet. // Use of this source code is authorized for educational purposes only. No use without // proper attribution to Rick Wagner (wagner@pollux.usc.edu) at the University of Southern // California. // Compiled with the Sun JDK 1.6 and written for the JDK 1.0 so it will run in all browsers. // The prefix naming convention used here is a modified Hungarian notation. // "s" is string, "sf" is single precision floating point, "i" is integer, "b" is boolean, // "d" is dimension, and "c" is color. public class Traffic extends Applet { // Applet instance variables: private String sVerNum = "1.12"; // Only constructors can run here ("" is a constructor) private Dimension dApplet; // The applet panel size (read from the html file) private Image imOffScreen = null; // Offscreen image for double buffering private Graphics grOffScreen = null; // Offscreen graphics for double buffering private int iNumCars = 7; // Initial number of race cars private int iMaxNumCars = 50; private Car CarArray[] = new Car[iMaxNumCars]; // Array of race cars private float sfRadius; // Turn radius in car lengths private boolean bStartStop = false; // Flag to toggle mouse click state private Timer AnimationTimer; // Timer for control of the animation rate private int iTimerInterval; // Timer interval in milliseconds private Label MessageLabel; private int iTimeCounter = 0; // Time counter for measurement purposes private boolean iNewCarInhibit = false; // Inhibit createing multiple cars at once // To allow browsers to get information about the applet: public String getAppletInfo() { return "Traffic applet, version " + sVerNum + ", by Rick Wagner, copyright 1998-2008,\nall rights reserved.\n\n" + "This is an educational example of object oriented design \n" + "using a timer to control animation rate.\n\n" + "Compiled July 4, 2008 with JDK 1.6. Source code use authorized for\n" + "educational purposes only. No use without attribution.\n"; } // Initialize the applet public void init() { this.setBackground(Color.lightGray); dApplet = this.size(); int i; sfRadius = 8; float sfTheta = -1 * (float) (Math.PI / 2); float x = 10; float y = -8; for (i = 0; i < iNumCars; i++) { if (x > 0) { x -= 2; CarArray[i] = new Car(x, y, 0); } else { sfTheta -= 2 / sfRadius; // Two car lengths behind x = (float) (sfRadius * Math.cos(sfTheta)); y = (float) (sfRadius * Math.sin(sfTheta)); CarArray[i] = new Car(x, y, sfTheta + (float) (Math.PI / 2)); } } setCarColors(); iTimerInterval = 33; // 33 ms is 30 frames per sec (TV rate) AnimationTimer = new Timer(this, iTimerInterval); // 40 ms is 25 frames per sec, 67 is 15 MessageLabel = new Label("Welcome to Traffic Simulation. Click to start."); MessageLabel.setAlignment(Label.CENTER); add(MessageLabel); } // End of init() // Execute this code after initialization public void start() { this.requestFocus(); // So we can get keyboard input System.out.println("\n" + this.getAppletInfo()); // Identify self to the Java console-aware user } // End of start() // Execute this code when the browser leaves the page: public void stop() { bStartStop = false; MessageLabel.setText("Click to start."); AnimationTimer.stop(); } // End of stop(); public void onTimer() // Called by the timer { int i; for (i = 0; i < iNumCars; i++) { CarArray[i].update(i); // Update the cars based on speed and position } repaint(); } // The applet frame painting function public void paint(Graphics g) { // Code for displaying images or drawing in the applet frame g.clearRect(0, 0, dApplet.width, dApplet.height); this.setBackground(Color.lightGray); int i; // Paint the race track: g.setColor(Color.gray); g.fillArc((int) (1.5 * 20), (int) (1.5 * 20), (int) (17 * 20), (int) (17 * 20), 0, 360); g.fillArc((int) (1.5 * 20) + 200, (int) (1.5 * 20), (int) (17 * 20), (int) (17 * 20), 0, 360); g.fillRect((int) (10 * 20), (int) (1.5 * 20), (int) (10 * 20), (int) (17 * 20)); g.setColor(Color.lightGray); g.fillArc((int) (2.5 * 20), (int) (2.5 * 20), (int) (15 * 20), (int) (15 * 20), 0, 360); g.fillArc((int) (2.5 * 20) + 200, (int) (2.5 * 20), (int) (15 * 20), (int) (15 * 20), 0, 360); g.fillRect((int) (10 * 20), (int) (2.5 * 20), (int) (10 * 20), (int) (15 * 20)); // Paint the cars: for (i = 0; i < iNumCars; i++) { CarArray[i].paint(g); } // Draw a recessed frame around the applet border. Designed for gray-on-gray browser background. g.setColor(Color.black); g.drawLine(0, 0, dApplet.width - 1, 0); g.drawLine(0, 0, 0, dApplet.height - 1); g.setColor(Color.white); g.drawLine(0, dApplet.height - 1, dApplet.width - 1, dApplet.height - 1); g.drawLine(dApplet.width - 1, 1, dApplet.width - 1, dApplet.height - 1); } // End of paint() // Implements double buffering public void update(Graphics g) { if (imOffScreen == null) { // Make sure the offscreen and graphics exist imOffScreen = this.createImage(dApplet.width, dApplet.height); grOffScreen = imOffScreen.getGraphics(); grOffScreen.clearRect(0, 0, dApplet.width, dApplet.height); } this.paint(grOffScreen); g.drawImage(imOffScreen, 0, 0, null); } public boolean mouseDown(Event e, int x, int y) { int i = 0; bStartStop = !bStartStop; if (bStartStop) { MessageLabel.setText("Click to stop."); this.showStatus("Click to stop."); AnimationTimer.start(); } else { MessageLabel.setText("Click to start."); this.showStatus("Click to start."); AnimationTimer.stop(); for (i = 0; i < iNumCars; i++) CarArray[i].setSpeed(0); } this.requestFocus(); // Added July 4, 2008: works around bug added in return true; // Java 2SE. } public boolean keyDown(Event e, int k) { float x = 0; float y = 0; float a = 0; int iRegime = 0; if (k == 32) { if (bStartStop) { if (iNumCars < iMaxNumCars && !iNewCarInhibit) { this.showStatus("Spacebar pressed, adding one car to " + String.valueOf(iNumCars) + " cars."); x = CarArray[iNumCars - 1].getPx(); y = CarArray[iNumCars - 1].getPy(); a = CarArray[iNumCars - 1].getDirection(); iNumCars++; CarArray[iNumCars - 1] = new Car(x, y, a); CarArray[iNumCars - 1].setSpeed(CarArray[iNumCars - 2].getSpeed() * ((float) 0.9)); CarArray[iNumCars - 1].setColor(get10Color((iNumCars - 1) % 10)); } else { this.showStatus("Spacebar pressed, " + String.valueOf(iNumCars) + " cars."); } } else { this.showStatus("Spacebar pressed."); } } else { this.showStatus("Key pressed: " + String.valueOf(k)); } return true; } private void setCarColors() { int i = 0; for (i = 0; i < iNumCars; i++) { CarArray[i].setColor(get10Color(i % 10)); } } private Color get10Color(int i) { Color c = null; switch (i) { case 0: { c = Color.red; break; } case 1: { c = Color.blue; break; } case 2: { c = Color.white; break; } case 3: { c = Color.green; break; } case 4: { c = Color.yellow; break; } case 5: { c = Color.cyan; break; } case 6: { c = Color.orange; break; } case 7: { c = Color.pink; break; } case 8: { c = Color.magenta; break; } case 9: { c = Color.yellow.darker(); break; } } return c; } class Car { private float sfCarLength; private float sfThrottle; // Throttle setting (0 to 1) private float sfBrake; // Brake setting (0 to 1) private float sfSpeed; // Scalar speed of the car private float sfAccel; // Scalar acceleration of the car private float sfDirection; // Direction of travel in radians from east. private float sfPx; // Position private float sfPy; private float sfX[] = new float[4]; private float sfY[] = new float[4]; private int iX[] = new int[4]; // Integer arrays for constructing the polygon for painting private int iY[] = new int[4]; private float sfPaintScaleFactor; private Color cCar; private Dimension d; public Car() // Default constructor { cCar = Color.white; sfCarLength = 1; // Car is one car length long sfThrottle = 0; sfBrake = 0; sfSpeed = 0; sfAccel = 0; sfPx = 0; sfPy = 0; sfPaintScaleFactor = 20; // Car is painted 20 pixels long pose(0, 0, 0); } public Car(float px, float py, float theta) // Position and direction constructor { cCar = Color.white; sfCarLength = 1; // Car is one car length long sfThrottle = 0; sfBrake = 0; sfSpeed = 0; sfAccel = 0; sfPx = px; sfPy = py; sfPaintScaleFactor = 20; // Car is painted 20 pixels long pose(sfPx, sfPy, normalizeAngle(theta)); } public void setColor(Color c) { cCar = c; } public void setSpeed(float s) { sfSpeed = s; } public float getSpeed() { return sfSpeed; } private void pose(float x, float y, float a) { // Sets the position and orientation of the car: int i; float sfTempX; float sfTempY; sfX[0] = (float) -.5; sfY[0] = (float) -.25; sfX[1] = (float) .5; sfY[1] = (float) -.25; sfX[2] = (float) .5; sfY[2] = (float) .25; sfX[3] = (float) -.5; sfY[3] = (float) .25; float sfSin = (float) Math.sin(a); // Compute these just once float sfCos = (float) Math.cos(a); for (i = 0; i <= 3; i++) { sfTempX = sfX[i]; sfTempY = sfY[i]; sfX[i] = x + sfTempX * sfCos - sfTempY * sfSin; sfY[i] = y + sfTempX * sfSin + sfTempY * sfCos; } sfPx = x; sfPy = y; sfDirection = a; } private float getPx() { return sfPx; } private float getPy() { return sfPy; } private float getDirection() { return sfDirection; } public void update(int iMyIndex) { float sfDeltaDistance = 0; float sfDeltaTheta = 0; float sfAngleToCar = 0; float sfDistanceToCar = 0; float sfTargetDistance = 0; float sfMyAngle; float sfLeadAngle; float sfMaxSpeed = (float) .25; // Quarter of a car length per update is the fastest float sfSpeedAttenuation = 0; float sfTempDirection = 0; float sfTempX = 0; float sfTempY = 0; int iLeadIndex = (iMyIndex - 1); if (iLeadIndex < 0) iLeadIndex = iNumCars - 1; int iMyRegime; int iLeadRegime; float sfDeltaSpeed = 0; iNewCarInhibit = false; // Determine the regime for applying updates: iMyRegime = getRegime(iMyIndex); iLeadRegime = getRegime(iLeadIndex); sfDistanceToCar = getDistance(iMyRegime, iLeadRegime, iLeadIndex); // Compute the ideal following distance: sfTargetDistance = (float) 17.0 * sfSpeed + (float) 1.0; // Linear function of my speed (about 4 center-to-center, max) if (sfDistanceToCar > sfTargetDistance) { // We need to catch up to the car: sfThrottle = (float) 1.0 * ((sfDistanceToCar - sfTargetDistance) / sfDistanceToCar); sfBrake = (float) 0.0; } else { if (sfDistanceToCar > sfTargetDistance * 3.0 / 4.0) { // We need to back off the gas: sfThrottle = (float) 0; sfBrake = (float) 0.2; } else { if (sfDistanceToCar > sfTargetDistance / 2.0) { // We need to touch the brakes: sfThrottle = (float) 0; sfBrake = (float) 0.7; } else { if (sfDistanceToCar > 1.0) { // We need to slam on the brakes: sfThrottle = (float) 0; sfBrake = (float) 1.0; } else { // Too late. Collision. iNewCarInhibit = true; } } } } // Acceleration decreases with speed sfSpeedAttenuation = ((float) 1.0 - sfSpeed / sfMaxSpeed); sfAccel = (float) (sfSpeedAttenuation * sfThrottle * .01 - sfBrake * .01); sfSpeed += sfAccel; if (sfSpeed < 0) sfSpeed = 0; // Can't go backwards if (sfSpeed > sfMaxSpeed) sfSpeed = sfMaxSpeed; // Speed limit if (sfDistanceToCar < (float) 1.0) { // Collision if (CarArray[iLeadIndex].sfSpeed < sfSpeed) { sfSpeed = CarArray[iLeadIndex].sfSpeed; } else { // We have a newly created car within us, inhibit new cars. iNewCarInhibit = true; } } sfDeltaDistance = sfSpeed; // If the regime is an even number then we're in a turn: if (iMyRegime % 2 == 0) { sfTempDirection = sfDirection + (sfDeltaDistance / sfRadius); if (iMyRegime == 2) { // East turn: sfTempX = (float) ((sfRadius * Math.cos(sfTempDirection - (float) (Math.PI / 2.0))) + 10); sfTempY = (float) ((sfRadius * Math.sin(sfTempDirection - (float) (Math.PI / 2.0)))); } else { // West turn: sfTempX = (float) (sfRadius * Math.cos(sfTempDirection - (float) (Math.PI / 2.0))); sfTempY = (float) (sfRadius * Math.sin(sfTempDirection - (float) (Math.PI / 2.0))); } } else { // We're on a straight: if (iMyRegime == 1) { // Bottom straight: sfTempX = sfPx + sfSpeed; sfTempY = -8; sfTempDirection = 0; } else { // Top straight: sfTempX = sfPx - sfSpeed; sfTempY = 8; sfTempDirection = (float) (Math.PI); } } CarArray[iMyIndex].pose(sfTempX, sfTempY, sfTempDirection); // Move the car to the new pose } // End of Car.update() public int getRegime(int i) { int iRegime = 0; if (CarArray[i].sfPx <= 0) { // We're in the west turn iRegime = 4; } else { if (CarArray[i].sfPx >= 10) { // We're in the east turn iRegime = 2; } else { // We're on a straight if (CarArray[i].sfPy > 0) { // We're on the top straight iRegime = 3; } else { // We're on the bottom straight iRegime = 1; } } } return iRegime; } private float getDistance(int iARegime, int iBRegime, int iBIndex) { float d = 0; float sfAAngle = 0; float sfBAngle = 0; float sfAngleToCar = 0; float sfATurnD = 0; float sfBTurnD = 0; float sfAStraightD = 0; float sfBStraightD = 0; switch (iARegime) { case 1: // I'm on the bottom straight { switch (iBRegime) { case 1: // He's on the bottom straight { d = CarArray[iBIndex].sfPx - sfPx; break; } case 2: // He's in the east turn (on the right) { sfAStraightD = 10 - sfPx; sfAAngle = - (float) (Math.PI / 2.0); sfBAngle = normalizeAngle(CarArray[iBIndex].sfDirection - (float) (Math.PI / 2.0)); sfAngleToCar = sfBAngle - sfAAngle; if (sfAngleToCar < 0) sfAngleToCar += (float) (Math.PI * 2.0); sfBTurnD = sfAngleToCar * sfRadius; d = sfAStraightD + sfBTurnD; break; } case 3: // He's on the top straight { sfAStraightD = 10 - sfPx; sfBTurnD = ((float) Math.PI) * sfRadius; sfBStraightD = 10 - CarArray[iBIndex].sfPx; d = sfAStraightD + sfBTurnD + sfBStraightD; break; } case 4: // He's in the west turn (on the left) { sfAStraightD = 10 - sfPx; sfBTurnD = ((float) Math.PI) * sfRadius; sfBStraightD = 10; sfAAngle = (float) (Math.PI / 2.0); sfBAngle = normalizeAngle(CarArray[iBIndex].sfDirection - (float) (Math.PI / 2.0)); sfAngleToCar = sfBAngle - sfAAngle; if (sfAngleToCar < 0) sfAngleToCar += (float) (Math.PI * 2.0); sfBTurnD += sfAngleToCar * sfRadius; d = sfAStraightD + sfBTurnD + sfBStraightD; break; } } break; } case 2: // I'm on the east turn (on the right) { switch (iBRegime) { case 1: // He's on the bottom straight { sfAAngle = normalizeAngle(sfDirection - (float) (Math.PI / 2.0)); sfBAngle = (float) (Math.PI / 2); sfAngleToCar = sfBAngle - sfAAngle; if (sfAngleToCar < 0) sfAngleToCar += (float) (Math.PI * 2.0); sfATurnD = sfAngleToCar * sfRadius; sfAStraightD = 10; sfBTurnD = ((float) Math.PI) * sfRadius; sfBStraightD = CarArray[iBIndex].sfPx; d = sfATurnD + sfAStraightD + sfBTurnD + sfBStraightD; break; } case 2: // He's in the east turn { sfAAngle = normalizeAngle(sfDirection - (float) (Math.PI / 2.0)); sfBAngle = normalizeAngle(CarArray[iBIndex].sfDirection - (float) (Math.PI / 2.0)); sfAngleToCar = sfBAngle - sfAAngle; if (sfBAngle > sfAAngle) { // He's ahead of me in this turn d = sfAngleToCar * sfRadius; } else { // He's behind me sfAngleToCar = ((float) (Math.PI * 2)) + sfAngleToCar; d = sfAngleToCar * sfRadius + 20; } break; } case 3: // He's on the top straight { sfAAngle = normalizeAngle(sfDirection - (float) (Math.PI / 2.0)); sfBAngle = (float) (Math.PI / 2.0); sfAngleToCar = sfBAngle - sfAAngle; if (sfAngleToCar < 0) sfAngleToCar += (float) (Math.PI * 2.0); sfATurnD = sfAngleToCar * sfRadius; sfBStraightD = 10 - CarArray[iBIndex].sfPx; d = sfATurnD + sfBStraightD; break; } case 4: // He's in the west turn (on the left) { sfAAngle = normalizeAngle(sfDirection - (float) (Math.PI / 2.0)); sfBAngle = (float) (Math.PI / 2.0); sfAngleToCar = sfBAngle - sfAAngle; if (sfAngleToCar < 0) sfAngleToCar += (float) (Math.PI * 2.0); sfATurnD = sfAngleToCar * sfRadius; sfBStraightD = 10; sfAAngle = (float) (Math.PI / 2.0); sfBAngle = normalizeAngle(CarArray[iBIndex].sfDirection - (float) (Math.PI / 2.0)); sfAngleToCar = sfBAngle - sfAAngle; if (sfAngleToCar < 0) sfAngleToCar += (float) (Math.PI * 2.0); sfBTurnD = sfAngleToCar * sfRadius; d = sfATurnD + sfBStraightD + sfBTurnD; break; } } break; } case 3: // I'm on the top straight { switch (iBRegime) { case 1: // He's on the bottom straight { sfAStraightD = sfPx; sfBTurnD = ((float) Math.PI) * sfRadius; sfBStraightD = CarArray[iBIndex].sfPx; d = sfAStraightD + sfBTurnD + sfBStraightD; break; } case 2: // He's in the east turn { sfAStraightD = sfPx; sfATurnD = ((float) Math.PI) * sfRadius; sfBStraightD = 10; sfAAngle = - (float) (Math.PI / 2.0); sfBAngle = normalizeAngle(CarArray[iBIndex].sfDirection - (float) (Math.PI / 2.0)); sfAngleToCar = sfBAngle - sfAAngle; if (sfAngleToCar < 0) sfAngleToCar += (float) (Math.PI * 2.0); sfBTurnD = sfAngleToCar * sfRadius; d = sfAStraightD + sfATurnD + sfBStraightD + sfBTurnD; break; } case 3: // He's on the top straight { d = sfPx - CarArray[iBIndex].sfPx; break; } case 4: // He's in the west turn { sfAStraightD = sfPx; sfAAngle = (float) (Math.PI / 2.0); sfBAngle = normalizeAngle(CarArray[iBIndex].sfDirection - (float) (Math.PI / 2.0)); sfAngleToCar = sfBAngle - sfAAngle; if (sfAngleToCar < 0) sfAngleToCar += (float) (Math.PI * 2.0); sfBTurnD = sfAngleToCar * sfRadius; d = sfAStraightD + sfBTurnD; break; } } break; } case 4: // I'm in the west turn (on the left) { switch (iBRegime) { case 1: // He's on the bottom straight { sfAAngle = normalizeAngle(sfDirection - (float) (Math.PI / 2.0)); sfBAngle = -(float) (Math.PI / 2); sfAngleToCar = sfBAngle - sfAAngle; if (sfAngleToCar < 0) sfAngleToCar += (float) (Math.PI * 2.0); sfATurnD = sfAngleToCar * sfRadius; sfAStraightD = CarArray[iBIndex].sfPx; d = sfATurnD + sfAStraightD; break; } case 2: // He's in the east turn (on the right) { sfAAngle = normalizeAngle(sfDirection - (float) (Math.PI / 2.0)); sfBAngle = -(float) (Math.PI / 2); sfAngleToCar = sfBAngle - sfAAngle; if (sfAngleToCar < 0) sfAngleToCar += (float) (Math.PI * 2.0); sfATurnD = sfAngleToCar * sfRadius; sfAStraightD = 10; sfAAngle = -(float) (Math.PI / 2); sfBAngle = normalizeAngle(CarArray[iBIndex].sfDirection - (float) (Math.PI / 2.0)); sfAngleToCar = sfBAngle - sfAAngle; if (sfAngleToCar < 0) sfAngleToCar += (float) (Math.PI * 2.0); sfBTurnD = sfAngleToCar * sfRadius; d = sfATurnD + sfAStraightD + sfBTurnD; break; } case 3: // He's on the top straight { sfAAngle = normalizeAngle(sfDirection - (float) (Math.PI / 2.0)); sfBAngle = -(float) (Math.PI / 2); sfAngleToCar = sfBAngle - sfAAngle; if (sfAngleToCar < 0) sfAngleToCar += (float) (Math.PI * 2.0); sfATurnD = sfAngleToCar * sfRadius; sfAStraightD = 10; sfBTurnD = ((float) Math.PI) * sfRadius; sfBStraightD = 10 - CarArray[iBIndex].sfPx; d = sfATurnD + sfAStraightD + sfBTurnD + sfBStraightD; break; } case 4: // He's in the west turn { boolean bBLeads = false; sfAAngle = normalizeAngle(sfDirection - (float) (Math.PI / 2.0)); sfBAngle = normalizeAngle(CarArray[iBIndex].sfDirection - (float) (Math.PI / 2.0)); if (sfAAngle >= 0) { if (sfBAngle >= 0) { // Both a and b positive if (sfAAngle > sfBAngle) {;} else { // b leads a bBLeads = true; } } else { if (sfAAngle > sfBAngle) { // b leads a bBLeads = true; } else {;} } } else { if (sfBAngle >= 0) { if (sfAAngle > sfBAngle) { // b leads a bBLeads = true; } else {;} } else { // Both a and b negative if (sfAAngle > sfBAngle) {;} else { // b leads a bBLeads = true; } } } if (bBLeads) { sfAngleToCar = sfBAngle - sfAAngle; if (sfAngleToCar < 0) sfAngleToCar += (float) (Math.PI * 2.0); d = sfAngleToCar * sfRadius; } else { sfAngleToCar = sfAAngle - sfBAngle; if (sfAngleToCar < 0) sfAngleToCar += (float) (Math.PI * 2.0); sfAngleToCar = ((float) (Math.PI * 2)) - sfAngleToCar; d = sfAngleToCar * sfRadius + 20; } break; } } break; } } return d; } public void paint(Graphics g) { Polygon pgon; int i; for (i = 0; i <= 3; i++) { iX[i] = 200 + Math.round(sfPaintScaleFactor * sfX[i]); // Get the polygon for painting iY[i] = 200 - Math.round(sfPaintScaleFactor * sfY[i]); } pgon = new Polygon(iX, iY, 4); g.setColor(cCar); g.fillPolygon(pgon); g.setColor(Color.black); g.drawPolygon(pgon); } private float normalizeAngle(float a) // Normalize angle to +/- pi radians { float r = a; if (a > Math.PI) r -= (float) (Math.PI * 2.0); if (a <= -Math.PI) r += (float) (Math.PI * 2.0); return r; } } // End of Car class } // End of Applet class class Timer implements Runnable { // Calls the onTimer() function in the calling applet every iInterval milliseconds. // Copyright 1998 and 1999 by Rick Wagner, all rights reserved. No use without attribution. private Thread TimerThread; private int iInterval; private Traffic app; // The calling applet public Timer(Traffic a, int i) // Interval constructor { iInterval = i; app = a; } public void start() { TimerThread = new Thread(this); TimerThread.start(); } public void stop() { if (TimerThread != null) TimerThread.stop(); TimerThread = null; } public void run() { long lStartTime = System.currentTimeMillis(); long lTemp = 0; int iSleepTime = iInterval / 10; if (iSleepTime == 0) iSleepTime = 1; while (true) { try { TimerThread.sleep(iSleepTime); // Wake up every 1/10 interval and see } // if it's time yet. catch(InterruptedException e1) { } lTemp = System.currentTimeMillis(); if (lTemp - lStartTime >= iInterval) { app.onTimer(); // Trigger the desired events. lStartTime = lTemp; } } } } // End of Timer class