- Home /
Question by
snipedavid22 · Sep 25, 2020 at 10:03 AM ·
movementrigidbody3d
RigidBody falls slowly when coliding with stairs
Hi, I am trying to make a RigidBody movement in my 3d game and I did a script that makes the player climb stiars but I sometimes get a problem when the player gets stucks and slowly goes back.
This is my script: using System.Collections; using System.Collections.Generic; using UnityEngine;
public class PlayerMovement2 : MonoBehaviour
{
public float speed;
public Rigidbody rb;
public float jumpForce;
[Header("Steps")]
public float maxStepHeight = 0.4f;
public float stepSearchOvershoot = 0.01f;
private List<ContactPoint> allCPs = new List<ContactPoint>();
private Vector3 lastVelocity;
void FixedUpdate()
{
#region Stairs
Vector3 velocity = this.GetComponent<Rigidbody>().velocity;
ContactPoint groundCP = default(ContactPoint);
bool grounded = FindGround(out groundCP, allCPs);
Vector3 stepUpOffset = default(Vector3);
bool stepUp = false;
if (grounded)
stepUp = FindStep(out stepUpOffset, allCPs, groundCP, velocity);
if (stepUp)
{
this.GetComponent<Rigidbody>().position += stepUpOffset;
this.GetComponent<Rigidbody>().velocity = lastVelocity;
}
allCPs.Clear();
lastVelocity = velocity;
#endregion
}
void OnCollisionEnter(Collision col)
{
allCPs.AddRange(col.contacts);
}
void OnCollisionStay(Collision col)
{
allCPs.AddRange(col.contacts);
}
#region Stairs
bool FindGround(out ContactPoint groundCP, List<ContactPoint> allCPs)
{
groundCP = default(ContactPoint);
bool found = false;
foreach (ContactPoint cp in allCPs)
{
//Pointing with some up direction
if (cp.normal.y > 0.0001f && (found == false || cp.normal.y > groundCP.normal.y))
{
groundCP = cp;
found = true;
}
}
return found;
}
bool FindStep(out Vector3 stepUpOffset, List<ContactPoint> allCPs, ContactPoint groundCP, Vector3 currVelocity)
{
stepUpOffset = default(Vector3);
//No chance to step if the player is not moving
Vector2 velocityXZ = new Vector2(currVelocity.x, currVelocity.z);
if (velocityXZ.sqrMagnitude < 0.0001f)
return false;
foreach (ContactPoint cp in allCPs)
{
bool test = ResolveStepUp(out stepUpOffset, cp, groundCP);
if (test)
return test;
}
return false;
}
bool ResolveStepUp(out Vector3 stepUpOffset, ContactPoint stepTestCP, ContactPoint groundCP)
{
stepUpOffset = default(Vector3);
Collider stepCol = stepTestCP.otherCollider;
//( 1 ) Check if the contact point normal matches that of a step (y close to 0)
if (Mathf.Abs(stepTestCP.normal.y) >= 0.01f)
{
return false;
}
//( 2 ) Make sure the contact point is low enough to be a step
if (!(stepTestCP.point.y - groundCP.point.y < maxStepHeight))
{
return false;
}
//( 3 ) Check to see if there's actually a place to step in front of us
//Fires one Raycast
RaycastHit hitInfo;
float stepHeight = groundCP.point.y + maxStepHeight + 0.0001f;
Vector3 stepTestInvDir = new Vector3(-stepTestCP.normal.x, 0, -stepTestCP.normal.z).normalized;
Vector3 origin = new Vector3(stepTestCP.point.x, stepHeight, stepTestCP.point.z) + (stepTestInvDir * stepSearchOvershoot);
Vector3 direction = Vector3.down;
if (!(stepCol.Raycast(new Ray(origin, direction), out hitInfo, maxStepHeight)))
{
return false;
}
//We have enough info to calculate the points
Vector3 stepUpPoint = new Vector3(stepTestCP.point.x, hitInfo.point.y + 0.0001f, stepTestCP.point.z) + (stepTestInvDir * stepSearchOvershoot);
Vector3 stepUpPointOffset = stepUpPoint - new Vector3(stepTestCP.point.x, groundCP.point.y, stepTestCP.point.z);
//We passed all the checks! Calculate and return the point!
stepUpOffset = stepUpPointOffset;
return true;
}
#endregion
void Start()
{
rb.GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
rb.velocity = new Vector3(Input.GetAxis("Horizontal") * speed, rb.velocity.y, Input.GetAxis("Vertical") * speed);
if (Input.GetKeyDown(KeyCode.Space))
{
rb.velocity = new Vector3(rb.velocity.x, jumpForce, rb.velocity.z);
}
}
}
here is a video: https://youtu.be/NKWyUVDamxM
screenshot-18.png
(15.3 kB)
Comment