001: /*
002: *
003: * Copyright (c) 2007, Sun Microsystems, Inc.
004: *
005: * All rights reserved.
006: *
007: * Redistribution and use in source and binary forms, with or without
008: * modification, are permitted provided that the following conditions
009: * are met:
010: *
011: * * Redistributions of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: * * Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in the
015: * documentation and/or other materials provided with the distribution.
016: * * Neither the name of Sun Microsystems nor the names of its contributors
017: * may be used to endorse or promote products derived from this software
018: * without specific prior written permission.
019: *
020: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
021: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
022: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
023: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
024: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
025: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
026: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
027: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
028: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
029: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
030: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
031: */
032: package example.manyballs;
033:
034: import javax.microedition.lcdui.Canvas;
035: import javax.microedition.lcdui.Display;
036: import javax.microedition.lcdui.Graphics;
037:
038: public class ManyCanvas extends Canvas {
039: static int NUM_HISTORY = 8;
040: private static final int STATUSBAR_HEIGHT = 12;
041: Display display;
042:
043: // a set of free roaming balls
044: SmallBall[] balls;
045: int numBalls;
046: int width;
047: int height;
048: boolean paused;
049: boolean menuShowing;
050: long[] times = new long[NUM_HISTORY];
051: int times_idx;
052: private int threadCount;
053:
054: /**
055: * Draws the drawing frame (which also contains the ball) and the
056: * controls.
057: */
058: String msg = null;
059:
060: public ManyCanvas(Display d, int maxBalls) {
061: display = d; // save the display
062:
063: // initialize the array of balls
064: balls = new SmallBall[maxBalls];
065:
066: width = getWidth();
067: height = getHeight();
068:
069: // Start with one ball
070: balls[0] = new SmallBall(this , 0, 0, width, height
071: - STATUSBAR_HEIGHT);
072: numBalls = 1;
073: paused = true;
074: }
075:
076: protected void paint(Graphics g) {
077: int x = g.getClipX();
078: int y = g.getClipY();
079: int w = g.getClipWidth();
080: int h = g.getClipHeight();
081:
082: // Draw the frame
083: g.setColor(0xffffff);
084: g.fillRect(x, y, w, h);
085:
086: // Draw each ball
087: for (int i = 0; i < numBalls; i++) {
088: if (balls[i].inside(x, y, x + w, y + h)) {
089: balls[i].paint(g);
090: }
091: }
092:
093: g.setColor(0);
094: g.drawRect(0, 0, width - 1, height - 1);
095:
096: long now = System.currentTimeMillis();
097: String str = null;
098:
099: if (times_idx >= NUM_HISTORY) {
100: long oldTime = times[times_idx % NUM_HISTORY];
101:
102: if (oldTime == now) {
103: // in case of divide-by-zero
104: oldTime = now - 1;
105: }
106:
107: long fps = ((long) 1000 * (long) NUM_HISTORY)
108: / (now - oldTime);
109:
110: if ((times_idx % 20) == 0) {
111: str = numBalls + " Ball(s) " + fps + " fps";
112: }
113: } else {
114: if ((times_idx % 20) == 0) {
115: str = numBalls + " Ball(s)";
116: }
117: }
118:
119: if (msg != null) {
120: g.setColor(0xffffff);
121: g.setClip(0, height - STATUSBAR_HEIGHT, width, height);
122: g.fillRect(0, height - STATUSBAR_HEIGHT, width,
123: STATUSBAR_HEIGHT);
124:
125: g.setColor(0);
126: g.drawString(msg, 5, height - STATUSBAR_HEIGHT - 2, 0);
127: g.drawRect(0, 0, width - 1, height - 1);
128:
129: // draw a reflection line
130: g.drawLine(0, height - STATUSBAR_HEIGHT, w, height
131: - STATUSBAR_HEIGHT);
132:
133: msg = null;
134: }
135:
136: if (str != null) {
137: /*
138: * Do a complete repaint, so that the message will
139: * be shown even in double-buffer mode.
140: */
141: repaint();
142: msg = str;
143: }
144:
145: times[times_idx % NUM_HISTORY] = now;
146: ++times_idx;
147: }
148:
149: /**
150: * Handle a pen down event.
151: */
152: public void keyPressed(int keyCode) {
153: int action = getGameAction(keyCode);
154:
155: switch (action) {
156: case LEFT:
157:
158: // Reduce the number of threads
159: if (numBalls > 0) {
160: // decrement the counter
161: numBalls -= 1;
162:
163: // stop the thread and remove the reference to it
164: balls[numBalls].stop = true;
165: balls[numBalls] = null;
166: }
167:
168: break;
169:
170: case RIGHT:
171:
172: // Increase the number of threads
173: if (numBalls < balls.length) {
174: // create a new ball and start it moving
175: balls[numBalls] = new SmallBall(this , 0, 0, width,
176: height - STATUSBAR_HEIGHT);
177: new Thread(balls[numBalls]).start();
178:
179: // increment the counter
180: numBalls += 1;
181: }
182:
183: break;
184:
185: case UP:
186: // Make them move faster
187: SmallBall.faster();
188:
189: break;
190:
191: case DOWN:
192: // Make them move slower
193: SmallBall.slower();
194:
195: break;
196: }
197:
198: repaint();
199: }
200:
201: void destroy() {
202: // kill all the balls and terminate
203: for (int i = 0; (i < balls.length) && (balls[i] != null); i++) {
204: balls[i].stop = true;
205:
206: // enable the balls to be garbage collected
207: balls[i] = null;
208: }
209:
210: numBalls = 0;
211: }
212:
213: /*
214: * Return whether the canvas is paused or not.
215: */
216: boolean isPaused() {
217: return paused;
218: }
219:
220: protected void hideNotify() {
221: menuShowing = true;
222: doPause();
223: }
224:
225: protected void showNotify() {
226: if (!paused && menuShowing) {
227: doStart();
228: }
229:
230: menuShowing = false;
231: }
232:
233: /**
234: * Pause the balls by signaling each of them to stop.
235: * The ball object still exists and holds the current position
236: * of the ball. It may be restarted later.
237: * The thread will terminate.
238: * TBD: is a join needed?
239: */
240: void pause() {
241: if (!paused) {
242: paused = true;
243: doPause();
244: }
245:
246: repaint();
247: }
248:
249: private void doPause() {
250: for (int i = 0; (i < balls.length) && (balls[i] != null); i++) {
251: balls[i].stop = true;
252: }
253:
254: waitForSpecifiedNumberOfThreads(0);
255: repaint();
256: }
257:
258: /*
259: * Start creates a new thread for each ball and start it.
260: */
261: void start() {
262: if (paused) {
263: paused = false;
264: doStart();
265: }
266:
267: repaint();
268: }
269:
270: private void doStart() {
271: display.setCurrent(this );
272:
273: for (int i = 0; (i < balls.length) && (balls[i] != null); i++) {
274: Thread t = new Thread(balls[i]);
275: t.start();
276: }
277:
278: waitForSpecifiedNumberOfThreads(numBalls);
279: repaint();
280: }
281:
282: public void notifyBallThreadStarted() {
283: synchronized (this ) {
284: threadCount++;
285: notifyAll();
286: }
287: }
288:
289: public void notifyBallThreadStopped() {
290: synchronized (this ) {
291: threadCount--;
292: notifyAll();
293: }
294: }
295:
296: public void waitForSpecifiedNumberOfThreads(final int threadNumber) {
297: try {
298: synchronized (this ) {
299: while (threadCount != threadNumber) {
300: wait();
301: }
302: }
303: } catch (InterruptedException e) {
304: e.printStackTrace();
305: }
306: }
307: }
|