/** * intersectsCircleMapTile: This method checks whether a circle intersects a specified map tile. * Pre: The map tile must exist. Post: A boolean will be returned indicating whether the shapes * collide (true) or do not collide (false) */ private static boolean intersectsCircleMapTile( double circleX, double circleY, double circleRadius, int mapX, int mapY) { // Distance from circle center to map tile center (non-negative) double dCircleTileDistanceX = Math.abs(circleX - (mapX + 0.5)); double dCircleTileDistanceY = Math.abs(circleY - (mapY + 0.5)); // Case: no intersection when the circle's bounding box does not intersect the tile's bounding // box. if (dCircleTileDistanceX > (0.5 + circleRadius)) { return false; } if (dCircleTileDistanceY > (0.5 + circleRadius)) { return false; } // Case: Intersection when the circle's center lies inside the box if (dCircleTileDistanceX <= 0.5) { return true; } if (dCircleTileDistanceY <= 0.5) { return true; } // Case: Intersection if an identical circle placed on the map-tile's corners intersects the // original circle. //Variable left squared to save processor speed. double dCornerCircleIntersectionDistance = (dCircleTileDistanceX - 0.5) * (dCircleTileDistanceX - 0.5) + (dCircleTileDistanceY - 0.5) * (dCircleTileDistanceY - 0.5); return (dCornerCircleIntersectionDistance <= circleRadius * circleRadius); }
/** * valueInBoundsY: This method returns the closest value within the y-coordinates of the map. Pre: * The map must exist. Post: Returns the closest value to the parameters that is in the * y-coordinates. */ public static int valueInBoundsY(int value) { return Math.max(Math.min(dngCurrentDungeon.iDungeonYSize, value), 0); }
/** * moveEntity: This method moves an entity and checks the potential move for collisions. Pre: The * game must have been initialized. The entity at the index must not be null. Post: The entity * will have been moved accordingly. */ public static void moveEntity(int iEntityID) { boolean bXHandled = false; boolean bYHandled = false; boolean bCollidesWithWalls = handleEntity(iEntityID).collidesWithWalls(); // X and Y displacements of the entity, provided that there will be no collisions. double dEntityXShift = Math.sin(handleEntity(iEntityID).getMovementDirection()) * handleEntity(iEntityID).dMovementMagnitude; double dEntityYShift = (-1) * Math.cos(handleEntity(iEntityID).getMovementDirection()) * handleEntity(iEntityID).dMovementMagnitude; // The pre-movement xposition, yposition, and circle radius. double dCurrentXPos = handleEntity(iEntityID).getXPos(); double dCurrentYPos = handleEntity(iEntityID).getYPos(); double dCurrentSize = handleEntity(iEntityID).getSize(); // Hypothetical post-movement coordinates of the circle's bounding box double dNewXPosCenter = dCurrentXPos + dEntityXShift; double dNewXPosRight = dNewXPosCenter + dCurrentSize; double dNewXPosLeft = dNewXPosCenter - dCurrentSize; double dNewYPosCenter = dCurrentYPos + dEntityYShift; double dNewYPosTop = dNewYPosCenter - dCurrentSize; double dNewYPosBot = dNewYPosCenter + dCurrentSize; // Handling right-way movement if (dNewXPosCenter < dngCurrentDungeon.getXSize() - dCurrentSize) { if (dEntityXShift > 0 && !bXHandled && bCollidesWithWalls) { // Entity is moving right rightMovingCollisions: for (int iuP1 = (int) dNewXPosLeft; iuP1 <= (int) dNewXPosRight; iuP1 += 1) { for (int iuP2 = valueInBoundsY((int) (dCurrentYPos - dCurrentSize)); iuP2 <= valueInBoundsY((int) (dCurrentYPos + dCurrentSize)); iuP2 += 1) { if (!isWalkable(handleTile(iuP1, iuP2).getTileType())) { if (intersectsCircleMapTile(dNewXPosCenter, dCurrentYPos, dCurrentSize, iuP1, iuP2)) { dEntityXShift = Math.max( (iuP1 - dCurrentXPos) - (dCurrentSize + DISTANCE_TO_KEEP_FROM_WALL), 0); break rightMovingCollisions; } } } } bXHandled = true; } } else { dEntityXShift = 0; } // Handling left-way movement if (dNewXPosCenter > 0 + dCurrentSize) { if (dEntityXShift < 0 && !bXHandled && bCollidesWithWalls) { // Entity is moving left leftMovingCollisions: for (int iuP1 = (int) dNewXPosRight; iuP1 >= (int) dNewXPosLeft; iuP1 -= 1) { for (int iuP2 = valueInBoundsY((int) (dCurrentYPos - dCurrentSize)); iuP2 <= valueInBoundsY((int) (dCurrentYPos + dCurrentSize)); iuP2 += 1) { if (!isWalkable(handleTile(iuP1, iuP2).getTileType())) { if (intersectsCircleMapTile(dNewXPosCenter, dCurrentYPos, dCurrentSize, iuP1, iuP2)) { dEntityXShift = Math.min( (iuP1 + 1 - dCurrentXPos) + (dCurrentSize + DISTANCE_TO_KEEP_FROM_WALL), 0); break leftMovingCollisions; } } } } bXHandled = true; } } else { dEntityXShift = 0; } // Handling down-way movement if (dNewYPosCenter < dngCurrentDungeon.getYSize() - dCurrentSize) { if (dEntityYShift > 0 && !bYHandled && bCollidesWithWalls) { // Entity is moving down downMovingCollisions: for (int iuP1 = (int) dNewYPosTop; iuP1 <= (int) dNewYPosBot; iuP1 += 1) { for (int iuP2 = valueInBoundsX((int) (dCurrentXPos - dCurrentSize)); iuP2 <= valueInBoundsX((int) (dCurrentXPos + dCurrentSize)); iuP2 += 1) { if (!isWalkable(handleTile(iuP2, iuP1).getTileType())) { if (intersectsCircleMapTile(dCurrentXPos, dNewYPosCenter, dCurrentSize, iuP2, iuP1)) { dEntityYShift = Math.max( (iuP1 - dCurrentYPos) - (dCurrentSize + DISTANCE_TO_KEEP_FROM_WALL), 0); break downMovingCollisions; } } } } bYHandled = true; } } else { dEntityYShift = 0; } // Handling up-way movement if (dNewYPosCenter > 0 + dCurrentSize) { if (dEntityYShift < 0 && !bYHandled && bCollidesWithWalls) { // Entity is moving up upMovingCollisions: for (int iuP1 = (int) dNewYPosBot; iuP1 >= (int) dNewYPosTop; iuP1 -= 1) { for (int iuP2 = valueInBoundsX((int) (dCurrentXPos - dCurrentSize)); iuP2 <= valueInBoundsX((int) (dCurrentXPos + dCurrentSize)); iuP2 += 1) { if (!isWalkable(handleTile(iuP2, iuP1).getTileType())) { if (intersectsCircleMapTile(dCurrentXPos, dNewYPosCenter, dCurrentSize, iuP2, iuP1)) { dEntityYShift = Math.min( (iuP1 + 1 - dCurrentYPos) + (dCurrentSize + DISTANCE_TO_KEEP_FROM_WALL), 0); break upMovingCollisions; } } } } bYHandled = true; } } else { dEntityYShift = 0; } dNewXPosCenter = dCurrentXPos + dEntityXShift; dNewYPosCenter = dCurrentYPos + dEntityYShift; if (handleEntity(iEntityID).collidesWithEntities()) { for (int iuP1 = 0; iuP1 < entveCurrentEntities.size(); iuP1++) { if (iuP1 != iEntityID) { if (handleEntity(iuP1).collidesWithEntities()) { double distance = (dNewXPosCenter - handleEntity(iuP1).getXPos()) * (dNewXPosCenter - handleEntity(iuP1).getXPos()) + (dNewYPosCenter - handleEntity(iuP1).getYPos()) * (dNewYPosCenter - handleEntity(iuP1).getYPos()); if (distance < (dCurrentSize + handleEntity(iuP1).getSize()) * (dCurrentSize + handleEntity(iuP1).getSize())) { dEntityXShift = 0; dEntityYShift = 0; } } } } } // Moves the character by shifting their X and Y coordinates. handleEntity(iEntityID).shiftXPos(dEntityXShift); handleEntity(iEntityID).shiftYPos(dEntityYShift); }