Soo I have this floating capsule character controller I made and there’s a slight issue regarding slopes. Whenever a player tries to move on slopes it’s as if the floating part of the movement lags behind. If the player moves away from the slope the capsule will float too high but if they move into the slope then it sinks a bit. I don’t really know how else to help aside from that but I’m happy to answer any questions!
using Unity.Netcode;
using UnityEngine;
public class PlayerMovement : NetworkBehaviour
{
public Rigidbody playerBody;
public LayerMask traversableLayers;
[Space]
public float groundingRayLength = 2.5f;
public float groundOffset = 2f;
public float maxSnapDist = 3f;
[Space]
public float airDrag = 0.97f;
public float groundDrag = 0.97f;
public float fallSpeed = 10f;
public float moveSpeed = 5f;
public Vector3 moveDirection;
private RaycastHit? groundDetails;
private bool canMove;
public override void OnNetworkSpawn()
{
if (!IsOwner)
{
playerBody.isKinematic = true;
}
}
private void Update()
{
if (!IsOwner) return;
moveDirection = Main.Instance.Input.Player.Move.ReadValue<Vector2>();
moveDirection = Vector3.ClampMagnitude(new Vector3(moveDirection.x, 0f, moveDirection.y), 1f);
}
private void FixedUpdate()
{
if (!IsOwner) return;
bool wasGrounded = groundDetails != null;
if (Grounded())
{
Vector3 relativeDirection = CameraManager.Instance.GetMoveDirection(moveDirection);
Vector3 projectedDirection = Vector3.ProjectOnPlane(relativeDirection, groundDetails.Value.normal).normalized;
float targetHeight = groundDetails.Value.point.y + groundOffset;
float angle = Vector3.Angle(Vector3.up, groundDetails.Value.normal);
relativeDirection *= moveSpeed;
projectedDirection *= moveSpeed;
if (!canMove) canMove = playerBody.position.y <= targetHeight;
if (canMove)
{
float target = (targetHeight - playerBody.position.y) / Time.fixedDeltaTime;
playerBody.linearVelocity = new Vector3(projectedDirection.x, target, projectedDirection.z);
}
}
else
{
canMove = false;
// if (wasGrounded) playerBody.linearVelocity = new Vector3(playerBody.linearVelocity.x, 0f, playerBody.linearVelocity.z);
}
playerBody.useGravity = groundDetails == null || !canMove;
}
private bool Grounded()
{
if (Physics.Raycast(playerBody.position, Vector3.down, out RaycastHit hit, groundingRayLength, traversableLayers))
{
groundDetails = hit;
return true;
}
groundDetails = null;
return false;
}
}