Source code: com/siemens/mp/color_game/Sprite.java
1 /*
2 * Siemens API for MicroEmulator
3 * Copyright (C) 2003 Markus Heberling <markus@heberling.net>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19 package com.siemens.mp.color_game;
20
21 import javax.microedition.lcdui.Image;
22 import javax.microedition.lcdui.Graphics;
23
24 public class Sprite extends Layer {
25
26 public static final int TRANS_NONE = 0;
27 public static final int TRANS_ROT90 = 5;
28 public static final int TRANS_ROT180 = 3;
29 public static final int TRANS_ROT270 = 6;
30 public static final int TRANS_MIRROR = 2;
31 public static final int TRANS_MIRROR_ROT90 = 7;
32 public static final int TRANS_MIRROR_ROT180 = 1;
33 public static final int TRANS_MIRROR_ROT270 = 4;
34
35 public Sprite(Image image) {
36 super(image.getWidth(), image.getHeight());
37
38 initializeFrames(image, image.getWidth(), image.getHeight(), false);
39
40 // initialize collision rectangle
41 initCollisionRectBounds();
42 }
43
44 public Sprite(Image image, int frameWidth, int frameHeight) {
45
46 super(frameWidth, frameHeight);
47 // if img is null img.getWidth() will throw NullPointerException
48 if ((frameWidth < 1 || frameHeight < 1) ||
49 ((image.getWidth() % frameWidth) != 0) ||
50 ((image.getHeight() % frameHeight) != 0)) {
51 throw new IllegalArgumentException();
52 }
53
54 // construct the array of images that
55 // we use as "frames" for the sprite.
56 // use default frame , sequence index = 0
57 initializeFrames(image, frameWidth, frameHeight, false);
58
59 // initialize collision rectangle
60 initCollisionRectBounds();
61
62 }
63
64 public Sprite(Sprite s) {
65
66 super(s != null ? s.getWidth() : 0,
67 s != null ? s.getHeight() : 0);
68
69 if (s == null) {
70 throw new NullPointerException();
71 }
72
73 this.sourceImage = Image.createImage(s.sourceImage);
74
75 this.numberFrames = s.numberFrames;
76
77 this.frameCoordsX = new int[this.numberFrames];
78 this.frameCoordsY = new int[this.numberFrames];
79
80 System.arraycopy(s.frameCoordsX, 0,
81 this.frameCoordsX, 0,
82 s.getRawFrameCount());
83
84 System.arraycopy(s.frameCoordsY, 0,
85 this.frameCoordsY, 0,
86 s.getRawFrameCount());
87
88 this.x = s.getX();
89 this.y = s.getY();
90
91 // these fields are set by defining a reference point
92 this.dRefX = s.dRefX;
93 this.dRefY = s.dRefY;
94
95 // these fields are set when defining a collision rectangle
96 this.collisionRectX = s.collisionRectX;
97 this.collisionRectY = s.collisionRectY;
98 this.collisionRectWidth = s.collisionRectWidth;
99 this.collisionRectHeight = s.collisionRectHeight;
100
101 // these fields are set when creating a Sprite from an Image
102 this.srcFrameWidth = s.srcFrameWidth;
103 this.srcFrameHeight = s.srcFrameHeight;
104
105
106 this.setVisible(s.isVisible());
107
108 this.frameSequence = new int[s.getFrameSequenceLength()];
109 this.setFrameSequence(s.frameSequence);
110 this.setFrame(s.getFrame());
111
112 this.setRefPixelPosition(s.getRefPixelX(), s.getRefPixelY());
113
114 }
115
116 public void defineReferencePixel(int x, int y) {
117 dRefX = x;
118 dRefY = y;
119 }
120
121
122 public void setRefPixelPosition(int x, int y) {
123
124 // update this.x and this.y
125 this.x = x - dRefX;
126 this.y = y - dRefY;
127
128 }
129
130
131 public int getRefPixelX() {
132 return this.x + dRefX;
133 }
134
135
136 public int getRefPixelY() {
137 return this.y + dRefY;
138 }
139
140 public void setFrame(int sequenceIndex) {
141 if (sequenceIndex < 0 || sequenceIndex >= frameSequence.length) {
142 throw new IndexOutOfBoundsException();
143 }
144 this.sequenceIndex = sequenceIndex;
145 }
146
147
148 public final int getFrame() {
149 return sequenceIndex;
150 }
151
152
153 public int getRawFrameCount() {
154 return numberFrames;
155 }
156
157
158 public int getFrameSequenceLength() {
159 return frameSequence.length;
160 }
161
162
163 public void nextFrame() {
164 sequenceIndex = (sequenceIndex + 1) % frameSequence.length;
165 }
166
167
168 public void prevFrame() {
169 if (sequenceIndex == 0) {
170 sequenceIndex = frameSequence.length - 1;
171 } else {
172 sequenceIndex--;
173 }
174 }
175
176
177 public final void paint(Graphics g) {
178 if (g == null) {
179 throw new NullPointerException();
180 }
181
182 if (visible) {
183
184 int clipX = g.getClipX();
185 int clipY = g.getClipY();
186 int clipW = g.getClipWidth();
187 int clipH = g.getClipHeight();
188
189 g.setClip(this.x, this.y, this.srcFrameWidth, this.srcFrameHeight);
190
191 g.drawImage(sourceImage, this.x-frameCoordsX[frameSequence[sequenceIndex]],
192 this.y-frameCoordsY[frameSequence[sequenceIndex]],Graphics.TOP | Graphics.LEFT);
193
194 g.setClip(clipX, clipY, clipW, clipH);
195 }
196
197 }
198
199
200 public void setFrameSequence(int sequence[]) {
201
202 if (sequence == null) {
203 // revert to the default sequence
204 sequenceIndex = 0;
205 customSequenceDefined = false;
206 frameSequence = new int[numberFrames];
207 // copy frames indices into frameSequence
208 for (int i = 0; i < numberFrames; i++) {
209 frameSequence[i] = i;
210 }
211 return;
212 }
213
214 if (sequence.length < 1) {
215 throw new IllegalArgumentException();
216 }
217
218 for (int i = 0; i < sequence.length; i++) {
219 if (sequence[i] < 0 || sequence[i] >= numberFrames) {
220 throw new ArrayIndexOutOfBoundsException();
221 }
222 }
223 customSequenceDefined = true;
224 frameSequence = new int[sequence.length];
225 System.arraycopy(sequence, 0, frameSequence, 0, sequence.length);
226 sequenceIndex = 0;
227 }
228
229
230 public void setImage(Image img, int frameWidth, int frameHeight) {
231
232 // if image is null image.getWidth() will throw NullPointerException
233 if ((frameWidth < 1 || frameHeight < 1) ||
234 ((img.getWidth() % frameWidth) != 0) ||
235 ((img.getHeight() % frameHeight) != 0)) {
236 throw new IllegalArgumentException();
237 }
238
239 int noOfFrames =
240 (img.getWidth() / frameWidth)*(img.getHeight() / frameHeight);
241
242 boolean maintainCurFrame = true;
243 if (noOfFrames < numberFrames) {
244 // use default frame , sequence index = 0
245 maintainCurFrame = false;
246 customSequenceDefined = false;
247 }
248
249 if (! ((srcFrameWidth == frameWidth) &&
250 (srcFrameHeight == frameHeight))) {
251
252 // computing is the location
253 // of the reference pixel in the painter's coordinate system.
254 // and then use this to find x and y position of the Sprite
255 int oldX = this.x + dRefX;
256
257 int oldY = this.y + dRefY;
258
259
260 setWidthImpl(frameWidth);
261 setHeightImpl(frameHeight);
262
263 initializeFrames(img, frameWidth, frameHeight, maintainCurFrame);
264
265 // initialize collision rectangle
266 initCollisionRectBounds();
267
268 // set the new x and y position of the Sprite
269 this.x = oldX - dRefX;
270
271 this.y = oldY - dRefY;
272
273 } else {
274 // just reinitialize the animation frames.
275 initializeFrames(img, frameWidth, frameHeight, maintainCurFrame);
276 }
277
278 }
279
280
281 public void defineCollisionRectangle(int x, int y, int width, int height) {
282
283 if (width < 0 || height < 0) {
284 throw new IllegalArgumentException();
285 }
286
287 collisionRectX = x;
288 collisionRectY = y;
289 collisionRectWidth = width;
290 collisionRectHeight = height;
291 }
292
293 //transfrom is ignored
294 public void setTransform(int transform) {
295 }
296
297 //pixellevel nor supported
298 public final boolean collidesWith(Sprite s, boolean pixelLevel) {
299
300 // check if either of the Sprite's are not visible
301 if (!(s.visible && this.visible)) {
302 return false;
303 }
304
305 // these are package private
306 // and can be accessed directly
307 int otherLeft = s.x + s.collisionRectX;
308 int otherTop = s.y + s.collisionRectY;
309 int otherRight = otherLeft + s.collisionRectWidth;
310 int otherBottom = otherTop + s.collisionRectHeight;
311
312 int left = this.x + this.collisionRectX;
313 int top = this.y + this.collisionRectY;
314 int right = left + this.collisionRectWidth;
315 int bottom = top + this.collisionRectHeight;
316
317 // check if the collision rectangles of the two sprites intersect
318 if (intersectRect(otherLeft, otherTop, otherRight, otherBottom,
319 left, top, right, bottom)) {
320
321
322 return true;
323 }
324 return false;
325
326 }
327
328 //pixellevel not supported
329 public final boolean collidesWith(TiledLayer t, boolean pixelLevel) {
330
331 // check if either this Sprite or the TiledLayer is not visible
332 if (!(t.visible && this.visible)) {
333 return false;
334 }
335
336 // dimensions of tiledLayer, cell, and
337 // this Sprite's collision rectangle
338
339 // these are package private
340 // and can be accessed directly
341 int tLx1 = t.x;
342 int tLy1 = t.y;
343 int tLx2 = tLx1 + t.width;
344 int tLy2 = tLy1 + t.height;
345
346 int tW = t.cellWidth;
347 int tH = t.cellHeight;
348
349 int sx1 = this.x + this.collisionRectX;
350 int sy1 = this.y + this.collisionRectY;
351 int sx2 = sx1 + this.collisionRectWidth;
352 int sy2 = sy1 + this.collisionRectHeight;
353
354 // number of cells
355 int tNumCols = t.columns;
356 int tNumRows = t.rows;
357
358 // temporary loop variables.
359 int startCol; // = 0;
360 int endCol; // = 0;
361 int startRow; // = 0;
362 int endRow; // = 0;
363
364 if (!intersectRect(tLx1, tLy1, tLx2, tLy2, sx1, sy1, sx2, sy2)) {
365 // if the collision rectangle of the sprite
366 // does not intersect with the dimensions of the entire
367 // tiled layer
368 return false;
369 }
370
371 // so there is an intersection
372
373 // note sx1 < sx2, tLx1 < tLx2, sx2 > tLx1 from intersectRect()
374 // use <= for comparison as this saves us some
375 // computation - the result will be 0
376 startCol = (sx1 <= tLx1) ? 0 : (sx1 - tLx1)/tW;
377 startRow = (sy1 <= tLy1) ? 0 : (sy1 - tLy1)/tH;
378 // since tLx1 < sx2 < tLx2, the computation will yield
379 // a result between 0 and tNumCols - 1
380 // subtract by 1 because sx2,sy2 represent
381 // the enclosing bounds of the sprite, not the
382 // locations in the coordinate system.
383 endCol = (sx2 < tLx2) ? ((sx2 - 1 - tLx1)/tW) : tNumCols - 1;
384 endRow = (sy2 < tLy2) ? ((sy2 - 1 - tLy1)/tH) : tNumRows - 1;
385
386 //if (!pixelLevel) {
387 // check for intersection with a non-empty cell,
388 for (int row = startRow; row <= endRow; row++) {
389 for (int col = startCol; col <= endCol; col++) {
390 if (t.cellMatrix[row][col] != 0) {
391 return true;
392 }
393 }
394 }
395 // worst case! we scanned through entire
396 // overlapping region and
397 // all the cells are empty!
398 return false;
399
400
401 }
402
403 //pixellevel not supported
404 public final boolean collidesWith(Image image,
405 int x, int y, boolean pixelLevel) {
406
407 // check if this Sprite is not visible
408 if (!(this.visible)) {
409 return false;
410 }
411
412 // if image is null
413 // image.getWidth() will throw NullPointerException
414 int otherLeft = x;
415 int otherTop = y;
416 int otherRight = x + image.getWidth();
417 int otherBottom = y + image.getHeight();
418
419 int left = this.x + this.collisionRectX;
420 int top = this.y + this.collisionRectY;
421 int right = left + this.collisionRectWidth;
422 int bottom = top + this.collisionRectHeight;
423
424 // first check if the collision rectangles of the two sprites intersect
425 if (intersectRect(otherLeft, otherTop, otherRight, otherBottom,
426 left, top, right, bottom)) {
427
428
429 return true;
430 }
431 return false;
432
433 }
434
435
436 // ----- private -----
437
438 private void initializeFrames(Image image, int fWidth,
439 int fHeight, boolean maintainCurFrame) {
440
441 int imageW = image.getWidth();
442 int imageH = image.getHeight();
443
444 int numHorizontalFrames = imageW / fWidth;
445 int numVerticalFrames = imageH / fHeight;
446
447 sourceImage = image;
448
449 srcFrameWidth = fWidth;
450 srcFrameHeight = fHeight;
451
452 numberFrames = numHorizontalFrames*numVerticalFrames;
453
454 frameCoordsX = new int[numberFrames];
455 frameCoordsY = new int[numberFrames];
456
457 if (!maintainCurFrame) {
458 sequenceIndex = 0;
459 }
460
461 if (!customSequenceDefined) {
462 frameSequence = new int[numberFrames];
463 }
464
465 int currentFrame = 0;
466
467 for (int yy = 0; yy < imageH; yy += fHeight) {
468 for (int xx = 0; xx < imageW; xx += fWidth) {
469
470 frameCoordsX[currentFrame] = xx;
471 frameCoordsY[currentFrame] = yy;
472
473 if (!customSequenceDefined) {
474 frameSequence[currentFrame] = currentFrame;
475 }
476 currentFrame++;
477
478 }
479 }
480 }
481
482 /**
483 * initialize the collision rectangle
484 */
485 private void initCollisionRectBounds() {
486
487 // reset x and y of collision rectangle
488 collisionRectX = 0;
489 collisionRectY = 0;
490
491 // intialize the collision rectangle bounds to that of the sprite
492 collisionRectWidth = this.width;
493 collisionRectHeight = this.height;
494
495 }
496
497
498 private boolean intersectRect(int r1x1, int r1y1, int r1x2, int r1y2,
499 int r2x1, int r2y1, int r2x2, int r2y2) {
500 return !(r2x1 >= r1x2 || r2y1 >= r1y2 || r2x2 <= r1x1 || r2y2 <= r1y1);
501 }
502
503
504
505 private static final int INVERTED_AXES = 0x4;
506 private static final int X_FLIP = 0x2;
507 private static final int Y_FLIP = 0x1;
508 private static final int ALPHA_BITMASK = 0xff000000;
509
510 Image sourceImage;
511
512 int numberFrames; // = 0;
513
514 int[] frameCoordsX;
515 int[] frameCoordsY;
516 int srcFrameWidth;
517 int srcFrameHeight;
518 int[] frameSequence;
519 private int sequenceIndex; // = 0
520 private boolean customSequenceDefined; // = false;
521
522
523 int dRefX; // =0
524
525 int dRefY; // =0
526
527 int collisionRectX; // =0
528
529 int collisionRectY; // =0
530
531 int collisionRectWidth;
532
533 int collisionRectHeight;
534
535 int t_currentTransformation;
536
537
538
539 }