package loon.action.collision; import java.util.ArrayList; import loon.LSystem; import loon.core.LRelease; import loon.core.geom.Point; import loon.core.geom.Polygon; import loon.core.geom.RectBox; import loon.core.graphics.device.LImage; import loon.core.graphics.opengl.LTexture; /** * Copyright 2008 - 2011 * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. * * @project loon * @author cping * @email:javachenpeng@yahoo.com * @version 0.1 */ public class CollisionMask implements LRelease { private int top, left, right, bottom; private LTexture.Mask data; private RectBox rect; public static Polygon makePolygon(String res) { return makePolygon(LImage.createImage(res)); } public static Polygon makePolygon(LImage image) { if (image == null) { throw new RuntimeException("Image is null !"); } return makePolygon(image.getPixels(), image.getWidth(), image.getHeight()); } public static Polygon makePolygon(int[] pixels, int w, int h) { return makePolygon(pixels, 0, 0, 0, 0, w, h, 3); } public static Polygon makePolygon(int[] pixels, int offsetX, int offsetY, int startX, int startY, int limitX, int limitY, int interval) { Polygon split = null; Polygon result = null; ArrayList<Point[]> points = new ArrayList<Point[]>(); Point[] tmpPoint; int x1, y1, x2, y2; boolean secondPoint; int pixel = 0; for (int y = startY; y < limitY - interval; y += interval) { secondPoint = false; x1 = y1 = -1; x2 = y2 = -1; for (int x = startX; x < limitX; x++) { pixel = pixels[x + limitX * y]; if (!secondPoint) { if ((pixel & LSystem.TRANSPARENT) == LSystem.TRANSPARENT) { x1 = x; y1 = y; secondPoint = true; } } else { if ((pixel & LSystem.TRANSPARENT) == LSystem.TRANSPARENT) { x2 = x; y2 = y; } } } if (secondPoint && (x2 > -1) && (y2 > -1)) { tmpPoint = new Point[2]; tmpPoint[0] = new Point(offsetX + x1, offsetY + y1); tmpPoint[1] = new Point(offsetX + x2, offsetY + y2); points.add(tmpPoint); } } split = makePolygon(points); if (split != null) { points = new ArrayList<Point[]>(); for (int x = startX; x < limitX - interval; x += interval) { secondPoint = false; x1 = y1 = -1; x2 = y2 = -1; for (int y = startY; y < limitY; y++) { pixel = pixels[x + limitX * y]; if (!secondPoint) { if ((pixel & LSystem.TRANSPARENT) == LSystem.TRANSPARENT) { x1 = x; y1 = y; secondPoint = true; } } else { if ((pixel & LSystem.TRANSPARENT) == LSystem.TRANSPARENT) { x2 = x; y2 = y; } } } if (secondPoint && (x2 > -1) && (y2 > -1)) { tmpPoint = new Point[2]; tmpPoint[0] = new Point(offsetX + x1, offsetY + y1); tmpPoint[1] = new Point(offsetX + x2, offsetY + y2); points.add(tmpPoint); } } result = makePolygon(points); } return result; } /** * 将指定的Point集合注入Polygon当中 * * @param points * @return */ private static Polygon makePolygon(ArrayList<Point[]> points) { Polygon polygon = null; if (!points.isEmpty()) { int size = points.size(); polygon = new Polygon(); for (int i = 0; i < size; i++) { Point p = (points.get(i))[0]; polygon.addPoint(p.x, p.y); } for (int i = size - 1; i >= 0; i--) { Point p = (points.get(i))[1]; polygon.addPoint(p.x, p.y); } } return polygon; } public static LTexture.Mask createMask(String res) { return createMask(LImage.createImage(res)); } public static LTexture.Mask createMask(LImage image) { if (image == null) { throw new RuntimeException("Image is null !"); } return createMask(image.getPixels(), image.getWidth(), image.getHeight()); } public static LTexture.Mask createMask(int[] pixels, int w, int h) { int width = w; int height = h; LTexture.Mask data = new LTexture.Mask(width, height); boolean[][] mask = new boolean[height][width]; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { mask[y][x] = (pixels[x + w * y] & LSystem.TRANSPARENT) == LSystem.TRANSPARENT; } } data.setData(mask); return data; } public CollisionMask(LTexture.Mask data) { set(data, 0, 0, data.getWidth(), data.getHeight()); } public void set(LTexture.Mask data, int x, int y, int w, int h) { this.data = data; if (rect == null) { this.rect = new RectBox(x, y, w, h); } else { this.rect.setBounds(x, y, w, h); } } public RectBox getBounds() { return rect; } private void calculateBoundingBox() { top = (int) (rect.y - rect.height / 2); left = (int) (rect.x - rect.width / 2); right = (left + rect.width); bottom = (top + rect.height); } public boolean checkBoundingBoxCollision(CollisionMask other) { return rect.intersects(other.getBounds()) || rect.contains(other.getBounds()); } public boolean checkBoundingBoxCollision(int x, int y) { return rect.intersects(x, y) || rect.contains(x, y); } public boolean collidesWith(CollisionMask other) { if (checkBoundingBoxCollision(other)) { other.calculateBoundingBox(); calculateBoundingBox(); boolean a = false; boolean b = false; for (int y = top; y < bottom; y++) { for (int x = left; x < right; x++) { a = data.getPixel(x - left, y - top); b = other.data.getPixel(x - other.left, y - other.top); if (a && b) { return true; } } } } return false; } public boolean collidesWith(int x, int y) { if (checkBoundingBoxCollision(x, y)) { calculateBoundingBox(); return data.getPixel(x - left, y - top); } return false; } public void dispose() { if (data != null) { data.dispose(); data = null; } } }