/* * Copyright 2011 Rod Hyde (rod@badlydrawngames.com) * * 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. */ package com.todoroo.zxzx.general; import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Pool; /** Functions that are useful for collision detection. * @author Rod */ public final class Colliders { public static interface RemovalHandler<T extends GameObject> { void onRemove (T t); } public static interface ColliderHandler<T extends GameObject, U extends GameObject> { void onCollision (T t, U u); } public static interface SceneryHandler<T extends GameObject> { void onCollision (T t, Rectangle r); } private Colliders () { } /** Returns true if two rectangles intersect. * @param a the first rectangle. * @param b the second rectangle. * @return true if the rectangles intersect, otherwise false. */ public static boolean intersects (Rectangle a, Rectangle b) { return (a.x + a.width > b.x) && (a.x < b.x + b.width) && (a.y + a.height > b.y) && (a.y < b.y + b.height); } /** Returns true if a rectangle intersects with any rectangles in an array. * @param a the rectangle. * @param rects the array of rectangles. * @return true if they intersect, otherwise false. */ public static boolean intersects (Rectangle a, Array<Rectangle> rects) { for (int i = rects.size - 1; i >= 0; i--) { Rectangle b = rects.get(i); if (intersects(a, b)) { return true; } } return false; } public static <V extends GameObject, W extends GameObject, T extends V, U extends W> void collide (T a, U b, ColliderHandler<V, W> callback) { if (a != b) { if (a.intersects(b)) { callback.onCollision(a, b); } } } public static <V extends GameObject, W extends GameObject, T extends V, U extends W> void collide (T go, Array<U> gos, ColliderHandler<V, W> callback) { for (int i = gos.size - 1; i >= 0; i--) { U other = gos.get(i); if (go.intersects(other)) { callback.onCollision(go, other); } } } public static <U extends GameObject, T extends U> void collide (Array<T> a, ColliderHandler<U, U> callback) { for (int i = a.size - 1; i >= 0; i--) { T go = a.get(i); for (int j = i - 1; j >= 0; j--) { T other = a.get(j); if (go.intersects(other)) { callback.onCollision(go, other); } } } } @SuppressWarnings("unchecked") public static <V extends GameObject, W extends GameObject, T extends V, U extends W> void collide (Array<T> a, Array<U> b, ColliderHandler<V, W> callback) { if (a != b) { for (int i = a.size - 1; i >= 0; i--) { T go = a.get(i); collide(go, b, callback); } } else { collide(a, (ColliderHandler<V, V>)callback); } } public static <U extends GameObject, T extends U> void collide (Array<T> gos, Array<Rectangle> rects, SceneryHandler<U> callback) { for (int i = gos.size - 1; i >= 0; i--) { T go = gos.get(i); collide(go, rects, callback); } } public static <U extends GameObject, T extends U> void collide (T go, Array<Rectangle> rects, SceneryHandler<U> callback) { for (int i = 0; i < rects.size && !go.inCollision; i++) { Rectangle r = rects.get(i); if (go.intersects(r)) { callback.onCollision(go, r); } } } /** Removes game objects that are marked as in collision, calling a removal handler for each one that is marked. Note that the * "U extends T" part of this method's signature means, for example, that PlayerShot and RobotShot can both have the same * handler if they are both derived from BaseShot. * * @param <T> the base class of the object. * @param <U> a more specific class of the object. * @param pool the pool to which the object belongs. * @param gos the array of game objects to check. * @param handler the collision handler callback. */ public static <T extends GameObject, U extends T> void removeMarkedCollisions (Pool<U> pool, Array<U> gos, RemovalHandler<T> handler) { // The "U extends T" allows for shotHandler to cope with both PlayerShot and RobotShot, because they both // extend BaseShot. for (int i = gos.size - 1; i >= 0; i--) { U go = gos.get(i); if (go.inCollision) { handler.onRemove(go); gos.removeIndex(i); pool.free(go); } } } /** Removes game objects that are outside of the given rectangular bounds. * @param <T> the object's class. * @param pool the pool to which the object belongs. * @param gos the array of game objects to check. * @param bounds the rectangular bounds. */ public static <T extends GameObject> void removeOutOfBounds (Pool<T> pool, Array<T> gos, Rectangle bounds) { float minX = bounds.x; float maxX = minX + bounds.width; float minY = bounds.y; float maxY = minY + bounds.height; for (int i = gos.size - 1; i >= 0; i--) { T go = gos.get(i); if (go.x >= maxX || go.x + go.width <= minX || go.y >= maxY || go.y + go.height <= minY) { gos.removeIndex(i); pool.free(go); } } } }