/** * Can we see this location? * * @param mapX * @param mapY * @param positive If non null, if this entity is detected, algorithm returns true * @param targetFlying If true, and positive is a flying gidrah, we ignore walls and simply return * true * @return true if there is a LOS to the specified map location */ public boolean canSee(float mapX, float mapY, Entity positive, boolean targetFlying) { if (targetFlying && positive != null && positive.isFlying()) { return true; } WormGameState gameState = Worm.getGameState(); GameMap map = gameState.getMap(); ArrayList<Entity> entities = gameState.getEntities(); int n = entities.size(); // Create a list of solid entities we think are somewhere in the LOS ENTITYCACHE.clear(); for (int i = 0; i < n; i++) { Entity e = entities.get(i); if (e != this && e.isActive() && e.isSolid()) { double dist = Util.distanceFromLineToPoint(getX(), getY(), mapX, mapY, e.getX(), e.getY()); if (dist >= 0.0 && dist <= e.getRadius()) { ENTITYCACHE.add(e); } } } int numCachedEntities = ENTITYCACHE.size(); BRESENHAM.plot((int) getX(), (int) getY(), (int) mapX, (int) mapY); int oldMapX = -1, oldMapY = -1; while (BRESENHAM.next()) { int x = BRESENHAM.getX() / MapRenderer.TILE_SIZE; int y = BRESENHAM.getY() / MapRenderer.TILE_SIZE; if (x != oldMapX || y != oldMapY) { for (int z = 0; z < GameMap.LAYERS; z++) { Tile tile = map.getTile(x, y, z); if (tile != null && !tile.isBulletThrough()) { // Tile blocks LOS return false; } } oldMapX = x; oldMapY = y; } // Check entity list if (positive != null) { for (int i = 0; i < numCachedEntities; i++) { Entity e = ENTITYCACHE.get(i); if (e == positive && e.getDistanceTo(BRESENHAM.getX(), BRESENHAM.getY()) < e.getRadius()) { return true; } } } // Skip 4 pixels at a time if (!BRESENHAM.next()) { break; } if (!BRESENHAM.next()) { break; } if (!BRESENHAM.next()) { break; } } return true; }
/** * Collision detection. * * @param dest The entity to check for collision with. * @return true if this entity is touching the destination entity; note that an entity can never * be touching itself */ public final boolean isTouching(Entity dest) { if (dest == this) { return false; } if (isRound() && getRadius() == 0) { return false; } if (dest.isRound() && dest.getRadius() == 0) { return false; } if (!isRound() && getBounds(BOUNDS).isEmpty()) { return false; } if (!dest.isRound() && dest.getBounds(TEMP).isEmpty()) { return false; } // At this point, BOUNDS and TEMP hold bounding rectangles, which we might // use if it's a rect-rect collision if (isRound() && dest.isRound()) { // Round-Round collision check float dx = dest.mapX + dest.getCollisionX() - (this.mapX + this.getCollisionX()); float dy = dest.mapY + dest.getCollisionY() - (this.mapY + this.getCollisionY()); dx *= dx; dy *= dy; return Math.sqrt(dx + dy) < getRadius() + dest.getRadius(); } else if (isRound() && !dest.isRound()) { // Round-Rect collison check return rectRoundCollisionCheck( mapX + getCollisionX(), mapY + getCollisionY(), getRadius(), TEMP); } else if (!isRound() && dest.isRound()) { // Rect-round collision check return rectRoundCollisionCheck( dest.mapX + dest.getCollisionX(), dest.mapY + dest.getCollisionY(), dest.getRadius(), BOUNDS); } else { // Rect-rect collision check return BOUNDS.intersects(TEMP); } }
/** * Get the distance to another entity * * @param xx * @param yy * @return distance, in pixels */ public float getDistanceTo(Entity e) { return Vector2f.sub(new Vector2f(e.getX(), e.getY()), new Vector2f(getX(), getY()), null) .length(); }