// Returns the largest move that this can make in the move direction, given another circle at offset public override double[] moveTo(GameCircle other, double[] offset, double[] move) { GameCircle c1 = this; GameCircle c2 = other; double radius = c1.getRadius() + c2.getRadius(); double desiredLength = Math.Sqrt(move[0] * move[0] + move[1] * move[1]); double distFromPath = Math.Abs(offset[0] * move[1] - offset[1] * move[0]) / desiredLength; if ((distFromPath >= radius) || (offset[0] * move[0] + offset[1] * move[1] <= 0)) { // if we get here then the circles never collide and so any move is okay return(move); // return the same move to indicate that this move is okay } double distToClosestPoint = Math.Sqrt((offset[0] * offset[0] + offset[1] * offset[1]) - distFromPath * distFromPath); double allowedLength = distToClosestPoint - Math.Sqrt(radius * radius - distFromPath * distFromPath); if (allowedLength >= desiredLength) { // if we get here then the desired move is not long enough to collide return(move); } double[] result = new double[2]; // create a new array to indicate that this move is different result[0] = move[0] * allowedLength / desiredLength; result[1] = move[1] * allowedLength / desiredLength; return(result); }
// Returns the maximum amount of distance that this can move in the move direction, given a rectangle at offset public override double[] moveTo(GameRectangle other, double[] offset, double[] move) { GameCircle c = this; GameRectangle r = other; double[] mirroredMove = new double[move.Length]; double[] mirroredOffset = new double[move.Length]; int i; // flip the coordinate system so that the offset is positive in all dimensions for (i = 0; i < move.Length; i++) { if (offset[i] >= 0) { mirroredOffset[i] = offset[i]; mirroredMove[i] = move[i]; } else { mirroredOffset[i] = -offset[i]; mirroredMove[i] = -move[i]; } } //System.Collections.Generic.List<double[]> intersections; //double[] tempIntersection; // figure out where it may intersect the left/right wall double width = r.getWidth() / 2 + c.getRadius(); if (mirroredMove[0] > 0 && mirroredOffset[0] >= width) { // calculate where it will intersect this line double[] allowedMove = new double[2]; allowedMove[0] = mirroredOffset[0] - width; // check that it will go far enough to collide if (allowedMove[0] < mirroredMove[0]) { allowedMove[1] = allowedMove[0] * mirroredMove[1] / mirroredMove[0]; // make sure that it actually intersects the line segment and not just the line if (Math.Abs(mirroredOffset[1] - allowedMove[1]) <= r.getHeight() / 2) { // reflect it back correctly and return if (offset[0] < 0) { allowedMove[0] *= -1; } if (offset[1] < 0) { allowedMove[1] *= -1; } return(allowedMove); } } } double height = r.getHeight() / 2 + c.getRadius(); if (mirroredMove[1] > 0 && mirroredOffset[1] >= height) { // calculate where it will intersect this line double[] allowedMove = new double[2]; allowedMove[1] = mirroredOffset[1] - height; // check that it will go far enough to collide if (allowedMove[1] < mirroredMove[1]) { allowedMove[0] = allowedMove[1] * mirroredMove[0] / mirroredMove[1]; // make sure that it actually intersects the line segment and not just the line if (Math.Abs(mirroredOffset[0] - allowedMove[0]) <= r.getWidth() / 2) { // reflect it back correctly and return if (offset[0] < 0) { allowedMove[0] *= -1; } if (offset[1] < 0) { allowedMove[1] *= -1; } return(allowedMove); } } } // figure out where it may intersect the corner arc double length = Math.Sqrt(move[0] * move[0] + move[1] * move[1]); double signedWidth = r.getWidth() / 2; double signedHeight = r.getHeight() / 2; for (i = 0; i < 2; i++) { double lateralOffset = (mirroredOffset[0] - signedWidth) * mirroredMove[1] / length - (mirroredOffset[1] - signedHeight) * mirroredMove[0] / length; // first check that the movement line will reach the arc if (Math.Abs(lateralOffset) <= c.getRadius()) { double forwardOffset = (mirroredOffset[0] - signedWidth) * mirroredMove[0] / length + (mirroredOffset[1] - signedHeight) * mirroredMove[1] / length; // Next check that the movement line is facing the right direction if (forwardOffset >= 0) { double collisionDist = forwardOffset - Math.Sqrt(c.getRadius() * c.getRadius() - lateralOffset * lateralOffset); // Make sure that it is hitting the outside of the arc if ((Math.Abs(mirroredOffset[0] - mirroredMove[0] * collisionDist / length) >= r.getWidth() / 2) && (Math.Abs(mirroredOffset[1] - mirroredMove[1] * collisionDist / length) >= r.getHeight() / 2)) { // If we get here then it is, in fact, moving toward the corner of the rectangle from the outside. Now decide if it wants to move that far // if it doesn't want to move that far, then it can just keep going if (collisionDist >= length) { return(move); } else { // If we get here, it means is would collide with the arc and we need to shorten the length double[] allowedMove = new double[2]; allowedMove[0] = move[0] * collisionDist / length; allowedMove[1] = move[1] * collisionDist / length; return(allowedMove); } } } } // Now alter the coordinates to check the other corner, and repeat if ((mirroredOffset[0] - signedWidth) * mirroredMove[0] >= (mirroredOffset[1] - signedHeight) * mirroredMove[1]) { // switch vertically because we're closer to the left/right edge signedHeight *= -1; } else { // switch vertically because we're closer to the left/right edge signedWidth *= -1; } } // If we get here, there are no collisions and so any move is fine return(move); }