Hello everyone.
I’ve been trying to make 3D movement using RigidBody but I’m facing some issues implementing some checks.
I was trying to implement slope movement to prevent the character from bouncing down slopes and that worked fine.
Then I tried to implement a max slope angle, where the character can’t climb steep slopes, while doing so I noticed that Rigidbody.Move() makes my character sometimes pass through walls, and worse pass through the ground.
Tried to do some checks to fix both issues but I can’t adjust the movement Vector properly.
I need the movement Vector to be adjusted as to prevent movement in the direction of the slope/wall but can move along side it.
Here’s the movement script that works in FixedUpdate()
private void FixedUpdate() {
HandleMovement();
}
void HandleMovement() {
Vector2 inputVector = gameInput.GetMovementVectorNormalized();
float moveDistance = moveSpeed * Time.deltaTime;
if (inputVector != Vector2.zero) {
// calculate rotation angle from input vector
float targetRotation = Mathf.Atan2(inputVector.x, inputVector.y) * Mathf.Rad2Deg + Camera.main.transform.eulerAngles.y;
// Rotate character
transform.eulerAngles = Vector3.up * Mathf.SmoothDampAngle(transform.eulerAngles.y, targetRotation, ref rotationSpeed, 0.1f);
Vector3 moveDir = Quaternion.Euler(0f, targetRotation, 0f) * Vector3.forward;
moveDir = AdjustVelocityToSlope(moveDir, transform);
moveDir = CheckFrontCollision(moveDir, transform);
// move character in direction
rbody.MovePosition(transform.position + moveDir * moveDistance);
}
isWalking = inputVector != Vector2.zero;
}
and here’s both the function that checks wall collision and slope angle
public Vector3 CheckFrontCollision(Vector3 velocity, Transform transform) {
float stepHeight = .3f;
float playerHeight = 1f;
float playerRadius = 1f;
float checkDistance = .2f;
// Capsule Cast to check wall collision
bool canMove = !Physics.CapsuleCast(
transform.position + Vector3.up * stepHeight,
transform.position + Vector3.up * playerHeight,
playerRadius,
velocity,
checkDistance
);
print(canMove);
// if hitting an object stop forward direction
if(!canMove) velocity.z = 0; // I believe this is the issue
return velocity;
}
public Vector3 AdjustVelocityToSlope(Vector3 velocity, Transform transform) {
Ray ray = new Ray(transform.position, Vector3.down);
if (Physics.Raycast(ray, out RaycastHit hit, 0.2f)) {
// calculate slope angle
float slopeAngle = Vector3.Angle(hit.normal, transform.up);
// calculate whether we are going up the ramp or down the ramp
float slopeDirection = Vector3.Angle(hit.normal, transform.forward) - 90;
print(slopeAngle);
// if higher than certain angle block movement forward.
if (slopeAngle > 35 && slopeDirection > 0) {
velocity.z = 0; // I believe this is the issue
return velocity;
}
// align move vector with the ramp
Quaternion slopeRotation = Quaternion.FromToRotation(Vector3.up, hit.normal);
Vector3 adjustedVeclocity = slopeRotation * velocity;
if (adjustedVeclocity.y < 0) return adjustedVeclocity;
}
return velocity;
}
basically it works fine as long as my wall and slop isn’t rotated around Y axis.
I guess the issue is that I set the velocity.z to 0 and this makes the character not walk in the global forward direction.
Here’s some images to clarify.
Needless to say if I am walking towards the wall head on then the character should not walk in any direction