/// <summary> /// Determines entities hit by the effect and returns the resulting list of entities. /// </summary> /// <returns>The list of entities hit by the action.</returns> public LinkedList <Entity> DetermineEntitiesHit() { //Calculate the range by finding the diagonal of the rectangle float range = TwoDimLinearHelper.PythagoreanLength(WidthFromCenter, HeightFromCenter); //Grab the entities within proximity to this effect LinkedList <Entity> nearbyEntities = EntityCollisionHelper.AllEntitiesInCircularArea(position, range); //Check each nearby entity to see if it lies within the effect's cone foreach (Entity entity in nearbyEntities) { if (!WithinRectangle(entity.transform.position, entity.PhysicalRadius)) { nearbyEntities.Remove(entity); } } return(nearbyEntities); }
/// <summary> /// Returns whether or not the entity at the provided position with the provided radius is within the cone specified by the effect's /// angle, range, and direction. /// </summary> /// <param name="entityPosition">The position of the entity.</param> /// <param name="entityRadius">The physical radius of the entity, or the radius used for collision detection.</param> /// <returns>True if the entity is inside the cone, false if the entity is not inside the cone.</returns> private bool DirectionallyWithinEffect(Vector3 entityPosition, float entityRadius) { int targetAngle = Mathf.Clamp(AngleInDegrees, 0, 180); Vector2 positionXY = position; Vector2 entityPositionXY = entityPosition; //If the effect is a full circle, angles do not need to be calculated since any angle is valid if (targetAngle == 0) { return(false); } //Find the angle the left, right edges of the cone are from the direction vector of the cone float halfAngle = (float)targetAngle / 2; //Convert the given position information into a displacement, returning true if the entity and the effect have the same position Vector2 entityDirection = entityPositionXY - positionXY; if (entityDirection.Equals(Vector2.zero)) { return(true); } //CHECK 1: ENTITY CENTER TEST //Return true if the center of the entity (entityDirection) lies in between the edges float entityAngle = Mathf.Abs(TwoDimLinearHelper.AngleInDegreesBetween(direction, entityDirection.normalized)); if (entityAngle <= halfAngle) { return(true); } //CHECK 2: ENTITY EDGE TEST //Create the left, right edge vectors for the cone. We know these vectors are already normalized Vector2 leftEdge = TwoDimLinearHelper.RotateVectorByDegrees(direction, halfAngle); Vector2 rightEdge = TwoDimLinearHelper.RotateVectorByDegrees(direction, -halfAngle); //Get the perpendicular vectors (pointing inward) of the edges. We know these vectors are already normalized Vector2 perpendicularLeftEdge = new Vector2(leftEdge.y, -leftEdge.x); Vector2 perpendicularRightEdge = new Vector2(-rightEdge.y, rightEdge.x); //Find the points on the edge of the entity's radius that are closest to the cone's edges Vector2 entityLeftEdgeTangent = entityPositionXY + (perpendicularLeftEdge * entityRadius); Vector2 entityRightEdgeTangent = entityPositionXY + (perpendicularRightEdge * entityRadius); //Use the tangent points to generate displacement vectors Vector2 entityLeftTangentDirection = entityLeftEdgeTangent - positionXY; Vector2 entityRightTangentDirection = entityRightEdgeTangent - positionXY; //Find the angles between the tangent and the tangent point directions float entityLeftTangentRelationAngle = TwoDimLinearHelper.AngleInDegreesBetween(leftEdge, entityLeftTangentDirection); float entityRightTangentRelationAngle = TwoDimLinearHelper.AngleInDegreesBetween(rightEdge, entityRightTangentDirection); //Test the angles of the tangent point directions and return false on failure bool entityLeftTangentWithinLeftEdge = entityLeftTangentRelationAngle <= 0; bool entityRightTangentWithinRightEdge = entityRightTangentRelationAngle >= 0; if (!(entityLeftTangentWithinLeftEdge && entityRightTangentWithinRightEdge)) { return(false); } //Return false if the entity is actually behind the cone and is physically unable to be hit by the cone bool leftOutsidePerpendicular = Math.Abs(entityLeftTangentRelationAngle) > 90; bool rightOutsidePerpendicular = Math.Abs(entityRightTangentRelationAngle) > 90; if (leftOutsidePerpendicular && rightOutsidePerpendicular) { if (entityDirection.magnitude > entityRadius) { return(false); } } //END TESTS //At this point, all tests have passed. Return true return(true); }
/// <summary> /// Determines whether or not the entity with the specified position and radius is within the rectangle of the effect. /// </summary> /// <param name="entityPosition">The position of the entity.</param> /// <param name="entityRadius">The physical radius of the entity, or the radius used for collision detection.</param> /// <returns>True if the entity is within the effect's rectangle, false if the entity is not within the effect's rectangle.</returns> private bool WithinRectangle(Vector2 entityPosition, float entityRadius) { //Calculate the entity's displacement vector Vector2 entityDisplacement = entityPosition - position; //CHECK 1: EFFECT CENTER TEST //Find the proximity of the entity's edge to the center of the effect float entityEdgeDistance = entityDisplacement.magnitude - entityRadius; //Assuming a positive radius, return true if the entity covers the center of the effect if (entityEdgeDistance <= 0) { return(true); } //CHECK 2: SMALLEST RECTANGLE TEST //Return true if the distance to the entity's edge is smaller than the width and height float minDimension = Mathf.Min(Width, Height); if (entityEdgeDistance <= minDimension) { return(true); } //CHECK 3: TANGENT POINT TEST //Verify the direction is not the zero vector if (direction.magnitude == 0) { return(false); } //Effectively rotate the entity according to the rectangle's rotation, so that we can perform //simple collision logic with a rectangle along the x/y axes float rectangleRotationInDegrees = TwoDimLinearHelper.AngleInDegreesBetween(Vector2.up, direction); Vector2 rotatedEntityDisplacement = TwoDimLinearHelper.RotateVectorByDegrees(entityDisplacement, rectangleRotationInDegrees); //Create the four tangent points on the edge of the entity Vector2[] tangentPoints = new Vector2[] { new Vector2(rotatedEntityDisplacement.x + entityRadius, rotatedEntityDisplacement.y), new Vector2(rotatedEntityDisplacement.x - entityRadius, rotatedEntityDisplacement.y), new Vector2(rotatedEntityDisplacement.x, rotatedEntityDisplacement.y + entityRadius), new Vector2(rotatedEntityDisplacement.x, rotatedEntityDisplacement.y - entityRadius) }; //Keep the half-values of the rectangle parameters on reference t avoid recalculations float halfWidth = WidthFromCenter; float halfHeight = HeightFromCenter; //For each tangent point, return true if the point lies inside the rectangle bool toRightOfLeftEdge; bool toLeftOfRightEdge; bool aboveLowerEdge; bool belowUpperEdge; foreach (Vector2 tangentPoint in tangentPoints) { toRightOfLeftEdge = -halfWidth <= tangentPoint.x; toLeftOfRightEdge = tangentPoint.x <= halfWidth; aboveLowerEdge = -halfHeight <= tangentPoint.y; belowUpperEdge = tangentPoint.y <= halfHeight; if (toRightOfLeftEdge && toLeftOfRightEdge && aboveLowerEdge && belowUpperEdge) { return(true); } } //CHECK 4: RECTANGLE CORNER TEST //Find the corners of the rectangle Vector2[] rectangleCorners = new Vector2[] { new Vector2(-halfWidth, -halfHeight), new Vector2(halfWidth, -halfHeight), new Vector2(-halfWidth, halfHeight), new Vector2(halfWidth, halfHeight) }; //Since no tangent points are inside the rectangle, return true if any corner is within the entity's radius Vector2 rotatedEntityDisplacementFromCorner; foreach (Vector2 rectangleCorner in rectangleCorners) { rotatedEntityDisplacementFromCorner = rotatedEntityDisplacement - rectangleCorner; if (rotatedEntityDisplacementFromCorner.magnitude <= entityRadius) { return(true); } } //END TESTS //At this point, all tests have failed and the entity is not overlapping with the rectangle. Return false return(false); }