// Calculates the displacement required in order not to be in a world collider private Vector3 ResolveCollisions(ref Vector3 playerVelocity) { // Get nearby colliders Physics.OverlapSphereNonAlloc(transform.position, Radius + 0.1f, _overlappingColliders, ~_excludedLayers); var totalDisplacement = Vector3.zero; var checkedColliderIndices = new HashSet <int>(); Vector3 velocityBeforeCrop = playerVelocity; // If the player is intersecting with that environment collider, separate them for (var i = 0; i < _overlappingColliders.Length; i++) { // Two player colliders shouldn't resolve collision with the same environment collider if (checkedColliderIndices.Contains(i)) { continue; } var envColl = _overlappingColliders[i]; // Skip empty slots if (envColl == null) { continue; } Vector3 collisionNormal; float collisionDistance; if (Physics.ComputePenetration( _collisionVolume, _collisionVolume.transform.position, _collisionVolume.transform.rotation, envColl, envColl.transform.position, envColl.transform.rotation, out collisionNormal, out collisionDistance)) { // Ignore very small penetrations // Required for standing still on slopes // ... still far from perfect though if (collisionDistance < 0.015) { continue; } checkedColliderIndices.Add(i); // Get outta that collider! totalDisplacement += collisionNormal * collisionDistance; // Crop down the velocity component which is in the direction of penetration playerVelocity -= Vector3.Project(playerVelocity, collisionNormal); } } // It's better to be in a clean state in the next resolve call for (var i = 0; i < _overlappingColliders.Length; i++) { _overlappingColliders[i] = null; } // Landing fx if (totalDisplacement.magnitude > 0.0001 && // There is some displacement Vector3.Dot(totalDisplacement.normalized, Gravity.Down) < -0.9f) // That displacement is against gravity { float verticalVelocity = Vector3.Dot(velocityBeforeCrop, Gravity.Down); const float differentSfxVelocityLimit = 25f; if (verticalVelocity > differentSfxVelocityLimit) { _sfx.LandFromHeight(); } else { _sfx.Land(); } } return(totalDisplacement); }