public void FixedUpdate()
{
Vector3 movementDirection = new Vector3(_playerActions.CurrentMovementDirection.x, 0, _playerActions.CurrentMovementDirection.y);
Vector3 movementVelocity = movementDirection * _context.Config.GroundControlMult;
Vector3 movementDisplacement = movementVelocity * Time.fixedDeltaTime;
Vector3 currentPosition = _context.Rigidbody.position;
float colliderRadius = _context.Collider.radius;
float colliderHeight = _context.Collider.height;
Vector3 lastNormal = Vector3.zero;
for (int i = 0; i < KCCUtils.MAX_WALL_CHECK_ITERATIONS; i++)
{
if (KCCUtils.CheckWillBeAgainstWall(currentPosition, colliderRadius, colliderHeight, movementDisplacement.normalized, movementDisplacement.magnitude, out RaycastHit hit))
{
float distanceToWall = Mathf.Max(hit.distance - KCCUtils.SKIN_WIDTH, 0);
Vector3 movementToWall = movementDisplacement.normalized * distanceToWall;
Vector3 movementInsideWall = movementDisplacement - movementToWall;
currentPosition += movementToWall;
// We've hit 1 plane. Slide along it.
if (i == 0)
{
movementDisplacement = Vector3.ProjectOnPlane(movementInsideWall, hit.normal);
}
// We've hit 2 planes. The only legal movement is along their intersection.
if (i == 1)
{
Vector3 crossProduct = Vector3.Cross(lastNormal, hit.normal);
Vector3 creaseVector = crossProduct.normalized;
movementDisplacement = Vector3.Project(movementInsideWall, creaseVector);
}
// We've hit 3 planes. The only legal movement is away from all 3.
if (i == 2)
{
movementDisplacement = Vector3.zero;
}
lastNormal = hit.normal;
}
else
{
currentPosition += movementDisplacement;
break;
}
}
_context.Rigidbody.MovePosition(currentPosition);
}
// Wall check
public static bool CheckWillBeAgainstWall(Vector3 startPosition, float radius, float height, Vector3 movementDirection, float maxDistance, out RaycastHit hit)
{
radius -= SKIN_WIDTH;
Vector3 topSphereOrigin = startPosition + Vector3.up * ((height / 2) - radius);
Vector3 bottomSphereOrigin = startPosition + Vector3.down * ((height / 2) - radius);
return Physics.CapsuleCast(topSphereOrigin, bottomSphereOrigin, radius, movementDirection, out hit, maxDistance);
}