Source Code Cross Referenced for Sprite.java in  » 6.0-JDK-Modules » j2me » javax » microedition » lcdui » game » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules » j2me » javax.microedition.lcdui.game 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         *   
0003:         *
0004:         * Copyright  1990-2007 Sun Microsystems, Inc. All Rights Reserved.
0005:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0006:         * 
0007:         * This program is free software; you can redistribute it and/or
0008:         * modify it under the terms of the GNU General Public License version
0009:         * 2 only, as published by the Free Software Foundation.
0010:         * 
0011:         * This program is distributed in the hope that it will be useful, but
0012:         * WITHOUT ANY WARRANTY; without even the implied warranty of
0013:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014:         * General Public License version 2 for more details (a copy is
0015:         * included at /legal/license.txt).
0016:         * 
0017:         * You should have received a copy of the GNU General Public License
0018:         * version 2 along with this work; if not, write to the Free Software
0019:         * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020:         * 02110-1301 USA
0021:         * 
0022:         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0023:         * Clara, CA 95054 or visit www.sun.com if you need additional
0024:         * information or have any questions.
0025:         */
0026:
0027:        package javax.microedition.lcdui.game;
0028:
0029:        import javax.microedition.lcdui.Image;
0030:        import javax.microedition.lcdui.Graphics;
0031:
0032:        import com.sun.midp.log.Logging;
0033:        import com.sun.midp.log.LogChannels;
0034:
0035:        /**
0036:         * A Sprite is a basic visual element that can be rendered with one of
0037:         * several frames stored in an Image; different frames can be shown to 
0038:         * animate the Sprite.  Several transforms such as flipping and rotation
0039:         * can also be applied to a Sprite to further vary its appearance.  As with
0040:         * all Layer subclasses, a Sprite's location can be changed and it can also
0041:         * be made visible or invisible.
0042:         * <P>
0043:         * <h3>Sprite Frames</h3>
0044:         * The raw frames used to render a Sprite are provided in a single Image
0045:         * object, which may be mutable or immutable.  If more than one frame is used,
0046:         * the Image is broken up into a series of equally-sized frames of a specified
0047:         * width and height.  As shown in the figure below, the same set of frames may
0048:         * be stored in several different arrangements depending on what is the most 
0049:         * convenient for the game developer.  
0050:         * <br>
0051:         * <center><img src="doc-files/frames.gif" width=777 height=402 
0052:         * ALT="Sprite Frames"></center>
0053:         * <br>
0054:         * <p>
0055:         * Each frame is assigned a unique index number.  The frame located in the
0056:         * upper-left corner of the Image is assigned an index of 0.  The remaining 
0057:         * frames are then numbered consecutively in row-major order (indices are 
0058:         * assigned across the first row, then the second row, and so on).  The method
0059:         * {@link #getRawFrameCount()} returns the total number of raw frames.
0060:         * <P>
0061:         * <h3>Frame Sequence</h3>
0062:         * A Sprite's frame sequence defines an ordered list of frames to be displayed.
0063:         * The default frame sequence mirrors the list of available frames, so 
0064:         * there is a direct mapping between the sequence index and the corresponding
0065:         * frame index.  This also means that the length of the default frame sequence
0066:         * is equal to the number of raw frames.  For example, if a Sprite has 4 
0067:         * frames, its default frame sequence is {0, 1, 2, 3}.  
0068:         * <center><img src="doc-files/defaultSequence.gif" width=182 height=269 
0069:         * ALT="Default Frame Sequence"></center>
0070:         * <P>
0071:         * The developer must manually switch the current frame in the frame sequence.
0072:         * This may be accomplished by calling {@link #setFrame}, 
0073:         * {@link #prevFrame()}, or {@link #nextFrame()}.  Note that these methods 
0074:         * always operate on the sequence index, they do not operate on frame indices;
0075:         * however, if the default frame sequence is used, then the sequence indices
0076:         * and the frame indices are interchangeable.
0077:         * <P>
0078:         * If desired, an arbitrary frame sequence may be defined for a Sprite.  
0079:         * The frame sequence must contain at least one element, and each element must
0080:         * reference a valid frame index.  By defining a new frame sequence, the 
0081:         * developer can conveniently display the Sprite's frames in any order 
0082:         * desired; frames may be repeated, omitted, shown in reverse order, etc.
0083:         * <P>
0084:         * For example, the diagram below shows how a special frame sequence might be
0085:         * used to animate a mosquito.  The frame sequence is designed so that the 
0086:         * mosquito flaps its wings three times and then pauses for a moment before 
0087:         * the cycle is repeated.
0088:         * <center><img src="doc-files/specialSequence.gif" width=346 height=510 
0089:         * ALT="Special Frame Sequence"></center>
0090:         * By calling {@link #nextFrame} each time the display is updated, the 
0091:         * resulting animation would like this:
0092:         * <br>
0093:         * <center><img src="doc-files/sequenceDemo.gif" width=96 height=36></center>
0094:         * <P>
0095:         * <h3>Reference Pixel</h3>
0096:         * Being a subclass of Layer, Sprite inherits various methods for setting and
0097:         * retrieving its location such as {@link #setPosition setPosition(x,y)}, 
0098:         * {@link #getX getX()}, and {@link #getY getY()}.  These methods all define
0099:         * position in terms of the upper-left corner of the Sprite's visual bounds;
0100:         * however, in some cases, it is more convenient to define the Sprite's position
0101:         * in terms of an arbitrary pixel within its frame, especially if transforms
0102:         * are applied to the Sprite.
0103:         * <P>
0104:         * Therefore, Sprite includes the concept of a <em>reference pixel</em>.    
0105:         * The reference pixel is defined by specifying its location in the
0106:         * Sprite's untransformed frame using 
0107:         * {@link #defineReferencePixel defineReferencePixel(x,y)}.  
0108:         * By default, the reference pixel is defined to be the pixel at (0,0) 
0109:         * in the frame.  If desired, the reference pixel may be defined outside 
0110:         * of the frame's bounds.    
0111:         * <p>
0112:         * In this example, the reference pixel is defined to be the pixel that
0113:         * the monkey appears to be hanging from:
0114:         * <p>
0115:         * <center><img src="doc-files/refpixel.gif" width=304 height=199
0116:         * ALT="Defining The Reference Pixel"></center>
0117:         * <p>
0118:         * {@link #getRefPixelX getRefPixelX()} and {@link #getRefPixelY getRefPixelY()}
0119:         * can be used to query the location of the reference pixel in the painter's 
0120:         * coordinate system.  The developer can also use 
0121:         * {@link #setRefPixelPosition setRefPixelPosition(x,y)} to position the Sprite 
0122:         * so that reference pixel appears at a specific location in the painter's
0123:         * coordinate system.  These methods automatically account for any transforms
0124:         * applied to the Sprite.
0125:         * <p>
0126:         * In this example, the reference pixel's position is set to a point at the end 
0127:         * of a tree branch; the Sprite's location changes so that the reference pixel
0128:         * appears at this point and the monkey appears to be hanging from the branch:
0129:         * <p>
0130:         * <center><img src="doc-files/setrefposition.gif" width=332 height=350
0131:         * ALT="Setting The Reference Pixel Position"></center>
0132:         * <p>
0133:         * <a name="transforms"></a>
0134:         * <h3>Sprite Transforms</h3>
0135:         * Various transforms can be applied to a Sprite.  The available transforms
0136:         * include rotations in multiples of 90 degrees, and mirrored (about
0137:         * the vertical axis) versions of each of the rotations.  A Sprite's transform 
0138:         * is set by calling {@link #setTransform setTransform(transform)}.
0139:         * <p>
0140:         * <center><img src="doc-files/transforms.gif" width=355 height=575 
0141:         * ALT="Transforms"></center>
0142:         * <br>
0143:         * When a transform is applied, the Sprite is automatically repositioned 
0144:         * such that the  reference pixel appears stationary in the painter's 
0145:         * coordinate system.  Thus, the reference pixel effectively becomes the
0146:         * center of the transform operation.  Since the reference pixel does not
0147:         * move, the values returned by {@link #getRefPixelX()} and 
0148:         * {@link #getRefPixelY()} remain the same; however, the values returned by
0149:         * {@link #getX getX()} and {@link #getY getY()} may change to reflect the 
0150:         * movement of the Sprite's upper-left corner.
0151:         * <p>
0152:         * Referring to the monkey example once again, the position of the 
0153:         * reference pixel remains at (48, 22) when a 90 degree rotation
0154:         * is applied, thereby making it appear as if the monkey is swinging
0155:         * from the branch:
0156:         * <p>
0157:         * <center><img src="doc-files/transcenter.gif" width=333 height=350
0158:         * ALT="Transform Center"></center>
0159:         * <p>
0160:         * <h3>Sprite Drawing</h3>
0161:         * Sprites can be drawn at any time using the {@link #paint(Graphics)} method.  
0162:         * The Sprite will be drawn on the Graphics object according to the current 
0163:         * state information maintained by the Sprite (i.e. position, frame, 
0164:         * visibility).  Erasing the Sprite is always the responsibility of code 
0165:         * outside the Sprite class.<p>
0166:         * <p>
0167:         * Sprites can be implemented using whatever techniques a manufacturers 
0168:         * wishes to use (e.g hardware acceleration may be used for all Sprites, for
0169:         * certain sizes of Sprites, or not at all).
0170:         * <p>
0171:         * For some platforms, certain Sprite sizes may be more efficient than others;
0172:         * manufacturers may choose to provide developers with information about
0173:         * device-specific characteristics such as these.
0174:         * <p>
0175:         */
0176:
0177:        public class Sprite extends Layer {
0178:
0179:            // ----- definitions for the various transformations possible -----
0180:
0181:            /**
0182:             * No transform is applied to the Sprite.  
0183:             * This constant has a value of <code>0</code>.
0184:             */
0185:            public static final int TRANS_NONE = 0;
0186:
0187:            /**
0188:             * Causes the Sprite to appear rotated clockwise by 90 degrees.
0189:             * This constant has a value of <code>5</code>.
0190:             */
0191:            public static final int TRANS_ROT90 = 5;
0192:
0193:            /**
0194:             * Causes the Sprite to appear rotated clockwise by 180 degrees.
0195:             * This constant has a value of <code>3</code>.
0196:             */
0197:            public static final int TRANS_ROT180 = 3;
0198:
0199:            /**
0200:             * Causes the Sprite to appear rotated clockwise by 270 degrees.
0201:             * This constant has a value of <code>6</code>.
0202:             */
0203:            public static final int TRANS_ROT270 = 6;
0204:
0205:            /**
0206:             * Causes the Sprite to appear reflected about its vertical
0207:             * center.
0208:             * This constant has a value of <code>2</code>.
0209:             */
0210:            public static final int TRANS_MIRROR = 2;
0211:
0212:            /**
0213:             * Causes the Sprite to appear reflected about its vertical
0214:             * center and then rotated clockwise by 90 degrees.
0215:             * This constant has a value of <code>7</code>.
0216:             */
0217:            public static final int TRANS_MIRROR_ROT90 = 7;
0218:
0219:            /**
0220:             * Causes the Sprite to appear reflected about its vertical
0221:             * center and then rotated clockwise by 180 degrees.
0222:             * This constant has a value of <code>1</code>.
0223:             */
0224:            public static final int TRANS_MIRROR_ROT180 = 1;
0225:
0226:            /**
0227:             * Causes the Sprite to appear reflected about its vertical
0228:             * center and then rotated clockwise by 270 degrees.
0229:             * This constant has a value of <code>4</code>.
0230:             */
0231:            public static final int TRANS_MIRROR_ROT270 = 4;
0232:
0233:            // ----- Constructors -----
0234:
0235:            /**
0236:             * Creates a new non-animated Sprite using the provided Image.  
0237:             * This constructor is functionally equivalent to calling
0238:             * <code>new Sprite(image, image.getWidth(), image.getHeight())</code>
0239:             * <p>
0240:             * By default, the Sprite is visible and its upper-left 
0241:             * corner is positioned at (0,0) in the painter's coordinate system.
0242:             * <br>
0243:             * @param image the <code>Image</code> to use as the single frame
0244:             * for the </code>Sprite
0245:             * @throws NullPointerException if <code>img</code> is <code>null</code>
0246:             */
0247:            public Sprite(Image image) {
0248:                super (image.getWidth(), image.getHeight());
0249:
0250:                initializeFrames(image, image.getWidth(), image.getHeight(),
0251:                        false);
0252:
0253:                // initialize collision rectangle
0254:                initCollisionRectBounds();
0255:
0256:                // current transformation is TRANS_NONE
0257:                setTransformImpl(TRANS_NONE);
0258:
0259:            }
0260:
0261:            /**
0262:             * Creates a new animated Sprite using frames contained in 
0263:             * the provided Image.  The frames must be equally sized, with the 
0264:             * dimensions specified by <code>frameWidth</code> and 
0265:             * <code>frameHeight</code>.  They may be laid out in the image 
0266:             * horizontally, vertically, or as a grid.  The width of the source 
0267:             * image must be an integer multiple of the frame width, and the height
0268:             * of the source image must be an integer multiple of the frame height.
0269:             * The  values returned by {@link Layer#getWidth} and 
0270:             * {@link Layer#getHeight} will reflect the frame width and frame height
0271:             * subject to the Sprite's current transform.
0272:             * <p>
0273:             * Sprites have a default frame sequence corresponding to the raw frame
0274:             * numbers, starting with frame 0.  The frame sequence may be modified
0275:             * with {@link #setFrameSequence(int[])}.
0276:             * <p>
0277:             * By default, the Sprite is visible and its upper-left corner is 
0278:             * positioned at (0,0) in the painter's coordinate system.
0279:             * <p>
0280:             * @param image the <code>Image</code> to use for <code>Sprite</code>
0281:             * @param frameWidth the <code>width</code>, in pixels, of the
0282:             * individual raw frames
0283:             * @param frameHeight the <code>height</code>, in pixels, of the
0284:             * individual raw frames
0285:             * @throws NullPointerException if <code>img</code> is <code>null</code>
0286:             * @throws IllegalArgumentException if <code>frameHeight</code> or
0287:             * <code>frameWidth</code> is less than <code>1</code>
0288:             * @throws IllegalArgumentException if the <code>image</code>
0289:             * width is not an integer multiple of the <code>frameWidth</code>
0290:             * @throws IllegalArgumentException if the <code>image</code>
0291:             * height is not an integer multiple of the <code>frameHeight</code>
0292:             */
0293:            public Sprite(Image image, int frameWidth, int frameHeight) {
0294:
0295:                super (frameWidth, frameHeight);
0296:                // if img is null img.getWidth() will throw NullPointerException
0297:                if ((frameWidth < 1 || frameHeight < 1)
0298:                        || ((image.getWidth() % frameWidth) != 0)
0299:                        || ((image.getHeight() % frameHeight) != 0)) {
0300:                    throw new IllegalArgumentException();
0301:                }
0302:
0303:                // construct the array of images that 
0304:                // we use as "frames" for the sprite.
0305:                // use default frame , sequence index = 0  
0306:                initializeFrames(image, frameWidth, frameHeight, false);
0307:
0308:                // initialize collision rectangle
0309:                initCollisionRectBounds();
0310:
0311:                // current transformation is TRANS_NONE
0312:                setTransformImpl(TRANS_NONE);
0313:
0314:            }
0315:
0316:            /**
0317:             * Creates a new Sprite from another Sprite.  <p>
0318:             *
0319:             * All instance attributes (raw frames, position, frame sequence, current
0320:             * frame, reference point, collision rectangle, transform, and visibility) 
0321:             * of the source Sprite are duplicated in the new Sprite.  
0322:             *
0323:             * @param s the <code>Sprite</code> to create a copy of
0324:             * @throws NullPointerException if <code>s</code> is <code>null</code>
0325:             *
0326:             */
0327:            public Sprite(Sprite s) {
0328:
0329:                super (s != null ? s.getWidth() : 0, s != null ? s.getHeight()
0330:                        : 0);
0331:
0332:                if (s == null) {
0333:                    throw new NullPointerException();
0334:                }
0335:
0336:                this .sourceImage = Image.createImage(s.sourceImage);
0337:
0338:                this .numberFrames = s.numberFrames;
0339:
0340:                this .frameCoordsX = new int[this .numberFrames];
0341:                this .frameCoordsY = new int[this .numberFrames];
0342:
0343:                System.arraycopy(s.frameCoordsX, 0, this .frameCoordsX, 0, s
0344:                        .getRawFrameCount());
0345:
0346:                System.arraycopy(s.frameCoordsY, 0, this .frameCoordsY, 0, s
0347:                        .getRawFrameCount());
0348:
0349:                this .x = s.getX();
0350:                this .y = s.getY();
0351:
0352:                // these fields are set by defining a reference point
0353:                this .dRefX = s.dRefX;
0354:                this .dRefY = s.dRefY;
0355:
0356:                // these fields are set when defining a collision rectangle
0357:                this .collisionRectX = s.collisionRectX;
0358:                this .collisionRectY = s.collisionRectY;
0359:                this .collisionRectWidth = s.collisionRectWidth;
0360:                this .collisionRectHeight = s.collisionRectHeight;
0361:
0362:                // these fields are set when creating a Sprite from an Image
0363:                this .srcFrameWidth = s.srcFrameWidth;
0364:                this .srcFrameHeight = s.srcFrameHeight;
0365:
0366:                // the above fields are used in setTransform()
0367:                // which is why we set them first, then  call setTransformImpl() 
0368:                // to set up internally used data structures.
0369:                setTransformImpl(s.t_currentTransformation);
0370:
0371:                this .setVisible(s.isVisible());
0372:
0373:                this .frameSequence = new int[s.getFrameSequenceLength()];
0374:                this .setFrameSequence(s.frameSequence);
0375:                this .setFrame(s.getFrame());
0376:
0377:                this .setRefPixelPosition(s.getRefPixelX(), s.getRefPixelY());
0378:
0379:            }
0380:
0381:            // ----- public methods -----
0382:
0383:            /**
0384:             * Defines the reference pixel for this Sprite.  The pixel is
0385:             * defined by its location relative to the upper-left corner of
0386:             * the Sprite's un-transformed frame, and it may lay outside of
0387:             * the frame's bounds.
0388:             * <p>
0389:             * When a transformation is applied, the reference pixel is
0390:             * defined relative to the Sprite's initial upper-left corner
0391:             * before transformation. This corner may no longer appear as the
0392:             * upper-left corner in the painter's coordinate system under
0393:             * current transformation.
0394:             * <p>
0395:             * By default, a Sprite's reference pixel is located at (0,0); that is,
0396:             * the pixel in the upper-left corner of the raw frame.
0397:             * <p>
0398:             * Changing the reference pixel does not change the
0399:             * Sprite's physical position in the painter's coordinate system;
0400:             * that is, the values returned by {@link #getX getX()} and
0401:             * {@link #getY getY()} will not change as a result of defining the
0402:             * reference pixel.  However, subsequent calls to methods that
0403:             * involve the reference pixel will be impacted by its new definition.
0404:             *
0405:             * @param inp_x the horizontal location of the reference pixel, relative
0406:             * to the left edge of the un-transformed frame
0407:             * @param inp_y the vertical location of the reference pixel, relative
0408:             * to the top edge of the un-transformed frame
0409:             * @see #setRefPixelPosition
0410:             * @see #getRefPixelX
0411:             * @see #getRefPixelY
0412:             */
0413:            public void defineReferencePixel(int inp_x, int inp_y) {
0414:                dRefX = inp_x;
0415:                dRefY = inp_y;
0416:            }
0417:
0418:            /**
0419:             * Sets this Sprite's position such that its reference pixel is located
0420:             * at (x,y) in the painter's coordinate system.
0421:             * @param inp_x the horizontal location at which to place 
0422:             * the reference pixel
0423:             * @param inp_y the vertical location at which to place the reference pixel
0424:             * @see #defineReferencePixel
0425:             * @see #getRefPixelX
0426:             * @see #getRefPixelY
0427:             */
0428:            public void setRefPixelPosition(int inp_x, int inp_y) {
0429:
0430:                // update x and y
0431:                x = inp_x
0432:                        - getTransformedPtX(dRefX, dRefY,
0433:                                t_currentTransformation);
0434:                y = inp_y
0435:                        - getTransformedPtY(dRefX, dRefY,
0436:                                t_currentTransformation);
0437:
0438:            }
0439:
0440:            /**
0441:             * Gets the horizontal position of this Sprite's reference pixel
0442:             * in the painter's coordinate system.  
0443:             * @return the horizontal location of the reference pixel
0444:             * @see #defineReferencePixel
0445:             * @see #setRefPixelPosition
0446:             * @see #getRefPixelY
0447:             */
0448:            public int getRefPixelX() {
0449:                return (this .x + getTransformedPtX(dRefX, dRefY,
0450:                        this .t_currentTransformation));
0451:            }
0452:
0453:            /**
0454:             * Gets the vertical position of this Sprite's reference pixel
0455:             * in the painter's coordinate system.
0456:             * @return the vertical location of the reference pixel
0457:             * @see #defineReferencePixel
0458:             * @see #setRefPixelPosition
0459:             * @see #getRefPixelX
0460:             */
0461:            public int getRefPixelY() {
0462:                return (this .y + getTransformedPtY(dRefX, dRefY,
0463:                        this .t_currentTransformation));
0464:            }
0465:
0466:            /**
0467:             * Selects the current frame in the frame sequence.  <p>
0468:             * The current frame is rendered when {@link #paint(Graphics)} is called.
0469:             * <p>
0470:             * The index provided refers to the desired entry in the frame sequence, 
0471:             * not the index of the actual frame itself.
0472:             * @param inp_sequenceIndex the index of of the desired entry in the frame 
0473:             * sequence 
0474:             * @throws IndexOutOfBoundsException if <code>frameIndex</code> is
0475:             * less than<code>0</code>
0476:             * @throws IndexOutOfBoundsException if <code>frameIndex</code> is
0477:             * equal to or greater than the length of the current frame
0478:             * sequence (or the number of raw frames for the default sequence)
0479:             * @see #setFrameSequence(int[])
0480:             * @see #getFrame
0481:             */
0482:            public void setFrame(int inp_sequenceIndex) {
0483:                if (inp_sequenceIndex < 0
0484:                        || inp_sequenceIndex >= frameSequence.length) {
0485:                    throw new IndexOutOfBoundsException();
0486:                }
0487:                sequenceIndex = inp_sequenceIndex;
0488:            }
0489:
0490:            /**
0491:             * Gets the current index in the frame sequence.  <p>
0492:             * The index returned refers to the current entry in the frame sequence,
0493:             * not the index of the actual frame that is displayed.
0494:             *
0495:             * @return the current index in the frame sequence 
0496:             * @see #setFrameSequence(int[])
0497:             * @see #setFrame
0498:             */
0499:            public final int getFrame() {
0500:                return sequenceIndex;
0501:            }
0502:
0503:            /**
0504:             * Gets the number of raw frames for this Sprite.  The value returned 
0505:             * reflects the number of frames; it does not reflect the length of the 
0506:             * Sprite's frame sequence.  However, these two values will be the same
0507:             * if the default frame sequence is used.
0508:             *
0509:             * @return the number of raw frames for this Sprite
0510:             * @see #getFrameSequenceLength
0511:             */
0512:            public int getRawFrameCount() {
0513:                return numberFrames;
0514:            }
0515:
0516:            /**
0517:             * Gets the number of elements in the frame sequence.  The value returned
0518:             * reflects the length of the Sprite's frame sequence; it does not reflect
0519:             * the number of raw frames.  However, these two values will be the same 
0520:             * if the default frame sequence is used.
0521:             *
0522:             * @return the number of elements in this Sprite's frame sequence
0523:             * @see #getRawFrameCount
0524:             */
0525:            public int getFrameSequenceLength() {
0526:                return frameSequence.length;
0527:            }
0528:
0529:            /**
0530:             * Selects the next frame in the frame sequence.  <p>
0531:             *
0532:             * The frame sequence is considered to be circular, i.e. if 
0533:             * {@link #nextFrame} is called when at the end of the sequence,
0534:             * this method will advance to the first entry in the sequence.
0535:             *
0536:             * @see #setFrameSequence(int[])
0537:             * @see #prevFrame
0538:             */
0539:            public void nextFrame() {
0540:                sequenceIndex = (sequenceIndex + 1) % frameSequence.length;
0541:            }
0542:
0543:            /**
0544:             * Selects the previous frame in the frame sequence.  <p>
0545:             *
0546:             * The frame sequence is considered to be circular, i.e. if
0547:             * {@link #prevFrame} is called when at the start of the sequence,
0548:             * this method will advance to the last entry in the sequence.
0549:             *
0550:             * @see #setFrameSequence(int[])
0551:             * @see #nextFrame
0552:             */
0553:            public void prevFrame() {
0554:                if (sequenceIndex == 0) {
0555:                    sequenceIndex = frameSequence.length - 1;
0556:                } else {
0557:                    sequenceIndex--;
0558:                }
0559:            }
0560:
0561:            /**
0562:             * Draws the Sprite.  
0563:             * <P>
0564:             * Draws current frame of Sprite using the provided Graphics object.
0565:             * The Sprite's upper left corner is rendered at the Sprite's current
0566:             * position relative to the origin of the Graphics object.  The current
0567:             * position of the Sprite's upper-left corner can be retrieved by 
0568:             * calling {@link #getX()} and {@link #getY()}.
0569:             * <P>
0570:             * Rendering is subject to the clip region of the Graphics object.
0571:             * The Sprite will be drawn only if it is visible.
0572:             * <p>
0573:             * If the Sprite's Image is mutable, the Sprite is rendered using the
0574:             * current contents of the Image.
0575:             * 
0576:             * @param g the graphics object to draw <code>Sprite</code> on
0577:             * @throws NullPointerException if <code>g</code> is <code>null</code>
0578:             *
0579:             */
0580:            public final void paint(Graphics g) {
0581:                // managing the painting order is the responsibility of
0582:                // the layermanager, so depth is ignored
0583:                if (g == null) {
0584:                    throw new NullPointerException();
0585:                }
0586:
0587:                if (visible) {
0588:
0589:                    // width and height of the source
0590:                    // image is the width and height
0591:                    // of the original frame
0592:                    g.drawRegion(sourceImage,
0593:                            frameCoordsX[frameSequence[sequenceIndex]],
0594:                            frameCoordsY[frameSequence[sequenceIndex]],
0595:                            srcFrameWidth, srcFrameHeight,
0596:                            t_currentTransformation, this .x, this .y,
0597:                            Graphics.TOP | Graphics.LEFT);
0598:                }
0599:
0600:            }
0601:
0602:            /**
0603:             * Set the frame sequence for this Sprite.  <p>
0604:             *
0605:             * All Sprites have a default sequence that displays the Sprites
0606:             * frames in order.  This method allows for the creation of an
0607:             * arbitrary sequence using the available frames.  The current
0608:             * index in the frame sequence is reset to zero as a result of 
0609:             * calling this method.
0610:             * <p>
0611:             * The contents of the sequence array are copied when this method
0612:             * is called; thus, any changes made to the array after this method
0613:             * returns have no effect on the Sprite's frame sequence.
0614:             * <P>
0615:             * Passing in <code>null</code> causes the Sprite to revert to the
0616:             * default frame sequence.<p>
0617:             *
0618:             * @param sequence an array of integers, where each integer represents
0619:             * a frame index
0620:             *       
0621:             * @throws ArrayIndexOutOfBoundsException if seq is non-null and any member
0622:             *         of the array has a value less than <code>0</code> or
0623:             *         greater than or equal to the
0624:             *         number of frames as reported by {@link #getRawFrameCount()}
0625:             * @throws IllegalArgumentException if the array has less than
0626:             * <code>1</code> element
0627:             * @see #nextFrame
0628:             * @see #prevFrame
0629:             * @see #setFrame
0630:             * @see #getFrame
0631:             *
0632:             */
0633:            public void setFrameSequence(int sequence[]) {
0634:
0635:                if (sequence == null) {
0636:                    // revert to the default sequence
0637:                    sequenceIndex = 0;
0638:                    customSequenceDefined = false;
0639:                    frameSequence = new int[numberFrames];
0640:                    // copy frames indices into frameSequence
0641:                    for (int i = 0; i < numberFrames; i++) {
0642:                        frameSequence[i] = i;
0643:                    }
0644:                    return;
0645:                }
0646:
0647:                if (sequence.length < 1) {
0648:                    throw new IllegalArgumentException();
0649:                }
0650:
0651:                for (int i = 0; i < sequence.length; i++) {
0652:                    if (sequence[i] < 0 || sequence[i] >= numberFrames) {
0653:                        throw new ArrayIndexOutOfBoundsException();
0654:                    }
0655:                }
0656:                customSequenceDefined = true;
0657:                frameSequence = new int[sequence.length];
0658:                System
0659:                        .arraycopy(sequence, 0, frameSequence, 0,
0660:                                sequence.length);
0661:                sequenceIndex = 0;
0662:            }
0663:
0664:            /**
0665:             * Changes the Image containing the Sprite's frames.  
0666:             * <p>
0667:             * Replaces the current raw frames of the Sprite with a new set of raw
0668:             * frames.  See the constructor {@link #Sprite(Image, int, int)} for
0669:             * information on how the frames are created from the image.  The 
0670:             * values returned by {@link Layer#getWidth} and {@link Layer#getHeight}
0671:             * will reflect the new frame width and frame height subject to the 
0672:             * Sprite's current transform.
0673:             * <p>
0674:             * Changing the image for the Sprite could change the number of raw 
0675:             * frames.  If the new frame set has as many or more raw frames than the
0676:             * previous frame set, then:
0677:             * <ul>
0678:             * <li>The current frame will be unchanged
0679:             * <li>If a custom frame sequence has been defined (using 
0680:             *     {@link #setFrameSequence(int[])}), it will remain unchanged.  If no
0681:             *     custom frame sequence is defined (i.e. the default frame
0682:             *     sequence
0683:             *     is in use), the default frame sequence will be updated to
0684:             *     be the default frame sequence for the new frame set.  In other
0685:             *     words, the new default frame sequence will include all of the
0686:             *     frames from the new raw frame set, as if this new image had been
0687:             *     used in the constructor.
0688:             * </ul>
0689:             * <p>
0690:             * If the new frame set has fewer frames than the previous frame set, 
0691:             * then:
0692:             * <ul>
0693:             * <li>The current frame will be reset to entry 0
0694:             * <li>Any custom frame sequence will be discarded and the frame sequence
0695:             *     will revert to the default frame sequence for the new frame
0696:             *     set.
0697:             * </ul>
0698:             * <p>
0699:             * The reference point location is unchanged as a result of calling this 
0700:             * method, both in terms of its defined location within the Sprite and its
0701:             * position in the painter's coordinate system.  However, if the frame
0702:             * size is changed and the Sprite has been transformed, the position of 
0703:             * the Sprite's upper-left corner may change such that the reference 
0704:             * point remains stationary.
0705:             * <p>
0706:             * If the Sprite's frame size is changed by this method, the collision 
0707:             * rectangle is reset to its default value (i.e. it is set to the new 
0708:             * bounds of the untransformed Sprite).
0709:             * <p> 
0710:             * @param img the <code>Image</code> to use for
0711:             * <code>Sprite</code>
0712:             * @param frameWidth the width in pixels of the individual raw frames
0713:             * @param frameHeight the height in pixels of the individual raw frames
0714:             * @throws NullPointerException if <code>img</code> is <code>null</code>
0715:             * @throws IllegalArgumentException if <code>frameHeight</code> or 
0716:             * <code>frameWidth</code> is less than <code>1</code>
0717:             * @throws IllegalArgumentException if the image width is not an integer
0718:             * multiple of the <code>frameWidth</code>
0719:             * @throws IllegalArgumentException if the image height is not an integer 
0720:             * multiple of the <code>frameHeight</code>
0721:             */
0722:            public void setImage(Image img, int frameWidth, int frameHeight) {
0723:
0724:                // if image is null image.getWidth() will throw NullPointerException
0725:                if ((frameWidth < 1 || frameHeight < 1)
0726:                        || ((img.getWidth() % frameWidth) != 0)
0727:                        || ((img.getHeight() % frameHeight) != 0)) {
0728:                    throw new IllegalArgumentException();
0729:                }
0730:
0731:                int noOfFrames = (img.getWidth() / frameWidth)
0732:                        * (img.getHeight() / frameHeight);
0733:
0734:                boolean maintainCurFrame = true;
0735:                if (noOfFrames < numberFrames) {
0736:                    // use default frame , sequence index = 0
0737:                    maintainCurFrame = false;
0738:                    customSequenceDefined = false;
0739:                }
0740:
0741:                if (!((srcFrameWidth == frameWidth) && (srcFrameHeight == frameHeight))) {
0742:
0743:                    // computing is the location
0744:                    // of the reference pixel in the painter's coordinate system.
0745:                    // and then use this to find x and y position of the Sprite
0746:                    int oldX = this .x
0747:                            + getTransformedPtX(dRefX, dRefY,
0748:                                    this .t_currentTransformation);
0749:
0750:                    int oldY = this .y
0751:                            + getTransformedPtY(dRefX, dRefY,
0752:                                    this .t_currentTransformation);
0753:
0754:                    setWidthImpl(frameWidth);
0755:                    setHeightImpl(frameHeight);
0756:
0757:                    initializeFrames(img, frameWidth, frameHeight,
0758:                            maintainCurFrame);
0759:
0760:                    // initialize collision rectangle
0761:                    initCollisionRectBounds();
0762:
0763:                    // set the new x and y position of the Sprite
0764:                    this .x = oldX
0765:                            - getTransformedPtX(dRefX, dRefY,
0766:                                    this .t_currentTransformation);
0767:
0768:                    this .y = oldY
0769:                            - getTransformedPtY(dRefX, dRefY,
0770:                                    this .t_currentTransformation);
0771:
0772:                    // Calculate transformed sprites collision rectangle
0773:                    // and transformed width and height
0774:
0775:                    computeTransformedBounds(this .t_currentTransformation);
0776:
0777:                } else {
0778:                    // just reinitialize the animation frames.
0779:                    initializeFrames(img, frameWidth, frameHeight,
0780:                            maintainCurFrame);
0781:                }
0782:
0783:            }
0784:
0785:            /**
0786:             * Defines the Sprite's bounding rectangle that is used for collision 
0787:             * detection purposes.  This rectangle is specified relative to the 
0788:             * un-transformed Sprite's upper-left corner and defines the area that is
0789:             * checked for collision detection.  For pixel-level detection, only those
0790:             * pixels within the collision rectangle are checked. 
0791:             *
0792:             * By default, a Sprite's collision rectangle is located at 0,0 as has the
0793:             * same dimensions as the Sprite.  The collision rectangle may be 
0794:             * specified to be larger or smaller than the default rectangle; if made 
0795:             * larger, the pixels outside the bounds of the Sprite are considered to be
0796:             * transparent for pixel-level collision detection.
0797:             *
0798:             * @param inp_x the horizontal location of the collision 
0799:             * rectangle relative to the untransformed Sprite's left edge
0800:             * @param inp_y the vertical location of the collision rectangle relative to
0801:             * the untransformed Sprite's top edge
0802:             * @param width the width of the collision rectangle
0803:             * @param height the height of the collision rectangle
0804:             * @throws IllegalArgumentException if the specified
0805:             * <code>width</code> or <code>height</code> is
0806:             * less than <code>0</code>
0807:             */
0808:            public void defineCollisionRectangle(int inp_x, int inp_y,
0809:                    int width, int height) {
0810:
0811:                if (width < 0 || height < 0) {
0812:                    throw new IllegalArgumentException();
0813:                }
0814:
0815:                collisionRectX = inp_x;
0816:                collisionRectY = inp_y;
0817:                collisionRectWidth = width;
0818:                collisionRectHeight = height;
0819:
0820:                // call set transform with current transformation to 
0821:                // update transformed sprites collision rectangle
0822:                setTransformImpl(t_currentTransformation);
0823:            }
0824:
0825:            /**
0826:             * Sets the transform for this Sprite.  Transforms can be 
0827:             * applied to a Sprite to change its rendered appearance.  Transforms 
0828:             * are applied to the original Sprite image; they are not cumulative, 
0829:             * nor can they be combined.  By default, a Sprite's transform is 
0830:             * {@link #TRANS_NONE}.
0831:             * <P>
0832:             * Since some transforms involve rotations of 90 or 270 degrees, their
0833:             * use may result in the overall width and height of the Sprite 
0834:             * being swapped.  As a result, the values returned by 
0835:             * {@link Layer#getWidth} and {@link Layer#getHeight} may change.
0836:             * <p>
0837:             * The collision rectangle is also modified by the transform so that
0838:             * it remains static relative to the pixel data of the Sprite.  
0839:             * Similarly, the defined reference pixel is unchanged by this method,
0840:             * but its visual location within the Sprite may change as a result.
0841:             * <P>
0842:             * This method repositions the Sprite so that the location of 
0843:             * the reference pixel in the painter's coordinate system does not change
0844:             * as a result of changing the transform.  Thus, the reference pixel 
0845:             * effectively becomes the centerpoint for the transform.  Consequently,
0846:             * the values returned by {@link #getRefPixelX} and {@link #getRefPixelY} 
0847:             * will be the same both before and after the transform is applied, but 
0848:             * the values returned by {@link #getX getX()} and {@link #getY getY()}
0849:             * may change.  
0850:             * <p>
0851:             * @param transform the desired transform for this <code>Sprite</code>
0852:             * @throws IllegalArgumentException if the requested
0853:             * <code>transform</code> is invalid
0854:             * @see #TRANS_NONE
0855:             * @see #TRANS_ROT90
0856:             * @see #TRANS_ROT180
0857:             * @see #TRANS_ROT270
0858:             * @see #TRANS_MIRROR
0859:             * @see #TRANS_MIRROR_ROT90
0860:             * @see #TRANS_MIRROR_ROT180
0861:             * @see #TRANS_MIRROR_ROT270
0862:             *
0863:             */
0864:            public void setTransform(int transform) {
0865:                setTransformImpl(transform);
0866:            }
0867:
0868:            /**
0869:             * Checks for a collision between this Sprite and the specified Sprite.
0870:             * <P>
0871:             * If pixel-level detection is used, a collision is detected only if
0872:             * opaque pixels collide.  That is, an opaque pixel in the first
0873:             * Sprite would have to collide with an opaque  pixel in the second
0874:             * Sprite for a collision to be detected.  Only those pixels within
0875:             * the Sprites' respective collision rectangles are checked.
0876:             * <P>
0877:             * If pixel-level detection is not used, this method simply
0878:             * checks if the Sprites' collision rectangles intersect.
0879:             * <P>
0880:             * Any transforms applied to the Sprites are automatically accounted for.
0881:             * <P>
0882:             * Both Sprites must be visible in order for a collision to be
0883:             * detected.
0884:             * <P>
0885:             * @param s the <code>Sprite</code> to test for collision with
0886:             * @param pixelLevel <code>true</code> to test for collision on a
0887:             * pixel-by-pixel basis, <code>false</code> to test using simple
0888:             * bounds checking.
0889:             * @return <code>true</code> if the two Sprites have collided, otherwise
0890:             * <code>false</code>
0891:             * @throws NullPointerException if Sprite <code>s</code> is 
0892:             * <code>null</code>
0893:             */
0894:            public final boolean collidesWith(Sprite s, boolean pixelLevel) {
0895:
0896:                // check if either of the Sprite's are not visible
0897:                if (!(s.visible && this .visible)) {
0898:                    return false;
0899:                }
0900:
0901:                // these are package private 
0902:                // and can be accessed directly
0903:                int otherLeft = s.x + s.t_collisionRectX;
0904:                int otherTop = s.y + s.t_collisionRectY;
0905:                int otherRight = otherLeft + s.t_collisionRectWidth;
0906:                int otherBottom = otherTop + s.t_collisionRectHeight;
0907:
0908:                int left = this .x + this .t_collisionRectX;
0909:                int top = this .y + this .t_collisionRectY;
0910:                int right = left + this .t_collisionRectWidth;
0911:                int bottom = top + this .t_collisionRectHeight;
0912:
0913:                // check if the collision rectangles of the two sprites intersect
0914:                if (intersectRect(otherLeft, otherTop, otherRight, otherBottom,
0915:                        left, top, right, bottom)) {
0916:
0917:                    // collision rectangles intersect
0918:                    if (pixelLevel) {
0919:
0920:                        // we need to check pixel level collision detection.
0921:                        // use only the coordinates within the Sprite frame if 
0922:                        // the collision rectangle is larger than the Sprite 
0923:                        // frame 
0924:                        if (this .t_collisionRectX < 0) {
0925:                            left = this .x;
0926:                        }
0927:                        if (this .t_collisionRectY < 0) {
0928:                            top = this .y;
0929:                        }
0930:                        if ((this .t_collisionRectX + this .t_collisionRectWidth) > this .width) {
0931:                            right = this .x + this .width;
0932:                        }
0933:                        if ((this .t_collisionRectY + this .t_collisionRectHeight) > this .height) {
0934:                            bottom = this .y + this .height;
0935:                        }
0936:
0937:                        // similarly for the other Sprite
0938:                        if (s.t_collisionRectX < 0) {
0939:                            otherLeft = s.x;
0940:                        }
0941:                        if (s.t_collisionRectY < 0) {
0942:                            otherTop = s.y;
0943:                        }
0944:                        if ((s.t_collisionRectX + s.t_collisionRectWidth) > s.width) {
0945:                            otherRight = s.x + s.width;
0946:                        }
0947:                        if ((s.t_collisionRectY + s.t_collisionRectHeight) > s.height) {
0948:                            otherBottom = s.y + s.height;
0949:                        }
0950:
0951:                        // recheck if the updated collision area rectangles intersect
0952:                        if (!intersectRect(otherLeft, otherTop, otherRight,
0953:                                otherBottom, left, top, right, bottom)) {
0954:
0955:                            // if they don't intersect, return false;
0956:                            return false;
0957:                        }
0958:
0959:                        // the updated collision rectangles intersect,
0960:                        // go ahead with collision detection
0961:
0962:                        // find intersecting region, 
0963:                        // within the collision rectangles
0964:                        int intersectLeft = (left < otherLeft) ? otherLeft
0965:                                : left;
0966:                        int intersectTop = (top < otherTop) ? otherTop : top;
0967:
0968:                        // used once, optimize.
0969:                        int intersectRight = (right < otherRight) ? right
0970:                                : otherRight;
0971:                        int intersectBottom = (bottom < otherBottom) ? bottom
0972:                                : otherBottom;
0973:
0974:                        int intersectWidth = Math.abs(intersectRight
0975:                                - intersectLeft);
0976:                        int intersectHeight = Math.abs(intersectBottom
0977:                                - intersectTop);
0978:
0979:                        // have the coordinates in painter space,
0980:                        // need coordinates of top left and width, height
0981:                        // in source image of Sprite.
0982:
0983:                        int this ImageXOffset = getImageTopLeftX(intersectLeft,
0984:                                intersectTop, intersectRight, intersectBottom);
0985:
0986:                        int this ImageYOffset = getImageTopLeftY(intersectLeft,
0987:                                intersectTop, intersectRight, intersectBottom);
0988:
0989:                        int otherImageXOffset = s.getImageTopLeftX(
0990:                                intersectLeft, intersectTop, intersectRight,
0991:                                intersectBottom);
0992:
0993:                        int otherImageYOffset = s.getImageTopLeftY(
0994:                                intersectLeft, intersectTop, intersectRight,
0995:                                intersectBottom);
0996:
0997:                        // check if opaque pixels intersect.
0998:
0999:                        return doPixelCollision(this ImageXOffset,
1000:                                this ImageYOffset, otherImageXOffset,
1001:                                otherImageYOffset, this .sourceImage,
1002:                                this .t_currentTransformation, s.sourceImage,
1003:                                s.t_currentTransformation, intersectWidth,
1004:                                intersectHeight);
1005:
1006:                    } else {
1007:                        // collides!
1008:                        return true;
1009:                    }
1010:                }
1011:                return false;
1012:
1013:            }
1014:
1015:            /**
1016:             * Checks for a collision between this Sprite and the specified
1017:             * TiledLayer.  If pixel-level detection is used, a collision is
1018:             * detected only if opaque pixels collide.  That is, an opaque pixel in
1019:             * the Sprite would have to collide with an opaque pixel in TiledLayer
1020:             * for a collision to be detected.  Only those pixels within the Sprite's
1021:             * collision rectangle are checked.
1022:             * <P>
1023:             * If pixel-level detection is not used, this method simply checks if the
1024:             * Sprite's collision rectangle intersects with a non-empty cell in the
1025:             * TiledLayer.
1026:             * <P>
1027:             * Any transform applied to the Sprite is automatically accounted for.
1028:             * <P>
1029:             * The Sprite and the TiledLayer must both be visible in order for
1030:             * a collision to be detected.
1031:             * <P>
1032:             * @param t the <code>TiledLayer</code> to test for collision with
1033:             * @param pixelLevel <code>true</code> to test for collision on a
1034:             * pixel-by-pixel basis, <code>false</code> to test using simple bounds
1035:             * checking against non-empty cells.
1036:             * @return <code>true</code> if this <code>Sprite</code> has
1037:             * collided with the <code>TiledLayer</code>, otherwise
1038:             * <code>false</code>
1039:             * @throws NullPointerException if <code>t</code> is <code>null</code>
1040:             */
1041:            public final boolean collidesWith(TiledLayer t, boolean pixelLevel) {
1042:
1043:                // check if either this Sprite or the TiledLayer is not visible
1044:                if (!(t.visible && this .visible)) {
1045:                    return false;
1046:                }
1047:
1048:                // dimensions of tiledLayer, cell, and
1049:                // this Sprite's collision rectangle
1050:
1051:                // these are package private 
1052:                // and can be accessed directly
1053:                int tLx1 = t.x;
1054:                int tLy1 = t.y;
1055:                int tLx2 = tLx1 + t.width;
1056:                int tLy2 = tLy1 + t.height;
1057:
1058:                int tW = t.getCellWidth();
1059:                int tH = t.getCellHeight();
1060:
1061:                int sx1 = this .x + this .t_collisionRectX;
1062:                int sy1 = this .y + this .t_collisionRectY;
1063:                int sx2 = sx1 + this .t_collisionRectWidth;
1064:                int sy2 = sy1 + this .t_collisionRectHeight;
1065:
1066:                // number of cells
1067:                int tNumCols = t.getColumns();
1068:                int tNumRows = t.getRows();
1069:
1070:                // temporary loop variables.
1071:                int startCol; // = 0;
1072:                int endCol; // = 0;
1073:                int startRow; // = 0;
1074:                int endRow; // = 0;
1075:
1076:                if (!intersectRect(tLx1, tLy1, tLx2, tLy2, sx1, sy1, sx2, sy2)) {
1077:                    // if the collision rectangle of the sprite
1078:                    // does not intersect with the dimensions of the entire 
1079:                    // tiled layer
1080:                    return false;
1081:                }
1082:
1083:                // so there is an intersection
1084:
1085:                // note sx1 < sx2, tLx1 < tLx2, sx2 > tLx1  from intersectRect()
1086:                // use <= for comparison as this saves us some
1087:                // computation - the result will be 0
1088:                startCol = (sx1 <= tLx1) ? 0 : (sx1 - tLx1) / tW;
1089:                startRow = (sy1 <= tLy1) ? 0 : (sy1 - tLy1) / tH;
1090:                // since tLx1 < sx2 < tLx2, the computation will yield
1091:                // a result between 0 and tNumCols - 1
1092:                // subtract by 1 because sx2,sy2 represent
1093:                // the enclosing bounds of the sprite, not the 
1094:                // locations in the coordinate system.
1095:                endCol = (sx2 < tLx2) ? ((sx2 - 1 - tLx1) / tW) : tNumCols - 1;
1096:                endRow = (sy2 < tLy2) ? ((sy2 - 1 - tLy1) / tH) : tNumRows - 1;
1097:
1098:                if (!pixelLevel) {
1099:                    // check for intersection with a non-empty cell,
1100:                    for (int row = startRow; row <= endRow; row++) {
1101:                        for (int col = startCol; col <= endCol; col++) {
1102:                            if (t.getCell(col, row) != 0) {
1103:                                return true;
1104:                            }
1105:                        }
1106:                    }
1107:                    // worst case! we scanned through entire 
1108:                    // overlapping region and
1109:                    // all the cells are empty!
1110:                    return false;
1111:                } else {
1112:                    // do pixel level
1113:
1114:                    // we need to check pixel level collision detection.
1115:                    // use only the coordinates within the Sprite frame if 
1116:                    // the collision rectangle is larger than the Sprite 
1117:                    // frame 
1118:                    if (this .t_collisionRectX < 0) {
1119:                        sx1 = this .x;
1120:                    }
1121:                    if (this .t_collisionRectY < 0) {
1122:                        sy1 = this .y;
1123:                    }
1124:                    if ((this .t_collisionRectX + this .t_collisionRectWidth) > this .width) {
1125:                        sx2 = this .x + this .width;
1126:                    }
1127:                    if ((this .t_collisionRectY + this .t_collisionRectHeight) > this .height) {
1128:                        sy2 = this .y + this .height;
1129:                    }
1130:
1131:                    if (!intersectRect(tLx1, tLy1, tLx2, tLy2, sx1, sy1, sx2,
1132:                            sy2)) {
1133:                        return (false);
1134:                    }
1135:
1136:                    // we have an intersection between the Sprite and 
1137:                    // one or more cells of the tiledlayer
1138:
1139:                    // note sx1 < sx2, tLx1 < tLx2, sx2 > tLx1  from intersectRect()
1140:                    // use <= for comparison as this saves us some
1141:                    // computation - the result will be 0
1142:                    startCol = (sx1 <= tLx1) ? 0 : (sx1 - tLx1) / tW;
1143:                    startRow = (sy1 <= tLy1) ? 0 : (sy1 - tLy1) / tH;
1144:                    // since tLx1 < sx2 < tLx2, the computation will yield
1145:                    // a result between 0 and tNumCols - 1
1146:                    // subtract by 1 because sx2,sy2 represent
1147:                    // the enclosing bounds of the sprite, not the 
1148:                    // locations in the coordinate system.
1149:                    endCol = (sx2 < tLx2) ? ((sx2 - 1 - tLx1) / tW)
1150:                            : tNumCols - 1;
1151:                    endRow = (sy2 < tLy2) ? ((sy2 - 1 - tLy1) / tH)
1152:                            : tNumRows - 1;
1153:
1154:                    // current cell coordinates
1155:                    int cellTop = startRow * tH + tLy1;
1156:                    int cellBottom = cellTop + tH;
1157:
1158:                    // the index of the current tile.
1159:                    int tileIndex; // = 0;
1160:
1161:                    for (int row = startRow; row <= endRow; row++, cellTop += tH, cellBottom += tH) {
1162:
1163:                        // current cell coordinates
1164:                        int cellLeft = startCol * tW + tLx1;
1165:                        int cellRight = cellLeft + tW;
1166:
1167:                        for (int col = startCol; col <= endCol; col++, cellLeft += tW, cellRight += tW) {
1168:
1169:                            tileIndex = t.getCell(col, row);
1170:
1171:                            if (tileIndex != 0) {
1172:
1173:                                // current cell/sprite intersection coordinates
1174:                                // in painter coordinate system.
1175:                                // find intersecting region, 
1176:                                int intersectLeft = (sx1 < cellLeft) ? cellLeft
1177:                                        : sx1;
1178:                                int intersectTop = (sy1 < cellTop) ? cellTop
1179:                                        : sy1;
1180:
1181:                                // used once, optimize.
1182:                                int intersectRight = (sx2 < cellRight) ? sx2
1183:                                        : cellRight;
1184:                                int intersectBottom = (sy2 < cellBottom) ? sy2
1185:                                        : cellBottom;
1186:
1187:                                if (intersectLeft > intersectRight) {
1188:                                    int temp = intersectRight;
1189:                                    intersectRight = intersectLeft;
1190:                                    intersectLeft = temp;
1191:                                }
1192:
1193:                                if (intersectTop > intersectBottom) {
1194:                                    int temp = intersectBottom;
1195:                                    intersectBottom = intersectTop;
1196:                                    intersectTop = temp;
1197:                                }
1198:
1199:                                int intersectWidth = intersectRight
1200:                                        - intersectLeft;
1201:                                int intersectHeight = intersectBottom
1202:                                        - intersectTop;
1203:
1204:                                int image1XOffset = getImageTopLeftX(
1205:                                        intersectLeft, intersectTop,
1206:                                        intersectRight, intersectBottom);
1207:
1208:                                int image1YOffset = getImageTopLeftY(
1209:                                        intersectLeft, intersectTop,
1210:                                        intersectRight, intersectBottom);
1211:
1212:                                int image2XOffset = t.tileSetX[tileIndex]
1213:                                        + (intersectLeft - cellLeft);
1214:                                int image2YOffset = t.tileSetY[tileIndex]
1215:                                        + (intersectTop - cellTop);
1216:
1217:                                if (doPixelCollision(image1XOffset,
1218:                                        image1YOffset, image2XOffset,
1219:                                        image2YOffset, this .sourceImage,
1220:                                        this .t_currentTransformation,
1221:                                        t.sourceImage, TRANS_NONE,
1222:                                        intersectWidth, intersectHeight)) {
1223:                                    // intersection found with this tile
1224:                                    return true;
1225:                                }
1226:                            }
1227:                        } // end of for col
1228:                    }// end of for row
1229:
1230:                    // worst case! we scanned through entire 
1231:                    // overlapping region and
1232:                    // no pixels collide!
1233:                    return false;
1234:                }
1235:
1236:            }
1237:
1238:            /**
1239:             * Checks for a collision between this Sprite and the specified Image
1240:             * with its upper left corner at the specified location.  If pixel-level
1241:             * detection is used, a collision is detected only if opaque pixels
1242:             * collide.  That is, an opaque pixel in the Sprite would have to collide
1243:             * with an opaque  pixel in Image for a collision to be detected.  Only
1244:             * those pixels within the Sprite's collision rectangle are checked.
1245:             * <P>
1246:             * If pixel-level detection is not used, this method simply checks if the
1247:             * Sprite's collision rectangle intersects with the Image's bounds.
1248:             * <P>
1249:             * Any transform applied to the Sprite is automatically accounted for.
1250:             * <P>
1251:             * The Sprite must be visible in order for a collision to be
1252:             * detected.
1253:             * <P>
1254:             * @param image the <code>Image</code> to test for collision
1255:             * @param inp_x the horizontal location of the <code>Image</code>'s
1256:             * upper left corner
1257:             * @param inp_y the vertical location of the <code>Image</code>'s
1258:             * upper left corner
1259:             * @param pixelLevel <code>true</code> to test for collision on a
1260:             * pixel-by-pixel basis, <code>false</code> to test using simple
1261:             * bounds checking
1262:             * @return <code>true</code> if this <code>Sprite</code> has
1263:             * collided with the <code>Image</code>, otherwise
1264:             * <code>false</code>
1265:             * @throws NullPointerException if <code>image</code> is
1266:             * <code>null</code>
1267:             */
1268:            public final boolean collidesWith(Image image, int inp_x,
1269:                    int inp_y, boolean pixelLevel) {
1270:
1271:                // check if this Sprite is not visible
1272:                if (!(visible)) {
1273:                    return false;
1274:                }
1275:
1276:                // if image is null 
1277:                // image.getWidth() will throw NullPointerException
1278:                int otherLeft = inp_x;
1279:                int otherTop = inp_y;
1280:                int otherRight = inp_x + image.getWidth();
1281:                int otherBottom = inp_y + image.getHeight();
1282:
1283:                int left = x + t_collisionRectX;
1284:                int top = y + t_collisionRectY;
1285:                int right = left + t_collisionRectWidth;
1286:                int bottom = top + t_collisionRectHeight;
1287:
1288:                // first check if the collision rectangles of the two sprites intersect
1289:                if (intersectRect(otherLeft, otherTop, otherRight, otherBottom,
1290:                        left, top, right, bottom)) {
1291:
1292:                    // collision rectangles intersect
1293:                    if (pixelLevel) {
1294:
1295:                        // find intersecting region, 
1296:
1297:                        // we need to check pixel level collision detection.
1298:                        // use only the coordinates within the Sprite frame if 
1299:                        // the collision rectangle is larger than the Sprite 
1300:                        // frame 
1301:                        if (this .t_collisionRectX < 0) {
1302:                            left = this .x;
1303:                        }
1304:                        if (this .t_collisionRectY < 0) {
1305:                            top = this .y;
1306:                        }
1307:                        if ((this .t_collisionRectX + this .t_collisionRectWidth) > this .width) {
1308:                            right = this .x + this .width;
1309:                        }
1310:                        if ((this .t_collisionRectY + this .t_collisionRectHeight) > this .height) {
1311:                            bottom = this .y + this .height;
1312:                        }
1313:
1314:                        // recheck if the updated collision area rectangles intersect
1315:                        if (!intersectRect(otherLeft, otherTop, otherRight,
1316:                                otherBottom, left, top, right, bottom)) {
1317:
1318:                            // if they don't intersect, return false;
1319:                            return false;
1320:                        }
1321:
1322:                        // within the collision rectangles
1323:                        int intersectLeft = (left < otherLeft) ? otherLeft
1324:                                : left;
1325:                        int intersectTop = (top < otherTop) ? otherTop : top;
1326:
1327:                        // used once, optimize.
1328:                        int intersectRight = (right < otherRight) ? right
1329:                                : otherRight;
1330:                        int intersectBottom = (bottom < otherBottom) ? bottom
1331:                                : otherBottom;
1332:
1333:                        int intersectWidth = Math.abs(intersectRight
1334:                                - intersectLeft);
1335:                        int intersectHeight = Math.abs(intersectBottom
1336:                                - intersectTop);
1337:
1338:                        // have the coordinates in painter space,
1339:                        // need coordinates of top left and width, height
1340:                        // in source image of Sprite.
1341:
1342:                        int this ImageXOffset = getImageTopLeftX(intersectLeft,
1343:                                intersectTop, intersectRight, intersectBottom);
1344:
1345:                        int this ImageYOffset = getImageTopLeftY(intersectLeft,
1346:                                intersectTop, intersectRight, intersectBottom);
1347:
1348:                        int otherImageXOffset = intersectLeft - inp_x;
1349:                        int otherImageYOffset = intersectTop - inp_y;
1350:
1351:                        // check if opaque pixels intersect.
1352:                        return doPixelCollision(this ImageXOffset,
1353:                                this ImageYOffset, otherImageXOffset,
1354:                                otherImageYOffset, this .sourceImage,
1355:                                this .t_currentTransformation, image,
1356:                                Sprite.TRANS_NONE, intersectWidth,
1357:                                intersectHeight);
1358:
1359:                    } else {
1360:                        // collides!
1361:                        return true;
1362:                    }
1363:                }
1364:                return false;
1365:
1366:            }
1367:
1368:            // -----
1369:
1370:            //  ----- private -----
1371:
1372:            /**
1373:             * create the Image Array.
1374:             *
1375:             * @param image Image to use for Sprite
1376:             * @param fWidth width, in pixels, of the individual raw frames
1377:             * @param fHeight height, in pixels, of the individual raw frames
1378:             * @param maintainCurFrame true if Current Frame is maintained
1379:             */
1380:            private void initializeFrames(Image image, int fWidth, int fHeight,
1381:                    boolean maintainCurFrame) {
1382:
1383:                int imageW = image.getWidth();
1384:                int imageH = image.getHeight();
1385:
1386:                int numHorizontalFrames = imageW / fWidth;
1387:                int numVerticalFrames = imageH / fHeight;
1388:
1389:                sourceImage = image;
1390:
1391:                srcFrameWidth = fWidth;
1392:                srcFrameHeight = fHeight;
1393:
1394:                numberFrames = numHorizontalFrames * numVerticalFrames;
1395:
1396:                frameCoordsX = new int[numberFrames];
1397:                frameCoordsY = new int[numberFrames];
1398:
1399:                if (!maintainCurFrame) {
1400:                    sequenceIndex = 0;
1401:                }
1402:
1403:                if (!customSequenceDefined) {
1404:                    frameSequence = new int[numberFrames];
1405:                }
1406:
1407:                int currentFrame = 0;
1408:
1409:                for (int yy = 0; yy < imageH; yy += fHeight) {
1410:                    for (int xx = 0; xx < imageW; xx += fWidth) {
1411:
1412:                        frameCoordsX[currentFrame] = xx;
1413:                        frameCoordsY[currentFrame] = yy;
1414:
1415:                        if (!customSequenceDefined) {
1416:                            frameSequence[currentFrame] = currentFrame;
1417:                        }
1418:                        currentFrame++;
1419:
1420:                    }
1421:                }
1422:            }
1423:
1424:            /**
1425:             * initialize the collision rectangle
1426:             */
1427:            private void initCollisionRectBounds() {
1428:
1429:                // reset x and y of collision rectangle
1430:                collisionRectX = 0;
1431:                collisionRectY = 0;
1432:
1433:                // intialize the collision rectangle bounds to that of the sprite
1434:                collisionRectWidth = this .width;
1435:                collisionRectHeight = this .height;
1436:
1437:            }
1438:
1439:            /**
1440:             * Detect rectangle intersection
1441:             * 
1442:             * @param r1x1 left co-ordinate of first rectangle
1443:             * @param r1y1 top co-ordinate of first rectangle
1444:             * @param r1x2 right co-ordinate of first rectangle
1445:             * @param r1y2 bottom co-ordinate of first rectangle
1446:             * @param r2x1 left co-ordinate of second rectangle
1447:             * @param r2y1 top co-ordinate of second rectangle
1448:             * @param r2x2 right co-ordinate of second rectangle
1449:             * @param r2y2 bottom co-ordinate of second rectangle
1450:             * @return True if there is rectangle intersection
1451:             */
1452:            private boolean intersectRect(int r1x1, int r1y1, int r1x2,
1453:                    int r1y2, int r2x1, int r2y1, int r2x2, int r2y2) {
1454:                if (r2x1 >= r1x2 || r2y1 >= r1y2 || r2x2 <= r1x1
1455:                        || r2y2 <= r1y1) {
1456:                    return false;
1457:                } else {
1458:                    return true;
1459:                }
1460:            }
1461:
1462:            /**
1463:             * Detect opaque pixel intersection between regions of two images
1464:             * 
1465:             * @param image1XOffset left coordinate in the first image
1466:             * @param image1YOffset top coordinate in the first image
1467:             * @param image2XOffset left coordinate in the second image
1468:             * @param image2YOffset top coordinate in the second image
1469:             * @param image1 first source image
1470:             * @param transform1 The transform for the first image
1471:             * @param image2 second source image
1472:             * @param transform2 transform set on the second image
1473:             * @param width width of overlapping region, when transformed
1474:             * @param height height of overlapping region, when transformed
1475:             * 
1476:             * Clarification required on parameters:
1477:             * XOffset and YOffset are the offsets from the top left
1478:             * hand corner of the image.
1479:             * width, height is the dimensions of the intersecting regions
1480:             * in the two transformed images.
1481:             * there fore appropriate conversions have to be made on these
1482:             * dimensions when using the values, according to the transformation
1483:             * that has been set.
1484:             * 
1485:             * @return True if there is a pixel level collision
1486:             */
1487:            private static boolean doPixelCollision(int image1XOffset,
1488:                    int image1YOffset, int image2XOffset, int image2YOffset,
1489:                    Image image1, int transform1, Image image2, int transform2,
1490:                    int width, int height) {
1491:
1492:                // starting point of comparison
1493:                int startY1;
1494:                // x and y increments
1495:                int xIncr1, yIncr1;
1496:
1497:                // .. for image 2
1498:                int startY2;
1499:                int xIncr2, yIncr2;
1500:
1501:                int numPixels = height * width;
1502:
1503:                int[] argbData1 = new int[numPixels];
1504:                int[] argbData2 = new int[numPixels];
1505:
1506:                if (0x0 != (transform1 & INVERTED_AXES)) {
1507:                    // inverted axes
1508:
1509:                    // scanlength = height
1510:
1511:                    if (0x0 != (transform1 & Y_FLIP)) {
1512:                        xIncr1 = -(height); // - scanlength
1513:
1514:                        startY1 = numPixels - height; // numPixels - scanlength
1515:                    } else {
1516:                        xIncr1 = height; // + scanlength
1517:
1518:                        startY1 = 0;
1519:                    }
1520:
1521:                    if (0x0 != (transform1 & X_FLIP)) {
1522:                        yIncr1 = -1;
1523:
1524:                        startY1 += (height - 1);
1525:                    } else {
1526:                        yIncr1 = +1;
1527:                    }
1528:
1529:                    image1.getRGB(argbData1, 0, height, // scanlength = height
1530:                            image1XOffset, image1YOffset, height, width);
1531:
1532:                } else {
1533:
1534:                    // scanlength = width
1535:
1536:                    if (0x0 != (transform1 & Y_FLIP)) {
1537:
1538:                        startY1 = numPixels - width; // numPixels - scanlength
1539:
1540:                        yIncr1 = -(width); // - scanlength
1541:                    } else {
1542:                        startY1 = 0;
1543:
1544:                        yIncr1 = width; // + scanlength
1545:                    }
1546:
1547:                    if (0x0 != (transform1 & X_FLIP)) {
1548:                        xIncr1 = -1;
1549:
1550:                        startY1 += (width - 1);
1551:                    } else {
1552:                        xIncr1 = +1;
1553:                    }
1554:
1555:                    image1.getRGB(argbData1, 0, width, // scanlength = width
1556:                            image1XOffset, image1YOffset, width, height);
1557:
1558:                }
1559:
1560:                if (0x0 != (transform2 & INVERTED_AXES)) {
1561:                    // inverted axes
1562:
1563:                    if (0x0 != (transform2 & Y_FLIP)) {
1564:                        xIncr2 = -(height);
1565:
1566:                        startY2 = numPixels - height;
1567:                    } else {
1568:                        xIncr2 = height;
1569:
1570:                        startY2 = 0;
1571:                    }
1572:
1573:                    if (0x0 != (transform2 & X_FLIP)) {
1574:                        yIncr2 = -1;
1575:
1576:                        startY2 += height - 1;
1577:                    } else {
1578:                        yIncr2 = +1;
1579:                    }
1580:
1581:                    image2.getRGB(argbData2, 0, height, image2XOffset,
1582:                            image2YOffset, height, width);
1583:
1584:                } else {
1585:
1586:                    if (0x0 != (transform2 & Y_FLIP)) {
1587:                        startY2 = numPixels - width;
1588:
1589:                        yIncr2 = -(width);
1590:                    } else {
1591:                        startY2 = 0;
1592:
1593:                        yIncr2 = +width;
1594:                    }
1595:
1596:                    if (0x0 != (transform2 & X_FLIP)) {
1597:                        xIncr2 = -1;
1598:
1599:                        startY2 += (width - 1);
1600:                    } else {
1601:                        xIncr2 = +1;
1602:                    }
1603:
1604:                    image2.getRGB(argbData2, 0, width, image2XOffset,
1605:                            image2YOffset, width, height);
1606:
1607:                }
1608:
1609:                int x1, x2;
1610:                int xLocalBegin1, xLocalBegin2;
1611:
1612:                // the loop counters
1613:                int numIterRows;
1614:                int numIterColumns;
1615:
1616:                for (numIterRows = 0, xLocalBegin1 = startY1, xLocalBegin2 = startY2; numIterRows < height; xLocalBegin1 += yIncr1, xLocalBegin2 += yIncr2, numIterRows++) {
1617:
1618:                    for (numIterColumns = 0, x1 = xLocalBegin1, x2 = xLocalBegin2; numIterColumns < width; x1 += xIncr1, x2 += xIncr2, numIterColumns++) {
1619:
1620:                        if (((argbData1[x1] & ALPHA_BITMASK) == FULLY_OPAQUE_ALPHA)
1621:                                && ((argbData2[x2] & ALPHA_BITMASK) == FULLY_OPAQUE_ALPHA)) {
1622:
1623:                            return true;
1624:                        }
1625:
1626:                    } // end for x        
1627:
1628:                } // end for y
1629:
1630:                // worst case!  couldn't find a single colliding pixel!
1631:                return false;
1632:            }
1633:
1634:            /**
1635:             * Given a rectangle that lies within the sprite 
1636:             * in the painter's coordinates,
1637:             * find the X coordinate of the top left corner 
1638:             * in the source image of the sprite
1639:             *
1640:             * @param x1 the x coordinate of the top left of the rectangle
1641:             * @param y1 the y coordinate of the top left of the rectangle
1642:             * @param x2 the x coordinate of the bottom right of the rectangle
1643:             * @param y2 the y coordinate of the bottom right of the rectangle
1644:             * 
1645:             * @return the X coordinate in the source image
1646:             * 
1647:             */
1648:            private int getImageTopLeftX(int x1, int y1, int x2, int y2) {
1649:                int retX = 0;
1650:
1651:                // left = this.x
1652:                // right = this.x + this.width
1653:                // top = this.y
1654:                // bottom = this.y + this.height
1655:
1656:                switch (this .t_currentTransformation) {
1657:
1658:                case TRANS_NONE:
1659:                case TRANS_MIRROR_ROT180:
1660:                    retX = x1 - this .x;
1661:                    break;
1662:
1663:                case TRANS_MIRROR:
1664:                case TRANS_ROT180:
1665:                    retX = (this .x + this .width) - x2;
1666:                    break;
1667:
1668:                case TRANS_ROT90:
1669:                case TRANS_MIRROR_ROT270:
1670:                    retX = y1 - this .y;
1671:                    break;
1672:
1673:                case TRANS_ROT270:
1674:                case TRANS_MIRROR_ROT90:
1675:                    retX = (this .y + this .height) - y2;
1676:                    break;
1677:
1678:                default:
1679:                    // for safety/completeness.
1680:                    Logging.report(Logging.ERROR, LogChannels.LC_HIGHUI,
1681:                            "Sprite: t_currentTransformation="
1682:                                    + t_currentTransformation);
1683:                    return retX;
1684:                }
1685:
1686:                retX += frameCoordsX[frameSequence[sequenceIndex]];
1687:
1688:                return retX;
1689:            }
1690:
1691:            /**
1692:             * Given a rectangle that lies within the sprite 
1693:             * in the painter's coordinates,
1694:             * find the Y coordinate of the top left corner 
1695:             * in the source image of the sprite
1696:             *
1697:             * @param x1 the x coordinate of the top left of the rectangle
1698:             * @param y1 the y coordinate of the top left of the rectangle
1699:             * @param x2 the x coordinate of the bottom right of the rectangle
1700:             * @param y2 the y coordinate of the bottom right of the rectangle
1701:             * 
1702:             * @return the Y coordinate in the source image
1703:             * 
1704:             */
1705:            private int getImageTopLeftY(int x1, int y1, int x2, int y2) {
1706:                int retY = 0;
1707:
1708:                // left = this.x
1709:                // right = this.x + this.width
1710:                // top = this.y
1711:                // bottom = this.y + this.height
1712:
1713:                switch (this .t_currentTransformation) {
1714:
1715:                case TRANS_NONE:
1716:                case TRANS_MIRROR:
1717:                    retY = y1 - this .y;
1718:                    break;
1719:
1720:                case TRANS_ROT180:
1721:                case TRANS_MIRROR_ROT180:
1722:                    retY = (this .y + this .height) - y2;
1723:                    break;
1724:
1725:                case TRANS_ROT270:
1726:                case TRANS_MIRROR_ROT270:
1727:                    retY = x1 - this .x;
1728:                    break;
1729:
1730:                case TRANS_ROT90:
1731:                case TRANS_MIRROR_ROT90:
1732:                    retY = (this .x + this .width) - x2;
1733:                    break;
1734:
1735:                default:
1736:                    // for safety/completeness.
1737:                    Logging.report(Logging.ERROR, LogChannels.LC_HIGHUI,
1738:                            "Sprite: t_currentTransformation="
1739:                                    + this .t_currentTransformation);
1740:                    return retY;
1741:                }
1742:
1743:                retY += frameCoordsY[frameSequence[sequenceIndex]];
1744:
1745:                return retY;
1746:            }
1747:
1748:            /**
1749:             * Sets the transform for this Sprite
1750:             *
1751:             * @param transform the desired transform for this Sprite
1752:             */
1753:            private void setTransformImpl(int transform) {
1754:
1755:                // ---
1756:
1757:                // setTransform sets up all transformation related data structures
1758:                // except transforming the current frame's bitmap.
1759:
1760:                // x, y, width, height, dRefX, dRefY, 
1761:                // collisionRectX, collisionRectY, collisionRectWidth,
1762:                // collisionRectHeight, t_currentTransformation,
1763:                // t_bufferImage
1764:
1765:                // The actual transformed frame is drawn at paint time.
1766:
1767:                // ---
1768:
1769:                // update top-left corner position
1770:                this .x = this .x
1771:                        + getTransformedPtX(dRefX, dRefY,
1772:                                this .t_currentTransformation)
1773:                        - getTransformedPtX(dRefX, dRefY, transform);
1774:
1775:                this .y = this .y
1776:                        + getTransformedPtY(dRefX, dRefY,
1777:                                this .t_currentTransformation)
1778:                        - getTransformedPtY(dRefX, dRefY, transform);
1779:
1780:                // Calculate transformed sprites collision rectangle
1781:                // and transformed width and height
1782:                computeTransformedBounds(transform);
1783:
1784:                // set the current transform to be the one requested
1785:                t_currentTransformation = transform;
1786:
1787:            }
1788:
1789:            /**
1790:             * Calculate transformed sprites collision rectangle
1791:             * and transformed width and height
1792:             * @param transform the desired transform for this <code>Sprite</code>
1793:             */
1794:            private void computeTransformedBounds(int transform) {
1795:                switch (transform) {
1796:
1797:                case TRANS_NONE:
1798:
1799:                    t_collisionRectX = collisionRectX;
1800:                    t_collisionRectY = collisionRectY;
1801:                    t_collisionRectWidth = collisionRectWidth;
1802:                    t_collisionRectHeight = collisionRectHeight;
1803:                    this .width = srcFrameWidth;
1804:                    this .height = srcFrameHeight;
1805:
1806:                    break;
1807:
1808:                case TRANS_MIRROR:
1809:
1810:                    // flip across vertical
1811:
1812:                    // NOTE: top left x and y coordinate must reflect the transformation
1813:                    // performed around the reference point
1814:
1815:                    // the X-offset of the reference point from the top left corner
1816:                    // changes.
1817:                    t_collisionRectX = srcFrameWidth
1818:                            - (collisionRectX + collisionRectWidth);
1819:
1820:                    t_collisionRectY = collisionRectY;
1821:                    t_collisionRectWidth = collisionRectWidth;
1822:                    t_collisionRectHeight = collisionRectHeight;
1823:
1824:                    // the Y-offset of the reference point from the top left corner
1825:                    // remains the same,
1826:                    // top left X-co-ordinate changes
1827:
1828:                    this .width = srcFrameWidth;
1829:                    this .height = srcFrameHeight;
1830:
1831:                    break;
1832:
1833:                case TRANS_MIRROR_ROT180:
1834:
1835:                    // flip across horizontal
1836:
1837:                    // NOTE: top left x and y coordinate must reflect the transformation
1838:                    // performed around the reference point
1839:
1840:                    // the Y-offset of the reference point from the top left corner
1841:                    // changes
1842:                    t_collisionRectY = srcFrameHeight
1843:                            - (collisionRectY + collisionRectHeight);
1844:
1845:                    t_collisionRectX = collisionRectX;
1846:                    t_collisionRectWidth = collisionRectWidth;
1847:                    t_collisionRectHeight = collisionRectHeight;
1848:
1849:                    // width and height are as before
1850:                    this .width = srcFrameWidth;
1851:                    this .height = srcFrameHeight;
1852:
1853:                    // the X-offset of the reference point from the top left corner
1854:                    // remains the same.
1855:                    // top left Y-co-ordinate changes
1856:
1857:                    break;
1858:
1859:                case TRANS_ROT90:
1860:
1861:                    // NOTE: top left x and y coordinate must reflect the transformation
1862:                    // performed around the reference point
1863:
1864:                    // the bottom-left corner of the rectangle becomes the 
1865:                    // top-left when rotated 90.
1866:
1867:                    // both X- and Y-offset to the top left corner may change
1868:
1869:                    // update the position information for the collision rectangle
1870:
1871:                    t_collisionRectX = srcFrameHeight
1872:                            - (collisionRectHeight + collisionRectY);
1873:                    t_collisionRectY = collisionRectX;
1874:
1875:                    t_collisionRectHeight = collisionRectWidth;
1876:                    t_collisionRectWidth = collisionRectHeight;
1877:
1878:                    // set width and height
1879:                    this .width = srcFrameHeight;
1880:                    this .height = srcFrameWidth;
1881:
1882:                    break;
1883:
1884:                case TRANS_ROT180:
1885:
1886:                    // NOTE: top left x and y coordinate must reflect the transformation
1887:                    // performed around the reference point
1888:
1889:                    // width and height are as before
1890:
1891:                    // both X- and Y- offsets from the top left corner may change
1892:
1893:                    t_collisionRectX = srcFrameWidth
1894:                            - (collisionRectWidth + collisionRectX);
1895:                    t_collisionRectY = srcFrameHeight
1896:                            - (collisionRectHeight + collisionRectY);
1897:
1898:                    t_collisionRectWidth = collisionRectWidth;
1899:                    t_collisionRectHeight = collisionRectHeight;
1900:
1901:                    // set width and height
1902:                    this .width = srcFrameWidth;
1903:                    this .height = srcFrameHeight;
1904:
1905:                    break;
1906:
1907:                case TRANS_ROT270:
1908:
1909:                    // the top-right corner of the rectangle becomes the 
1910:                    // top-left when rotated 270.
1911:
1912:                    // both X- and Y-offset to the top left corner may change
1913:
1914:                    // update the position information for the collision rectangle
1915:
1916:                    t_collisionRectX = collisionRectY;
1917:                    t_collisionRectY = srcFrameWidth
1918:                            - (collisionRectWidth + collisionRectX);
1919:
1920:                    t_collisionRectHeight = collisionRectWidth;
1921:                    t_collisionRectWidth = collisionRectHeight;
1922:
1923:                    // set width and height
1924:                    this .width = srcFrameHeight;
1925:                    this .height = srcFrameWidth;
1926:
1927:                    break;
1928:
1929:                case TRANS_MIRROR_ROT90:
1930:
1931:                    // both X- and Y- offset from the top left corner may change
1932:
1933:                    // update the position information for the collision rectangle
1934:
1935:                    t_collisionRectX = srcFrameHeight
1936:                            - (collisionRectHeight + collisionRectY);
1937:                    t_collisionRectY = srcFrameWidth
1938:                            - (collisionRectWidth + collisionRectX);
1939:
1940:                    t_collisionRectHeight = collisionRectWidth;
1941:                    t_collisionRectWidth = collisionRectHeight;
1942:
1943:                    // set width and height
1944:                    this .width = srcFrameHeight;
1945:                    this .height = srcFrameWidth;
1946:
1947:                    break;
1948:
1949:                case TRANS_MIRROR_ROT270:
1950:
1951:                    // both X- and Y- offset from the top left corner may change
1952:
1953:                    // update the position information for the collision rectangle
1954:
1955:                    t_collisionRectY = collisionRectX;
1956:                    t_collisionRectX = collisionRectY;
1957:
1958:                    t_collisionRectHeight = collisionRectWidth;
1959:                    t_collisionRectWidth = collisionRectHeight;
1960:
1961:                    // set width and height
1962:                    this .width = srcFrameHeight;
1963:                    this .height = srcFrameWidth;
1964:
1965:                    break;
1966:
1967:                default:
1968:                    // INVALID TRANSFORMATION!
1969:                    throw new IllegalArgumentException();
1970:
1971:                }
1972:            }
1973:
1974:            /**
1975:             * Given the x and y offsets off a pixel from the top left
1976:             * corner, in an untransformed sprite, 
1977:             * calculates the x coordinate of the pixel when the same sprite
1978:             * is transformed, with the coordinates of the top-left pixel
1979:             * of the transformed sprite as (0,0).
1980:             *
1981:             * @param inp_x Horizontal offset within the untransformed sprite
1982:             * @param inp_y Vertical offset within the untransformed sprite
1983:             * @param transform transform for the sprite
1984:             * @return The x-offset, of the coordinates of the pixel,
1985:             *         with the top-left corner as 0 when transformed.
1986:             */
1987:            int getTransformedPtX(int inp_x, int inp_y, int transform) {
1988:
1989:                int t_x = 0;
1990:
1991:                switch (transform) {
1992:
1993:                case TRANS_NONE:
1994:                    t_x = inp_x;
1995:                    break;
1996:                case TRANS_MIRROR:
1997:                    t_x = srcFrameWidth - inp_x - 1;
1998:                    break;
1999:                case TRANS_MIRROR_ROT180:
2000:                    t_x = inp_x;
2001:                    break;
2002:                case TRANS_ROT90:
2003:                    t_x = srcFrameHeight - inp_y - 1;
2004:                    break;
2005:                case TRANS_ROT180:
2006:                    t_x = srcFrameWidth - inp_x - 1;
2007:                    break;
2008:                case TRANS_ROT270:
2009:                    t_x = inp_y;
2010:                    break;
2011:                case TRANS_MIRROR_ROT90:
2012:                    t_x = srcFrameHeight - inp_y - 1;
2013:                    break;
2014:                case TRANS_MIRROR_ROT270:
2015:                    t_x = inp_y;
2016:                    break;
2017:                default:
2018:                    // for safety/completeness.
2019:                    Logging.report(Logging.ERROR, LogChannels.LC_HIGHUI,
2020:                            "Sprite: transform=" + transform);
2021:                    break;
2022:                }
2023:
2024:                return t_x;
2025:
2026:            }
2027:
2028:            /**
2029:             * Given the x and y offsets off a pixel from the top left
2030:             * corner, in an untransformed sprite, 
2031:             * calculates the y coordinate of the pixel when the same sprite
2032:             * is transformed, with the coordinates of the top-left pixel
2033:             * of the transformed sprite as (0,0).
2034:             *
2035:             * @param inp_x Horizontal offset within the untransformed sprite
2036:             * @param inp_y Vertical offset within the untransformed sprite
2037:             * @param transform transform for the sprite
2038:             * @return The y-offset, of the coordinates of the pixel,
2039:             *         with the top-left corner as 0 when transformed.
2040:             */
2041:            int getTransformedPtY(int inp_x, int inp_y, int transform) {
2042:
2043:                int t_y = 0;
2044:
2045:                switch (transform) {
2046:
2047:                case TRANS_NONE:
2048:                    t_y = inp_y;
2049:                    break;
2050:                case TRANS_MIRROR:
2051:                    t_y = inp_y;
2052:                    break;
2053:                case TRANS_MIRROR_ROT180:
2054:                    t_y = srcFrameHeight - inp_y - 1;
2055:                    break;
2056:                case TRANS_ROT90:
2057:                    t_y = inp_x;
2058:                    break;
2059:                case TRANS_ROT180:
2060:                    t_y = srcFrameHeight - inp_y - 1;
2061:                    break;
2062:                case TRANS_ROT270:
2063:                    t_y = srcFrameWidth - inp_x - 1;
2064:                    break;
2065:                case TRANS_MIRROR_ROT90:
2066:                    t_y = srcFrameWidth - inp_x - 1;
2067:                    break;
2068:                case TRANS_MIRROR_ROT270:
2069:                    t_y = inp_x;
2070:                    break;
2071:                default:
2072:                    // for safety/completeness.
2073:                    Logging.report(Logging.ERROR, LogChannels.LC_HIGHUI,
2074:                            "Sprite: transform=" + transform);
2075:                    break;
2076:                }
2077:
2078:                return t_y;
2079:
2080:            }
2081:
2082:            // --- member variables
2083:
2084:            /**
2085:             * If this bit is set, it denotes that the transform causes the
2086:             * axes to be interchanged
2087:             */
2088:            private static final int INVERTED_AXES = 0x4;
2089:
2090:            /**
2091:             * If this bit is set, it denotes that the transform causes the
2092:             * x axis to be flipped.
2093:             */
2094:            private static final int X_FLIP = 0x2;
2095:
2096:            /**
2097:             * If this bit is set, it denotes that the transform causes the
2098:             * y axis to be flipped.
2099:             */
2100:            private static final int Y_FLIP = 0x1;
2101:
2102:            /**
2103:             * Bit mask for channel value in ARGB pixel.
2104:             */
2105:            private static final int ALPHA_BITMASK = 0xff000000;
2106:
2107:            /**
2108:             * Alpha channel value for full opacity.
2109:             */
2110:            private static final int FULLY_OPAQUE_ALPHA = 0xff000000;
2111:
2112:            /**
2113:             * Source image
2114:             */
2115:            Image sourceImage;
2116:
2117:            /**
2118:             * The number of frames
2119:             */
2120:            int numberFrames; // = 0;
2121:
2122:            /**
2123:             * list of X coordinates of individual frames
2124:             */
2125:            int[] frameCoordsX;
2126:            /**
2127:             * list of Y coordinates of individual frames
2128:             */
2129:            int[] frameCoordsY;
2130:
2131:            /**
2132:             * Width of each frame in the source image
2133:             */
2134:            int srcFrameWidth;
2135:
2136:            /**
2137:             * Height of each frame in the source image
2138:             */
2139:            int srcFrameHeight;
2140:
2141:            /**
2142:             * The sequence in which to display the Sprite frames
2143:             */
2144:            int[] frameSequence;
2145:
2146:            /**
2147:             * The sequence index
2148:             */
2149:            private int sequenceIndex; // = 0
2150:
2151:            /**
2152:             * Set to true if custom sequence is used.
2153:             */
2154:            private boolean customSequenceDefined; // = false;
2155:
2156:            // -- reference point
2157:            /**
2158:             * Horizontal offset of the reference point
2159:             * from the top left of the sprite.
2160:             */
2161:            int dRefX; // =0
2162:
2163:            /**
2164:             * Vertical offset of the reference point
2165:             * from the top left of the sprite.
2166:             */
2167:            int dRefY; // =0
2168:
2169:            // --- collision rectangle
2170:
2171:            /**
2172:             * Horizontal offset of the top left of the collision
2173:             * rectangle from the top left of the sprite.
2174:             */
2175:            int collisionRectX; // =0
2176:
2177:            /**
2178:             * Vertical offset of the top left of the collision
2179:             * rectangle from the top left of the sprite.
2180:             */
2181:            int collisionRectY; // =0
2182:
2183:            /**
2184:             * Width of the bounding rectangle for collision detection.
2185:             */
2186:            int collisionRectWidth;
2187:
2188:            /**
2189:             * Height of the bounding rectangle for collision detection.
2190:             */
2191:            int collisionRectHeight;
2192:
2193:            // --- transformation(s)
2194:            // --- values that may change on setting transformations
2195:            // start with t_
2196:
2197:            /**
2198:             * The current transformation in effect.
2199:             */
2200:            int t_currentTransformation;
2201:
2202:            /**
2203:             * Horizontal offset of the top left of the collision
2204:             * rectangle from the top left of the sprite.
2205:             */
2206:            int t_collisionRectX;
2207:
2208:            /**
2209:             * Vertical offset of the top left of the collision
2210:             * rectangle from the top left of the sprite.
2211:             */
2212:            int t_collisionRectY;
2213:
2214:            /**
2215:             * Width of the bounding rectangle for collision detection,
2216:             * with the current transformation in effect.
2217:             */
2218:            int t_collisionRectWidth;
2219:
2220:            /**
2221:             * Height of the bounding rectangle for collision detection,
2222:             * with the current transformation in effect.
2223:             */
2224:            int t_collisionRectHeight;
2225:
2226:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.