/* * ----------------------------------------------------------------------- * Copyright 2012 - Alistair Rutherford - www.netthreads.co.uk * ----------------------------------------------------------------------- * * 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.netthreads.libgdx.scene; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.Group; import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.utils.SnapshotArray; /** * Helper methods for traversing through scenes and actors. * * I have put this stuff here to void having to subclass the base types from LibGdx anymore than I have to. * */ public class SceneHelper { private static final Vector2 point = new Vector2(); /** * Find hit class. * * @param x * Current x position. * @param y * Current y position * @param group * The starting Group. * @param targetClass * The target class type. * * @return The target or null if not found. */ @SuppressWarnings("rawtypes") public static Actor hit(float x, float y, Group group, Class targetClass) { SnapshotArray<Actor> children = group.getChildren(); Actor hit = null; boolean found = false; int index = children.size - 1; while (!found && index >= 0) { Actor child = children.get(index); if (child.getClass().isAssignableFrom(targetClass)) { point.x = x; point.y = y; group.localToDescendantCoordinates(child, point); if (child.hit(point.x, point.y, true) != null) { found = true; hit = child; } else if (child instanceof Group) { child = hit(x, y, (Group) child, targetClass); } } index--; } return hit; } /** * Look for intersection between two actors. * * I have defined this here as I can't extend the base classes Actor and Group. * * @param x * The x pos rectangle. * @param y * The y pos rectangle. * @param width * The rectangle width. * @param height * The rectangle height. * @param group * The group. * @param targetClass * The target class. * * @return Target class, null if no intersection. */ @SuppressWarnings("rawtypes") public static Actor intersects(float x, float y, float width, float height, Group group, Class targetClass) { SnapshotArray<Actor> children = group.getChildren(); Actor hit = null; int index = children.size - 1; while (hit == null && index >= 0) { Actor child = children.get(index); point.x = x; point.y = y; group.localToDescendantCoordinates(child, point); // If child is our target class then immediately check for // intersection if (child.getClass().equals(targetClass)) { if (isIntersect(point.x, point.y, width, height, 0, 0, child.getWidth(), child.getHeight())) { hit = child; } } else if (child instanceof Group) { hit = intersects(point.x, point.y, width, height, (Group) child, targetClass); } index--; } return hit; } /** * Makes simple intersection check. * * @param sourceX * Source rectangle x pos. * @param sourceY * Source rectangle x pos. * @param sourceWidth * Source rectangle width. * @param sourceHeight * Source rectangle height. * @param targetX * Target rectangle x pos. * @param targetY * Source rectangle y pos. * @param targetWidth * Source rectangle width. * @param targetHeight * Source rectangle height. * * @return True if two rectangles intersect. */ public static boolean isIntersect(float sourceX, float sourceY, float sourceWidth, float sourceHeight, float targetX, float targetY, float targetWidth, float targetHeight) { float left1 = sourceX; float left2 = targetX; float right1 = sourceX + sourceWidth; float right2 = targetX + targetWidth; float top1 = sourceY; float top2 = targetY; float bottom1 = sourceY + sourceHeight; float bottom2 = targetY + targetHeight; if (bottom1 < top2) return false; if (top1 > bottom2) return false; if (right1 < left2) return false; if (left1 > right2) return false; return true; } /** * Look for target hit of specified class. * * @param x * Current x position. * @param y * Current y position * @param stage * The starting stage. * @param targetClass * The target class type. * @return Target class or null if not found. */ @SuppressWarnings("rawtypes") public static Actor hit(float x, float y, Stage stage, Class targetClass) { Group root = stage.getRoot(); SnapshotArray<Actor> children = root.getChildren(); Actor hit = null; boolean found = false; int index = children.size - 1; while (!found && index >= 0) { Actor child = children.get(index); point.x = x; point.y = y; root.localToDescendantCoordinates(child, point); Actor childHit = root.hit(point.x, point.y, true); if (childHit != null && childHit.getClass().isAssignableFrom(targetClass)) { found = true; hit = childHit; } else { index--; } } return hit; } }