package loon.action.collision; import loon.canvas.Image; import loon.canvas.LColor; import loon.geom.Line; import loon.geom.Point; import loon.geom.RectBox; import loon.geom.Shape; import loon.geom.ShapeUtils; import loon.geom.Vector2f; import loon.geom.Vector3f; import loon.utils.MathUtils; public final class CollisionHelper extends ShapeUtils { /** * 检查两个坐标值是否在指定的碰撞半径内 * * @param x1 * @param y1 * @param r1 * @param x2 * @param y2 * @param r2 * @return */ public static boolean isCollision(float x1, float y1, float r1, float x2, float y2, float r2) { float a = r1 + r2; float dx = x1 - x2; float dy = y1 - y2; return a * a > dx * dx + dy * dy; } /** * 获得两个矩形间距离 * * @param box1 * @param box2 * @return */ public static float getDistance(final RectBox box1, final RectBox box2) { final float xdiff = box1.x - box2.x; final float ydiff = box1.y - box2.y; return MathUtils.sqrt(xdiff * xdiff + ydiff * ydiff); } /** * 检查两个矩形是否发生了碰撞 * * @param rect1 * @param rect2 * @return */ public static boolean isRectToRect(RectBox rect1, RectBox rect2) { return rect1.intersects(rect2); } /** * 判断两个圆形是否发生了碰撞 * * @param rect1 * @param rect2 * @return */ public static boolean isCircToCirc(RectBox rect1, RectBox rect2) { Point middle1 = getMiddlePoint(rect1); Point middle2 = getMiddlePoint(rect2); float distance = middle1.distanceTo(middle2); float radius1 = rect1.getWidth() / 2; float radius2 = rect2.getWidth() / 2; return (distance - radius2) < radius1; } /** * 检查矩形与圆形是否发生了碰撞 * * @param rect1 * @param rect2 * @return */ public static boolean isRectToCirc(RectBox rect1, RectBox rect2) { float radius = rect2.getWidth() / 2; Point middle = getMiddlePoint(rect2); Point upperLeft = new Point(rect1.getMinX(), rect1.getMinY()); Point upperRight = new Point(rect1.getMaxX(), rect1.getMinY()); Point downLeft = new Point(rect1.getMinX(), rect1.getMaxY()); Point downRight = new Point(rect1.getMaxX(), rect1.getMaxY()); boolean collided = true; if (!isPointToLine(upperLeft, upperRight, middle, radius)) { if (!isPointToLine(upperRight, downRight, middle, radius)) { if (!isPointToLine(upperLeft, downLeft, middle, radius)) { if (!isPointToLine(downLeft, downRight, middle, radius)) { collided = false; } } } } return collided; } /** * 换算点线距离 * * @param point1 * @param point2 * @param middle * @param radius * @return */ private static boolean isPointToLine(Point point1, Point point2, Point middle, float radius) { Line line = new Line(point1, point2); float distance = line.ptLineDist(middle); return distance < radius; } /** * 返回中间距离的Point2D形式 * * @param rectangle * @return */ private static Point getMiddlePoint(RectBox rectangle) { return new Point(rectangle.getCenterX(), rectangle.getCenterY()); } /** * 判定指定的两张图片之间是否产生了碰撞 * * @param src * @param x1 * @param y1 * @param dest * @param x2 * @param y2 * @return */ public boolean isPixelCollide(Image src, float x1, float y1, Image dest, float x2, float y2) { float width1 = x1 + src.width() - 1, height1 = y1 + src.height() - 1, width2 = x2 + dest.width() - 1, height2 = y2 + dest.height() - 1; int xstart = (int) MathUtils.max(x1, x2), ystart = (int) MathUtils.max( y1, y2), xend = (int) MathUtils.min(width1, width2), yend = (int) MathUtils .min(height1, height2); int toty = MathUtils.abs(yend - ystart); int totx = MathUtils.abs(xend - xstart); for (int y = 1; y < toty - 1; y++) { int ny = MathUtils.abs(ystart - (int) y1) + y; int ny1 = MathUtils.abs(ystart - (int) y2) + y; for (int x = 1; x < totx - 1; x++) { int nx = MathUtils.abs(xstart - (int) x1) + x; int nx1 = MathUtils.abs(xstart - (int) x2) + x; try { if (((src.getPixel(nx, ny) & LColor.TRANSPARENT) != 0x00) && ((dest.getPixel(nx1, ny1) & LColor.TRANSPARENT) != 0x00)) { return true; } else if (getPixelData(src, nx, ny)[0] != 0 && getPixelData(dest, nx1, ny1)[0] != 0) { return true; } } catch (Exception e) { } } } return false; } private static int[] getPixelData(Image image, int x, int y) { return LColor.getRGBs(image.getPixel(x, y)); } /** * 判断指定大小的两组像素是否相交 * * @param rectA * @param dataA * @param rectB * @param dataB * @return */ public static boolean intersect(RectBox rectA, int[] dataA, RectBox rectB, int[] dataB) { int top = (int) MathUtils.max(rectA.getY(), rectB.getY()); int bottom = (int) MathUtils.min(rectA.getBottom(), rectB.getBottom()); int left = (int) MathUtils.max(rectA.getX(), rectB.getX()); int right = (int) MathUtils.min(rectA.getRight(), rectB.getRight()); for (int y = top; y < bottom; y++) { for (int x = left; x < right; x++) { int colorA = dataA[(int) ((x - rectA.x) + (y - rectA.y) * rectA.width)]; int colorB = dataB[(int) ((x - rectB.x) + (y - rectB.y) * rectB.width)]; if (colorA >>> 24 != 0 && colorB >>> 24 != 0) { return true; } } } return false; } /** * 判断两个Shape是否相交 * * @param s1 * @param s2 * @return */ public final static boolean intersects(Shape s1, Shape s2) { if (s1 == null || s2 == null) { return false; } return s1.intersects(s2); } /** * 判断两个Shape是否存在包含关系 * * @param s1 * @param s2 * @return */ public final static boolean contains(Shape s1, Shape s2) { if (s1 == null || s2 == null) { return false; } return s1.contains(s2); } public final static Line getLine(Shape shape, int s, int e) { float[] start = shape.getPoint(s); float[] end = shape.getPoint(e); Line line = new Line(start[0], start[1], end[0], end[1]); return line; } public final static Line getLine(Shape shape, float sx, float sy, int e) { float[] end = shape.getPoint(e); Line line = new Line(sx, sy, end[0], end[1]); return line; } public final static boolean checkAABBvsAABB(Vector2f p1, float w1, float h1, Vector2f p2, float w2, float h2) { return checkAABBvsAABB(p1.x, p1.y, w1, h1, p2.x, p2.y, w2, h2); } public final static boolean checkAABBvsAABB(float x1, float y1, float w1, float h1, float x2, float y2, float w2, float h2) { return !(x1 > x2 + w2 || x1 + w1 < x2) && !(y1 > y2 + h2 || y1 + h1 < y2); } public final static boolean checkAABBvsAABB(Vector2f p1Min, Vector2f p1Max, Vector2f p2Min, Vector2f p2Max) { return checkAABBvsAABB(p1Min.x, p1Min.y, p1Max.x - p1Min.x, p1Max.y - p1Min.y, p2Min.x, p2Min.y, p2Max.x - p2Min.x, p2Max.y - p2Min.y); } public final static boolean checkAABBvsAABB(Vector3f p1, float w1, float h1, float t1, Vector3f p2, float w2, float h2, float t2) { return checkAABBvsAABB(p1.x, p1.y, p1.z, w1, h1, t1, p2.x, p2.y, p2.z, w2, h2, t2); } public final static boolean checkAABBvsAABB(float x1, float y1, float z1, float w1, float h1, float t1, float x2, float y2, float z2, float w2, float h2, float t2) { return !(x1 > x2 + w2 || x1 + w1 < x2) && !(y1 > y2 + h2 || y1 + h1 < y2) && !(z1 > z2 + t2 || z1 + t1 < z2); } public final static boolean checkAABBvsAABB(Vector3f p1Min, Vector3f p1Max, Vector3f p2Min, Vector3f p2Max) { return checkAABBvsAABB(p1Min.x, p1Min.y, p1Min.z, p1Max.x - p1Min.x, p1Max.y - p1Min.y, p1Max.z - p1Min.z, p2Min.x, p2Min.y, p1Min.z, p2Max.x - p2Min.x, p2Max.y - p2Min.y, p2Max.z - p2Min.z); } public final static boolean checkCircleCircle(Vector2f p1, float r1, Vector2f p2, float r2) { return checkCircleCircle(p1.x, p1.y, r1, p2.x, p2.y, r2); } public final static boolean checkCircleCircle(float x1, float y1, float r1, float x2, float y2, float r2) { float distance = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1); float radiusSumSq = (r1 + r2) * (r1 + r2); return distance <= radiusSumSq; } public final static boolean checkSphereSphere(Vector3f p1, float r1, Vector3f p2, float r2) { return checkSphereSphere(p1.x, p1.y, p1.z, r1, p2.x, p2.y, p2.z, r2); } public final static boolean checkSphereSphere(float x1, float y1, float z1, float r1, float x2, float y2, float z2, float r2) { float distance = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) + (z2 - z1) * (z2 - z1); float radiusSumSq = (r1 + r2) * (r1 + r2); return distance <= radiusSumSq; } }