zoukankan      html  css  js  c++  java
  • 转载:一个sprite类

    /**
     * tiger注:
     * 
     * 这是网上看到的一个sprite类。
     * 
     * spriteImg源图是帧图片的集合图片。按从上到下从左到右的排列。详见方法:splitImage
     * 判断两个sprite是否碰撞的方法是collidesWith 。根据参数会判断是否像素碰撞。
     * 像素碰撞验证的时候是看交叉的像素是否都不是透明!
     * 
     * 我感觉这里有一个方法有误:getBounds(Sprite) . 应该按帧的大小来创建。
     * 
     */
    
    /**
     * @author Captain Awesome (http://www.javagaming.org/index.php?action=profile;u=28320)
     * You may use this sprite-class (or parts of it) in any way you want, as long
     * as you don't remove this notice and give me credit for my work.
     *
     * The only thing I didn't make myself is the splitImage(); method,
     * which I found (and copied) from: http://www.javalobby.org/articles/ultimate-image/#13
     *
     * The reference to the BufferedImage you use in the constructor is not kept
     * since the Sprite creates it's own optimized BufferedImage.
     *
     */
    
    import java.awt.Color;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.GraphicsConfiguration;
    import java.awt.GraphicsEnvironment;
    import java.awt.Image;
    import java.awt.Rectangle;
    import java.awt.Toolkit;
    import java.awt.Transparency;
    import java.awt.image.BufferedImage;
    import java.awt.image.FilteredImageSource;
    import java.awt.image.ImageFilter;
    import java.awt.image.ImageProducer;
    import java.awt.image.PixelGrabber;
    import java.awt.image.RGBImageFilter;
    import java.io.Serializable;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    
    public class Sprite implements Cloneable, Serializable {
    	public Sprite(BufferedImage img) {
    		spriteImg = toCompatibleImage(img);
    	}
    
    	@Override
    	public Sprite clone() {
    		try {
    			return (Sprite) super.clone();
    		} catch (CloneNotSupportedException e) {
    			System.out.println("Clone failed.");
    			return null;
    		}
    	}
    
    	/*
    	 * Starts the animation of the sprite. The user must then call
    	 * continueAnimation() in order to animate the sprite.
    	 */
    	public void setAnimation(int sleep) {
    		sleepTime = sleep;
    		currentSleepFrame = 0;
    		runAnim = true;
    	}
    
    	public boolean isAnimating() {
    		return runAnim;
    	}
    
    	/*
    	 * Stops the animation
    	 */
    	public void stopAnimation() {
    		runAnim = false;
    	}
    
    	/*
    	 * Paints the sprite. If splitSprite has been used, it will paint the
    	 * current frame.
    	 */
    	public void paint(Graphics g) {
    		g.drawImage(this.getImage(), this.getRealX(), this.getRealY(), null);
    	}
    
    	// Continues an animation
    	public void continueAnimation() {
    		if (isAnimating() && currentSleepFrame >= sleepTime) {
    			currentSleepFrame = 0;
    			this.nextFrame();
    		} else {
    			currentSleepFrame++;
    		}
    	}
    
    	/*
    	 * Paints the original Sprite if setAnimation has been used
    	 */
    	public void paintOrig(Graphics g) {
    		g.drawImage(spriteImg, x, y, null);
    	}
    
    	/*
    	 * Sets the position based on the parameters
    	 */
    	public void setPosition(int x, int y) {
    		this.x = x;
    		this.y = y;
    	}
    
    	// Defines which reference pixel (i.e where the image will be placed on the
    	// x/y coordinates)
    	public void setRefPixel(int x, int y) {
    		refX = x;
    		refY = y;
    	}
    
    	/*
    	 * Creates an animation of the current sprite, @param cols & rows decides
    	 * how many columnss and rows the sprite should be split into It then
    	 * modifies the @var frameSequence to hold every spritenumber in animImg
    	 */
    	public void splitSprite(int cols, int rows) {
    		this.cols = cols;
    		this.rows = rows;
    
    		animImg = splitImage(spriteImg, cols, rows);
    		frameSequence = new int[animImg.length];
    		for (int i = 0; i < animImg.length; i++)
    			frameSequence[i] = i;
    	}
    
    	public void setFrame(int frame) {
    		currentFrame = frame;
    	}
    
    	/*
    	 * Edits the framesequence (alters the animation), 2 versions The first sets
    	 * a name to use with getFrameSequence(); The other one just sets the
    	 * framesequence
    	 */
    	public void setFrameSequence(int[] sequence, String name) {
    		frameSequence = sequence;
    		currentFrame = 0;
    
    		frameSequenceName = name;
    	}
    
    	public void setFrameSequence(int[] sequence) {
    		frameSequence = sequence;
    		currentFrame = 0;
    
    		frameSequenceName = "UNDEFINED";
    	}
    
    	public String getFrameSequence() {
    		return frameSequenceName;
    	}
    
    	public int[] getFrames() {
    		return this.frameSequence;
    	}
    
    	/*
    	 * Goes to the next frame in the animation
    	 */
    	public void nextFrame() {
    		currentFrame++;
    		if (currentFrame >= frameSequence.length)
    			currentFrame = 0;
    	}
    
    	public int getFrame() {
    		return currentFrame;
    	}
    
    	public int getSize() {
    		if (animImg != null)
    			return animImg.length;
    		else
    			return 1;
    	}
    
    	/*
    	 * Splits the image to create an animation
    	 */
    	private static BufferedImage[] splitImage(BufferedImage img, int cols,
    			int rows) {
    		int w = img.getWidth() / cols;
    		int h = img.getHeight() / rows;
    		int num = 0;
    		BufferedImage imgs[] = new BufferedImage[cols * rows];
    
    		for (int y = 0; y < rows; y++) {
    			for (int x = 0; x < cols; x++) {
    				if (num == imgs.length)
    					break;
    				imgs[num] = createCompatibleImage(w, h);
    				// Tell the graphics to draw only one block of the image
    				Graphics2D g = imgs[num].createGraphics();
    				g.drawImage(img, 0, 0, w, h, w * x, h * y, w * x + w,
    						h * y + h, null);
    				g.dispose();
    				num++;
    			}
    		}
    
    		return imgs;
    	}
    
    	// Creates a BufferedImage that is optimized for this system.
    	private static BufferedImage createCompatibleImage(int width, int height) {
    		GraphicsConfiguration gfx = GraphicsEnvironment
    				.getLocalGraphicsEnvironment().getDefaultScreenDevice()
    				.getDefaultConfiguration();
    
    		return gfx.createCompatibleImage(width, height,
    				Transparency.TRANSLUCENT);
    	}
    
    	private static BufferedImage toCompatibleImage(BufferedImage image) {
    		// Create a new compatible image
    		BufferedImage bimg = createCompatibleImage(image.getWidth(), image
    				.getHeight());
    
    		// Get the graphics of the image and paint the original image onto it.
    		Graphics2D g = (Graphics2D) bimg.getGraphics();
    		g.drawImage(image, 0, 0, null);
    		g.dispose();
    
    		// Return the new, compatible image.
    		return bimg;
    	}
    
    	/*
    	 * Collision detection between the current sprite and another sprite
    	 */
    	public boolean collidesWith(Sprite otherSprite, boolean pixelPerfect) {
    		boolean isColliding = false;
    
    		Rectangle r1 = getBounds(this);
    		Rectangle r2 = getBounds(otherSprite);
    
    		if (r1.intersects(r2)) {
    			if (pixelPerfect) {
    				isColliding = pixelPerfectCollision(otherSprite, r1, r2);
    			} else {
    				isColliding = true;
    			}
    		}
    
    		return isColliding;
    	}
    
    	/*
    	 * pixelPerfectCollision(); first determines the area where the sprites
    	 * collides AKA the collision-rectangle. It then grabs the pixels from both
    	 * sprites which are inside the rectangle. It then checks every pixel from
    	 * the arrays given by grabPixels();, and if 2 pixels at the same position
    	 * are opaque, (alpha value over 0) it will return true. Otherwise it will
    	 * return false.
    	 */
    	private boolean pixelPerfectCollision(Sprite sprite, Rectangle r1,
    			Rectangle r2) {
    		int cornerTopX = -1;
    		int cornerTopY = -1;
    
    		int cornerBottomX = 1;
    		int cornerBottomY = 1;
    
    		/*
    		 * Get the X-values for the two coordinates where the sprites collide
    		 * Seriously, don't use the for loop, I don't know what I was thinking.
    		 * Solution found below.
    		 */
    		// for(int i=0;i<r1.getWidth();i++) {
    		// if(r1.getX()+i >= r2.getX() & r1.getX()+i < r2.getX()+r2.getWidth())
    		// {
    		// if(cornerTopX==-1)cornerTopX = (int) (r1.getX() + i);
    		// cornerBottomX = (int) (r1.getX() + i);
    		// }
    		// }
    
    		cornerTopX = (r1.x > r2.x) ? r1.x : r2.x;
    		cornerBottomX = ((r1.x + r1.width) < (r2.x + r2.width)) ? (r1.x + r1.width)
    				: (r2.x + r2.width);
    
    		/*
    		 * Get the Y-values for the two coordinates where the sprites collide
    		 * Solution found below.
    		 */
    		// for(int i=0;i<r1.getHeight();i++) {
    		// if(r1.getY()+i >= r2.getY() & r1.getY()+i < r2.getY()+r2.getHeight())
    		// {
    		// if(cornerTopY==-1)cornerTopY = (int) (r1.getY() + i);
    		// cornerBottomY = (int) (r1.getY() + i);
    		// }
    		// }
    
    		cornerTopY = (r1.y > r2.y) ? r1.y : r2.y;
    		cornerBottomY = ((r1.y + r1.height) < (r2.y + r2.height)) ? (r1.y + r1.height)
    				: (r2.y + r2.height);
    
    		// Determine the width and height of the collision rectangle
    		int width = cornerBottomX - cornerTopX;
    		int height = cornerBottomY - cornerTopY;
    
    		// Create arrays to hold the pixels
    		int[] pixels1 = new int[width * height];
    		int[] pixels2 = new int[width * height];
    
    		// Create the pixelgrabber and fill the arrays
    		PixelGrabber pg1 = new PixelGrabber(getImage(),
    				cornerTopX - getRealX(), cornerTopY - getRealY(), width,
    				height, pixels1, 0, width);
    		PixelGrabber pg2 = new PixelGrabber(sprite.getImage(), cornerTopX
    				- sprite.getRealX(), cornerTopY - sprite.getRealY(), width,
    				height, pixels2, 0, width);
    
    		// Grab the pixels
    		try {
    			pg1.grabPixels();
    			pg2.grabPixels();
    		} catch (InterruptedException ex) {
    			Logger.getLogger(Sprite.class.getName())
    					.log(Level.SEVERE, null, ex);
    		}
    
    		// Check if pixels at the same spot from both arrays are not
    		// transparent.
    		for (int i = 0; i < pixels1.length; i++) {
    			int a = (pixels1[i] >>> 24) & 0xff;
    			int a2 = (pixels2[i] >>> 24) & 0xff;
    
    			/*
    			 * Awesome, we found two pixels in the same spot that aren't
    			 * completely transparent! Thus the sprites are colliding!
    			 */
    			if (a > 0 && a2 > 0)
    				return true;
    
    		}
    
    		return false;
    	}
    
    	// Invokes transparency on the selected color
    	public void invokeTransparency(Color color) {
    		spriteImg = makeTransparent(spriteImg, color);
    
    		if (this.cols > 0 & this.rows > 0)
    			this.splitSprite(this.cols, this.rows);
    
    	}
    
    	public void invokeTransparency(Color color, int newAlphaValue) {
    		spriteImg = makeTransparent(spriteImg, color, newAlphaValue);
    		if (this.cols > 0 & this.rows > 0)
    			this.splitSprite(this.cols, this.rows);
    	}
    
    	public static BufferedImage makeTransparent(BufferedImage img,
    			final Color color) {
    		ImageFilter filter = new RGBImageFilter() {
    
    			public int markerRGB = color.getRGB() | 0xFF000000;
    
    			@Override
    			public final int filterRGB(int x, int y, int rgb) {
    				if ((rgb | 0xFF000000) == markerRGB)
    					return 0x00FFFFFF & rgb;
    				else
    					return rgb;
    			}
    		};
    
    		ImageProducer ip = new FilteredImageSource(img.getSource(), filter);
    
    		Image temp = Toolkit.getDefaultToolkit().createImage(ip);
    
    		BufferedImage bufImg = createCompatibleImage(img.getWidth(), img
    				.getHeight());
    		Graphics2D g = bufImg.createGraphics();
    		g.drawImage(temp, 0, 0, null);
    		g.dispose();
    
    		return bufImg;
    	}
    
    	public static BufferedImage makeTransparent(BufferedImage img,
    			final Color color, final int newColor) {
    		ImageFilter filter = new RGBImageFilter() {
    
    			public int markerRGB = color.getRGB() | 0xFF000000;
    
    			@Override
    			public final int filterRGB(int x, int y, int rgb) {
    				if ((rgb | 0xFF000000) == markerRGB) {
    					return newColor & rgb;
    				} else {
    					return rgb;
    				}
    			}
    		};
    
    		ImageProducer ip = new FilteredImageSource(img.getSource(), filter);
    
    		Image temp = Toolkit.getDefaultToolkit().createImage(ip);
    
    		BufferedImage bufImg = createCompatibleImage(img.getWidth(), img
    				.getHeight());
    		Graphics2D g = bufImg.createGraphics();
    		g.drawImage(temp, 0, 0, null);
    		g.dispose();
    
    		return bufImg;
    	}
    
    	/*
    	 * Returns the width of the current sprite
    	 */
    	public int getWidth() {
    		return this.getImage().getWidth();
    	}
    
    	/*
    	 * Returns the height of the sprite
    	 */
    	public int getHeight() {
    		return this.getImage().getHeight();
    	}
    
    	/*
    	 * Returns the X-position of the sprite getRealX() returns the X-Position of
    	 * the Sprite's upper-left corner
    	 */
    	public int getX() {
    		return x;
    	}
    
    	public int getRefX() {
    		return refX;
    	}
    
    	public int getRealX() {
    		return x - refX;
    	}
    
    	/*
    	 * Returns the Y-position of the sprite getRealY() returns the Y-position of
    	 * the Sprite's upper-left corner
    	 */
    	public int getY() {
    		return y;
    	}
    
    	public int getRefY() {
    		return refY;
    	}
    
    	public int getRealY() {
    		return y - refY;
    	}
    
    	/*
    	 * Returns the boundaries for the sprite, used for collision detection
    	 */
    	public static Rectangle getBounds(Sprite sprite) {
    		return new Rectangle(sprite.getRealX(), sprite.getRealY(), sprite
    				.getWidth(), sprite.getHeight());
    	}
    
    	/*
    	 * Returns the image this sprite is using (if it was split, it will return
    	 * the current frame. Else it will return the whole image.)
    	 */
    	public BufferedImage getImage() {
    		if (animImg != null && currentFrame < frameSequence.length)
    			return animImg[frameSequence[currentFrame]];
    		else
    			return spriteImg;
    	}
    
    	// Returns the whole image, no matter if it has been split or not.
    	public BufferedImage getOrigImage() {
    		return spriteImg;
    	}
    
    	// Flips the sprite (horizontal/vertical)
    	public void flipHorizontal() {
    		int w = this.getOrigImage().getWidth();
    		int h = this.getOrigImage().getHeight();
    
    		BufferedImage bimg = new BufferedImage(w, h,
    				BufferedImage.TYPE_4BYTE_ABGR);
    		Graphics2D g = bimg.createGraphics();
    
    		g.drawImage(this.getOrigImage(), 0, 0, w, h, w, 0, 0, h, null);
    		g.dispose();
    
    		this.spriteImg = toCompatibleImage(bimg);
    
    		if (this.rows > 0 & this.cols > 0)
    			animImg = splitImage(spriteImg, cols, rows);
    	}
    
    	public void flipVertical() {
    		int w = this.getOrigImage().getWidth();
    		int h = this.getOrigImage().getHeight();
    
    		BufferedImage bimg = new BufferedImage(w, h,
    				BufferedImage.TYPE_4BYTE_ABGR);
    		Graphics2D g = bimg.createGraphics();
    
    		g.drawImage(this.getOrigImage(), 0, 0, w, h, 0, h, w, 0, null);
    		g.dispose();
    
    		this.spriteImg = toCompatibleImage(bimg);
    
    		if (this.rows > 0 & this.cols > 0)
    			animImg = splitImage(spriteImg, cols, rows);
    	}
    
    	// Call one of these methods after the sprite has been de-serialized.
    	public void reloadSprite(BufferedImage img) {
    		this.spriteImg = img;
    		if (this.rows > 0 & this.cols > 0)
    			animImg = splitImage(spriteImg, cols, rows);
    	}
    
    	// Getting the cols and rows
    	public int getCols() {
    		return this.cols;
    	}
    
    	public int getRows() {
    		return this.rows;
    	}
    
    	public static BufferedImage duplicateAndReverse(BufferedImage bimg) {
    		BufferedImage temp = createCompatibleImage(bimg.getWidth() * 2, bimg
    				.getHeight());
    
    		int w = bimg.getWidth();
    		int h = bimg.getHeight();
    
    		Graphics2D g = temp.createGraphics();
    
    		g.drawImage(bimg, 0, 0, null);
    
    		g.drawImage(bimg, w, 0, w * 2, h, w, 0, 0, h, null);
    		g.dispose();
    
    		return temp;
    	}
    
    	private transient BufferedImage spriteImg;
    	private transient BufferedImage[] animImg;
    
    	private int x;
    	private int y;
    
    	private int refX;
    	private int refY;
    
    	private int frameSequence[] = { 0 };
    	private int currentFrame = 0;
    
    	private int sleepTime;
    	private int currentSleepFrame;
    	private boolean runAnim = false;
    
    	private int cols = 0;
    	private int rows = 0;
    
    	private String frameSequenceName = "ORIG";
    
    	// For serialization
    	private static final long serialVersionUID = 1L;
    
    }
    
  • 相关阅读:
    OpenCV中Mat,图像二维指针和CxImage类的转换
    opencv reduce()函数
    vc 6.0添加版本信息
    tesseract::TessBaseAPI api
    lnk1146 erro,solution
    LNK2001 error 解决方法
    Error LNK2038 mismatch detected for 'RuntimeLibrary': value 'MT_StaticRelease' doesn't match value 'MD_DynamicRelease'
    APP后台架构开发实践笔记
    从0到1 快速建一个区块链
    App 后台架构
  • 原文地址:https://www.cnblogs.com/chaohi/p/2064105.html
Copyright © 2011-2022 走看看