Guest User

Untitled

a guest
Jan 18th, 2011
2,245
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 18.67 KB | None | 0 0
  1. /**
  2.  * @author Captain Awesome (http://www.javagaming.org/index.php?action=profile;u=28320)
  3.  * You may use this sprite-class (or parts of it) in any way you want, as long
  4.  * as you don't remove this notice and give me credit for my work.
  5.  *
  6.  * The only thing I didn't make myself is the splitImage(); method,
  7.  * which I found (and copied) from: http://www.javalobby.org/articles/ultimate-image/#13
  8.  *
  9.  * The reference to the BufferedImage you use in the constructor is not kept
  10.  * since the Sprite creates it's own optimized BufferedImage.
  11.  *
  12.  */
  13.  
  14. package com.awesome.graphic;
  15.  
  16. import java.awt.Color;
  17. import java.awt.Graphics;
  18. import java.awt.Graphics2D;
  19. import java.awt.GraphicsConfiguration;
  20. import java.awt.GraphicsEnvironment;
  21. import java.awt.Image;
  22. import java.awt.Rectangle;
  23. import java.awt.Toolkit;
  24. import java.awt.Transparency;
  25. import java.awt.image.BufferedImage;
  26. import java.awt.image.FilteredImageSource;
  27. import java.awt.image.ImageFilter;
  28. import java.awt.image.ImageProducer;
  29. import java.awt.image.PixelGrabber;
  30. import java.awt.image.RGBImageFilter;
  31. import java.io.Serializable;
  32. import java.util.logging.Level;
  33. import java.util.logging.Logger;
  34.  
  35. public class Sprite implements Cloneable, Serializable {
  36.     public Sprite(BufferedImage img) {
  37.         spriteImg = toCompatibleImage(img);
  38.     }
  39.  
  40.     @Override
  41.     public Sprite clone() {
  42.         try {
  43.             return (Sprite) super.clone();
  44.         }catch (CloneNotSupportedException e) {
  45.             System.out.println("Clone failed.");
  46.             return null;
  47.         }
  48.     }
  49.  
  50.     /**
  51.      * Starts the animation of the sprite.
  52.      * The user must then call continueAnimation() in order to animate the sprite.
  53.      */
  54.     public void setAnimation(int sleep) {
  55.         sleepTime = sleep;
  56.         currentSleepFrame = 0;
  57.         runAnim = true;
  58.     }
  59.  
  60.     /**
  61.      *
  62.      * @return true if this Sprite has an animation set, otherwise false.
  63.      */
  64.     public boolean isAnimating() {
  65.         return runAnim;
  66.     }
  67.  
  68.     /*
  69.      * Stops the animation
  70.      */
  71.     public void stopAnimation() {
  72.         runAnim=false;
  73.     }
  74.  
  75.  
  76.     /**
  77.      * Paints the sprite. If splitSprite has been used,
  78.      * it will paint the current frame.
  79.      */
  80.     public void paint(Graphics g) {
  81.         g.drawImage(this.getImage(), this.getRealX(), this.getRealY(), null);
  82.     }
  83.  
  84.     /**
  85.      * Paints the specified frame at the specified position. Ignores reference
  86.      * pixels.
  87.      * @param g The Graphics used to paint this Sprite on.
  88.      * @param frame The frame you wish to paint.
  89.      * @param x The x-position to paint the frame at.
  90.      * @param y The y-position to paint the frame at.
  91.      */
  92.     public void paintFrame(Graphics g, int frame, int x, int y) {
  93.         g.drawImage(animImg[frameSequence[frame]], x, y, null);
  94.     }
  95.  
  96.    
  97.     /**
  98.      * Continues the animation if setAnimation() has been used.
  99.      */
  100.     public void continueAnimation() {
  101.         if(isAnimating() && currentSleepFrame >= sleepTime) {
  102.             currentSleepFrame = 0;
  103.             this.nextFrame();
  104.         }else {
  105.             currentSleepFrame ++;
  106.         }
  107.     }
  108.  
  109.  
  110.     /**
  111.      *  Paints the original Sprite even if the Sprite already has been split.
  112.      */
  113.     public void paintOrig(Graphics g) {
  114.         g.drawImage(spriteImg, x, y, null);
  115.     }
  116.  
  117.     /**
  118.      * Sets the position based on the parameters
  119.      */
  120.     public void setPosition(int x, int y) {
  121.         this.x=x;
  122.         this.y=y;
  123.     }  
  124.    
  125.     /**
  126.      * Defines which reference pixel (i.e where the image will be placed on the x/y coordinates)
  127.      * @param x The x position of the reference pixel.
  128.      * @param y The y-position of the reference pixel.
  129.      */
  130.     public void setRefPixel(int x, int y) {
  131.         refX = x;
  132.         refY = y;
  133.     }
  134.  
  135.     /**
  136.      * Splits this sprite into an array based on the parameters. Used to create
  137.      * animations.
  138.      * @param cols The amount of columns to split the Sprite into.
  139.      * @param rows The amount of rows to split the Sprite into.
  140.      */
  141.     public void splitSprite(int cols, int rows) {
  142.         this.cols = cols;
  143.         this.rows = rows;
  144.  
  145.         animImg = splitImage(spriteImg, cols, rows);
  146.         frameSequence = new int[animImg.length];
  147.         for(int i=0;i<animImg.length;i++)frameSequence[i]=i;
  148.     }
  149.  
  150.     /**
  151.      * Manually sets the current frame.
  152.      * @param frame The frame to set this Sprite to.
  153.      */
  154.     public void setFrame(int frame) {
  155.         currentFrame = frame;
  156.     }
  157.  
  158.     /**
  159.      * Sets a new framesequence.
  160.      * @param sequence The new sequence.
  161.      * @param name The name of this framesequence.
  162.      */
  163.     public void setFrameSequence(int[] sequence, String name) {
  164.         frameSequence = sequence;
  165.         currentFrame = 0;
  166.  
  167.         frameSequenceName = name;
  168.     }
  169.  
  170.    
  171.     /**
  172.      * Sets a new framesequence. The name of the framesequence will be set to
  173.      * undefined.
  174.      * @param sequence The new sequence.
  175.      */
  176.     public void setFrameSequence(int[] sequence) {
  177.         this.setFrameSequence(sequence, "UNDEFINED");
  178.     }
  179.  
  180.     /**
  181.      *
  182.      * @return the name of the current framesequence.
  183.      */
  184.     public String getFrameSequence() {
  185.         return frameSequenceName;
  186.     }
  187.  
  188.     /**
  189.      *
  190.      * @return the current framesequence.
  191.      */
  192.     public int[] getFrames() {
  193.         return this.frameSequence;
  194.     }
  195.  
  196.     /**
  197.      * Manually continues the animation to the next frame.
  198.      */
  199.     public void nextFrame() {
  200.         currentFrame++;
  201.         if(currentFrame>=frameSequence.length)currentFrame=0;
  202.     }
  203.  
  204.     /**
  205.      *
  206.      * @return the current frame.
  207.      */
  208.     public int getFrame() {
  209.         return currentFrame;
  210.     }
  211.  
  212.     /**
  213.      *
  214.      * @return the max amount of frames if this Sprite has been split,
  215.      * otherwise 1.
  216.      */
  217.     public int getSize() {
  218.         if(animImg!=null)return animImg.length;
  219.         else return 1;
  220.     }
  221.  
  222.     /**
  223.      * Splits the image to create an animation
  224.      */
  225.     private static BufferedImage[] splitImage(BufferedImage img, int cols, int rows) {
  226.         int w = img.getWidth()/cols;
  227.         int h = img.getHeight()/rows;
  228.         int num = 0;
  229.         BufferedImage imgs[] = new BufferedImage[cols*rows];
  230.        
  231.         for(int y = 0; y < rows; y++) {
  232.             for(int x = 0; x < cols; x++) {
  233.                 if(num==imgs.length)break;
  234.                 imgs[num] = createCompatibleImage(w, h);
  235.                 // Tell the graphics to draw only one block of the image
  236.                 Graphics2D g = imgs[num].createGraphics();
  237.                 g.drawImage(img, 0, 0, w, h, w*x, h*y, w*x+w, h*y+h, null);
  238.                 g.dispose();
  239.                 num++;
  240.             }
  241.         }
  242.  
  243.         return imgs;
  244.     }
  245.  
  246.     //Creates a BufferedImage that is optimized for this system.
  247.     private static BufferedImage createCompatibleImage(int width, int height) {
  248.         GraphicsConfiguration gfx = GraphicsEnvironment.
  249.                     getLocalGraphicsEnvironment().getDefaultScreenDevice().
  250.                     getDefaultConfiguration();
  251.  
  252.         return gfx.createCompatibleImage(width, height, Transparency.TRANSLUCENT);
  253.     }
  254.  
  255.     private static BufferedImage toCompatibleImage(BufferedImage image)  {
  256.             //Create a new compatible image
  257.             BufferedImage bimg = createCompatibleImage(image.getWidth(), image.getHeight());
  258.  
  259.             //Get the graphics of the image and paint the original image onto it.
  260.             Graphics2D g = (Graphics2D) bimg.getGraphics();
  261.             g.drawImage(image, 0, 0, null);
  262.             g.dispose();
  263.  
  264.             //Return the new, compatible image.
  265.             return bimg;
  266.     }
  267.  
  268.  
  269.     /**
  270.      * Checks if a Sprite is colliding with another Sprite.
  271.      * @param otherSprite The Sprite to check a collission with.
  272.      * @param pixelPerfect If true, it will use a pixel-perfect algorithm. If
  273.      * false, it only checks its bounding box.
  274.      * @return true if the Sprites collide, otherwise false.
  275.      */
  276.     public boolean collidesWith(Sprite otherSprite, boolean pixelPerfect) {
  277.         boolean isColliding=false;
  278.  
  279.         Rectangle r1 = this.getBounds();
  280.         Rectangle r2 = otherSprite.getBounds();
  281.  
  282.         r1.intersection(r2);
  283.        
  284.         if(intersection(r1, r2)) {
  285.             if(pixelPerfect) {
  286.                 isColliding = pixelPerfectCollision(otherSprite, r1, r2);
  287.             }else {
  288.                 isColliding = true;
  289.             }
  290.         }
  291.  
  292.         return isColliding;
  293.     }
  294.  
  295.     private static boolean intersection(Rectangle r, Rectangle d) {
  296.         int rect1x = r.x;
  297.         int rect1y = r.y;
  298.         int rect1w = r.width;
  299.         int rect1h = r.height;
  300.  
  301.         int rect2x = d.x;
  302.         int rect2y = d.y;
  303.         int rect2w = d.width;
  304.         int rect2h = d.height;
  305.  
  306.         return (rect1x + rect1w >= rect2x &&
  307.                 rect1y + rect1h >= rect2y &&
  308.                 rect1x <= rect2x + rect2w &&
  309.                 rect1y <= rect2y + rect2h);
  310.     }
  311.  
  312.  
  313.     /*
  314.      *  pixelPerfectCollision(); first determines the area where the sprites collides
  315.      *  AKA the collision-rectangle. It then grabs the pixels from both sprites
  316.      *  which are inside the rectangle. It then checks every pixel from the arrays
  317.      *  given by grabPixels();, and if 2 pixels at the same position are opaque,
  318.      *  (alpha value over 0) it will return true. Otherwise it will return false.
  319.      */
  320.     private boolean pixelPerfectCollision(Sprite sprite, Rectangle r1, Rectangle r2) {
  321.         /*
  322.          * Get the X-values and Y-values for the two coordinates where the sprites collide
  323.          */
  324.  
  325.         int cornerTopX = (r1.x>r2.x)?r1.x:r2.x;
  326.         int cornerBottomX = ((r1.x+r1.width) < (r2.x+r2.width))?(r1.x+r1.width):(r2.x+r2.width);
  327.  
  328.         int cornerTopY = (r1.y>r2.y)?r1.y:r2.y;
  329.         int cornerBottomY = ((r1.y+r1.height) < (r2.y+r2.height))?(r1.y+r1.height):(r2.y+r2.height);
  330.  
  331.         //Determine the width and height of the collision rectangle
  332.         int width=cornerBottomX-cornerTopX;
  333.         int height=cornerBottomY-cornerTopY;
  334.  
  335.         //Create arrays to hold the pixels
  336.         int[] pixels1 = new int[width*height];
  337.         int[] pixels2 = new int[width*height];
  338.  
  339.         //Create the pixelgrabber and fill the arrays
  340.         PixelGrabber pg1 = new PixelGrabber(getImage(), cornerTopX-getRealX(), cornerTopY-getRealY(), width, height, pixels1, 0, width);
  341.         PixelGrabber pg2 = new PixelGrabber(sprite.getImage(), cornerTopX-sprite.getRealX(), cornerTopY-sprite.getRealY(), width, height, pixels2, 0, width);
  342.  
  343.         //Grab the pixels
  344.         try {
  345.             pg1.grabPixels();
  346.             pg2.grabPixels();
  347.         } catch (InterruptedException ex) {
  348.             Logger.getLogger(Sprite.class.getName()).log(Level.SEVERE, null, ex);
  349.         }
  350.  
  351.         //Check if pixels at the same spot from both arrays are not transparent.
  352.         for(int i=0;i<pixels1.length;i++) {
  353.             int a = (pixels1[i] >>> 24) & 0xff;
  354.             int a2 = (pixels2[i] >>> 24) & 0xff;
  355.  
  356.             /* Awesome, we found two pixels in the same spot that aren't
  357.              * completely transparent! Thus the sprites are colliding!
  358.              */
  359.             if(a > 0 && a2 > 0) return true;
  360.            
  361.         }
  362.        
  363.         return false;
  364.     }
  365.  
  366.     /**
  367.      * Makes the specified Color completely transparent.
  368.      * @param color The Color to make transparent.
  369.      */
  370.     public void invokeTransparency(Color color) {
  371.         spriteImg = makeTransparent(spriteImg, color);
  372.  
  373.         if(this.cols > 0 & this.rows > 0)this.splitSprite(this.cols, this.rows);
  374.  
  375.     }
  376.  
  377.  
  378.     /**
  379.      * Alters the specified Color's transparency to the specified alpha value.
  380.      * @param color The Color to replace.
  381.      * @param newAlphaValue A hex-value of the new alpha value.
  382.      */
  383.     public void invokeTransparency(Color color, int newAlphaValue) {
  384.         spriteImg = makeTransparent(spriteImg, color, newAlphaValue);
  385.         if(this.cols > 0 & this.rows > 0)this.splitSprite(this.cols, this.rows);
  386.     }
  387.  
  388.     private static BufferedImage makeTransparent(BufferedImage img, final Color color) {
  389.         ImageFilter filter = new RGBImageFilter() {
  390.  
  391.             public int markerRGB = color.getRGB() | 0xFF000000;
  392.            
  393.             @Override
  394.             public final int filterRGB(int x, int y, int rgb) {
  395.                 if((rgb | 0xFF000000)==markerRGB)return 0x00FFFFFF & rgb;
  396.                 else return rgb;
  397.             }
  398.         };
  399.  
  400.         ImageProducer ip = new FilteredImageSource(img.getSource(), filter);
  401.  
  402.         Image temp = Toolkit.getDefaultToolkit().createImage(ip);
  403.  
  404.  
  405.         BufferedImage bufImg = createCompatibleImage(img.getWidth(), img.getHeight());
  406.         Graphics2D g = bufImg.createGraphics();
  407.         g.drawImage(temp, 0, 0, null);
  408.         g.dispose();
  409.  
  410.         return bufImg;
  411.     }
  412.  
  413.     private static BufferedImage makeTransparent(BufferedImage img, final Color color, final int newColor) {
  414.         ImageFilter filter = new RGBImageFilter() {
  415.  
  416.             public int markerRGB = color.getRGB() | 0xFF000000;
  417.  
  418.             @Override
  419.             public final int filterRGB(int x, int y, int rgb) {
  420.                 if((rgb | 0xFF000000)==markerRGB) {
  421.                     return newColor & rgb;
  422.                 }else {
  423.                     return rgb;
  424.                 }
  425.             }
  426.         };
  427.  
  428.         ImageProducer ip = new FilteredImageSource(img.getSource(), filter);
  429.  
  430.         Image temp = Toolkit.getDefaultToolkit().createImage(ip);
  431.  
  432.  
  433.         BufferedImage bufImg = createCompatibleImage(img.getWidth(), img.getHeight());
  434.         Graphics2D g = bufImg.createGraphics();
  435.         g.drawImage(temp, 0, 0, null);
  436.         g.dispose();
  437.  
  438.         return bufImg;
  439.     }
  440.  
  441.     /**
  442.      *Returns the width of the current sprite
  443.      */
  444.     public int getWidth() {
  445.         return this.getImage().getWidth();
  446.     }
  447.  
  448.     /**
  449.      * Returns the height of the sprite
  450.      * */
  451.     public int getHeight() {
  452.         return this.getImage().getHeight();
  453.     }
  454.  
  455.     /**
  456.      *
  457.      * @return the current x-position of this Sprite.
  458.      */
  459.     public int getX() {
  460.         return x;
  461.     }
  462.  
  463.     /**
  464.      *
  465.      * @return the current x-position of the reference pixel of this Sprite.
  466.      */
  467.     public int getRefX() {
  468.         return refX;
  469.     }
  470.  
  471.     /**
  472.      *
  473.      * @return the current x-position of the top-left corner of this Sprite.
  474.      */
  475.     public int getRealX() {
  476.         return x-refX;
  477.     }
  478.  
  479.     /**
  480.      *
  481.      * @return the current y-position of this Sprite.
  482.      */
  483.     public int getY() {
  484.         return y;
  485.     }
  486.  
  487.     /**
  488.      *
  489.      * @return the current y-position of the reference pixel of this Sprite.
  490.      */
  491.     public int getRefY() {
  492.         return refY;
  493.     }
  494.  
  495.     /**
  496.      *
  497.      * @return the current y-position of the top-left corner of this Sprite.
  498.      */
  499.      public int getRealY() {
  500.          return y-refY;
  501.      }
  502.  
  503.     /**
  504.      * Returns the boundaries for the sprite, used for collision detection
  505.      */
  506.     public Rectangle getBounds() {
  507.         if(this.bounds == null) {
  508.             this.bounds = new Rectangle(this.getRealX(), this.getRealY(), this.getWidth(), this.getHeight());
  509.  
  510.             return this.bounds;
  511.         }
  512.        
  513.         this.bounds.setBounds(this.getRealX(), this.getRealY(), this.getWidth(), this.getHeight());
  514.  
  515.         return this.bounds;
  516.     }
  517.  
  518.  
  519.     /**
  520.      *
  521.      * @return the image of the current frame if it has been split, otherwise
  522.      * the whole image.
  523.      */
  524.      public BufferedImage getImage() {
  525.         if(animImg!=null && currentFrame<frameSequence.length)return animImg[frameSequence[currentFrame]];
  526.         else return spriteImg;
  527.     }
  528.  
  529.     /**
  530.       *
  531.       * @return the whole image even if this Sprite has been split.
  532.       */
  533.     public BufferedImage getOrigImage() {
  534.         return spriteImg;
  535.     }
  536.  
  537.     /**
  538.      * Flips this sprite horizontally.
  539.      */
  540.     public void flipHorizontal() {
  541.         int w = this.getOrigImage().getWidth();
  542.         int h = this.getOrigImage().getHeight();
  543.  
  544.         BufferedImage bimg = new BufferedImage(w, h, BufferedImage.TYPE_4BYTE_ABGR);
  545.         Graphics2D g = bimg.createGraphics();
  546.  
  547.         g.drawImage(this.getOrigImage(), 0, 0, w, h, w, 0, 0, h, null);
  548.         g.dispose();
  549.        
  550.         this.spriteImg = toCompatibleImage(bimg);
  551.  
  552.         if(this.rows > 0 & this.cols > 0)animImg = splitImage(spriteImg, cols, rows);
  553.     }
  554.  
  555.     /**
  556.      * Flips this sprite horizontally.
  557.      */
  558.     public void flipVertical() {
  559.         int w = this.getOrigImage().getWidth();
  560.         int h = this.getOrigImage().getHeight();
  561.  
  562.         BufferedImage bimg = new BufferedImage(w, h, BufferedImage.TYPE_4BYTE_ABGR);
  563.         Graphics2D g = bimg.createGraphics();
  564.  
  565.         g.drawImage(this.getOrigImage(), 0, 0, w, h, 0, h, w, 0, null);
  566.         g.dispose();
  567.  
  568.         this.spriteImg = toCompatibleImage(bimg);
  569.  
  570.         if(this.rows > 0 & this.cols > 0)animImg = splitImage(spriteImg, cols, rows);
  571.     }
  572.  
  573.  
  574.     /**
  575.      * Re-builds the current Sprite after it has been de-serialized.
  576.      * @param img The BufferedImage to rebuild the Sprite with.
  577.      */
  578.     public void reloadSprite(BufferedImage img) {
  579.         this.spriteImg = img;
  580.         if(this.rows > 0 & this.cols > 0)animImg = splitImage(spriteImg, cols, rows);
  581.     }
  582.  
  583.     /**
  584.      *
  585.      * @return the columns used to split this Sprite with.
  586.      */
  587.     public int getCols() {
  588.         return this.cols;
  589.     }
  590.  
  591.     /**
  592.      *
  593.      * @return the columns used to split this Sprite with.
  594.      */
  595.     public int getRows() {
  596.         return this.rows;
  597.     }
  598.  
  599.     private static BufferedImage duplicateAndReverse(BufferedImage bimg) {
  600.         BufferedImage temp = createCompatibleImage(bimg.getWidth()*2, bimg.getHeight());
  601.  
  602.         int w = bimg.getWidth();
  603.         int h = bimg.getHeight();
  604.  
  605.         Graphics2D g = temp.createGraphics();
  606.  
  607.         g.drawImage(bimg, 0, 0, null);
  608.  
  609.         g.drawImage(bimg, w, 0, w*2, h, w, 0, 0, h, null);
  610.         g.dispose();
  611.  
  612.         return temp;
  613.     }
  614.    
  615.     private transient BufferedImage spriteImg;
  616.     private transient BufferedImage[] animImg;
  617.  
  618.     private int x;
  619.     private int y;
  620.  
  621.     private int refX;
  622.     private int refY;
  623.  
  624.     private int frameSequence[] = {0};
  625.     private int currentFrame = 0;
  626.  
  627.     private int sleepTime;
  628.     private int currentSleepFrame;
  629.     private boolean runAnim = false;
  630.  
  631.     private int cols = 1;
  632.     private int rows = 1;
  633.  
  634.     private String frameSequenceName = "ORIG";
  635.  
  636.     private Rectangle bounds;
  637.  
  638.     //For serialization
  639.     private static final long serialVersionUID = 1L;
  640.  
  641. }
Advertisement
Add Comment
Please, Sign In to add comment