public void CheckCurrentSegment(ParticleSystem startZone, ParticleSystem endZone) { //We have a start and end position - A and B. A = startZone.transform.position; B = endZone.transform.position; //We have a Vector3 named AB which represents the line from A to B. //D will represent the closest point to the player that lies along the line AB. D = Vector3.zero; foreach (Player player in GameManager.Instance.players) { //C represents the player's position C = player.transform.position; //Define A to B by subtracting A's worldspace coord from B. AB = B - A; //Here is where we find the progressive travel down the line AB where D will fall. float t = Vector3.Dot(C - A, AB) / Vector3.Dot(AB, AB); //Create D by taking the percentage travel multiplied by the line (so 50% travel on a 8 unit vector is a 4 unit vector) //Add that vector to A and we have the location of D in worldspace. D = A + t * AB; //We don't need to create these vectors but I've done so for readability. //Find the distance from the player to the various points. Vector3 playerToD = player.transform.position - D; Vector3 playerToA = player.transform.position - A; Vector3 playerToB = player.transform.position - B; //If the distance from the player to D is less than the radius of the current, we assume the player is within the current if (playerToD.sqrMagnitude < currentRadius * currentRadius) { //The point D could potentially be outside of the two points //The point D can be outside of the line if this situation occurs: // // C // | // | // D A--------B bool betweenPoints = false; bool nearANode = false; bool nearBNode = false; bool overInputThreshhold = false; //T can potentially be negative or greater than one if (t > 0 && t < 1f) { //So we evaluate being between the points to handle the different cases accordingly. betweenPoints = true; } //If we're close to either end point, we want to know this. if (playerToA.sqrMagnitude < currentRadius * currentRadius) { nearANode = true; } if (playerToA.sqrMagnitude < currentRadius * currentRadius) { nearBNode = true; } //This is how the player escapes the air current. //One part listening to the player input float reverseInputAmt = 1 - Mathf.Clamp(player.controller.inputAmt, 0, 1); //Another part recognizing if the player has been recently affected by a // strong force that should knock them from the current if (reverseInputAmt < .5f || player.controller.forceAmt > 2) { overInputThreshhold = true; } if (!overInputThreshhold) { //This makes the outer edges of the current not as potent. float distanceFallOffMultiplier = Mathf.Clamp(1 - (playerToD.magnitude / currentRadius), 0.5f, 1.0f); //Debug.Log("D Falloff: " + distanceFallOffMultiplier + "\n"); //If the player is between the nodes or near a node //Set their velocity equal to zero //Disregard gravity //Apply a force that pushes them towards the next node & to the center. //The force applied is semi-negated if they are being affected by other sources. //This isn't the greatest if check but it gets the job done. //Other components going on: The near node cases of A and B, B // The near node cases of A and B are different from between. B doesn't push player to the center, so if they walk near the exit, force is in the direction of the current and doesn't push the player to the middle. // The distance fall off multiplier is clamped to half as powerful, so the current applies effect if (betweenPoints) { player.controller.mRigidBody.velocity = Vector3.zero; player.controller.mRigidBody.useGravity = false; player.controller.ApplyConstantForce(distanceFallOffMultiplier * reverseInputAmt * AB.normalized * pushSpeed + -playerToD * pushSpeed / 5, true, true); //Tracking if the player is in a current is gameplay relevant - say a player did bonus damage in a current, etc. player.controller.InCurrent = true; } else if (nearANode) { player.controller.mRigidBody.velocity = Vector3.zero; player.controller.mRigidBody.useGravity = false; player.controller.ApplyConstantForce(distanceFallOffMultiplier * reverseInputAmt * AB.normalized * pushSpeed + -playerToD * pushSpeed / 5, true, true); //Tracking if the player is in a current is gameplay relevant - say a player did bonus damage in a current, etc. player.controller.InCurrent = true; } else if (nearBNode) { player.controller.mRigidBody.velocity = Vector3.zero; player.controller.mRigidBody.useGravity = false; player.controller.ApplyConstantForce(distanceFallOffMultiplier * reverseInputAmt * AB.normalized * pushSpeed, true, true); //Tracking if the player is in a current is gameplay relevant - say a player did bonus damage in a current, etc. player.controller.InCurrent = true; } } } else { player.controller.mRigidBody.useGravity = true; } } }