- Home /
Slide when touching walls without losing velocity
For top-down 3d game with obstacles and walls around it (arena like) How to make the moving object not lose velocity when touching walls and obstacles? If for example, the object moves in an angle of 45 deg to the wall, it loses 50% from its movement speed (as it should in real life... but in my game I want it to behave differently) I want the object to continue moving along the wall without losing the 50% velocity
the moving object is with a rigid body and the obstacles and walls are colliders. I planted physics material with 0 friction to the moving object and the obstacles
Thanks
Answer by Ermiq · Dec 03, 2019 at 12:03 PM
Quite tricky thing.
First of all, you'll need to use Rigidbody's OnCollisionStay()
event to check if collided with a wall (or something else that has its surface positioned at ~90 degrees to the ground).
To do that, you'll use the GetContacts
property of the Collision
, iterate through them and find out those contact points where the normal (a vector that is perpendicular to the surface) is at ~90 degrees to the ground normal. If Collision
has such points, then it means you are touching a wall.
ContactPoint[] points = new ContactPoint[20];
Vector3 wallNormal; //this will store the vector that points out from the wall
bool isTouchingWall;
OnCollisionStay(Collision col)
{
int pointsAmount = col.GetContacts(points);
isTouchingWall = false; //don't know if we're near a wall yet
for (int i = 0; i < pointsAmount; i++)
{
//if angle between the touched surface and the plane ground is more than 80 degrees, than it means this surface is kind of a wall
if (Vector3.Angle(points[i].normal, Vector3.up) > 80f)
{
wallNormal = points[i].normal;
wallNormal.y = 0f; // eliminate all possible slopes of the wall touched so the vector will be ideally horizontal.
isTouchingWall = true;
break; //quit the iteration as we already got some wall
}
}
}
So, now if the rigidbody has detected some wall, isTouchingWall
will be true. But what if we jump? In this case, OnCollisionStay()
won't be triggered, and isTouschingWall
might stay true. Set it to false in:
OnCollisionExit() {
isTouchingWall = false;
}
Now, we know when the rigidbody is near a wall, and we know the wall normal vector.
With this info you'll need to change your move direction that is applied to the rigidbody in your movement methods. The resulting direction should point along the wall surface. To get this new direction you'll need to use Vector3.Reflect
to get the opposite version of the regular move direction (kind of reflected off the wall surface). And than multiply the regular move direction with the reflected direction to get the centered direction that is pointing in the middle of them, that will be the direction along the wall.
void Move()
{
//you've calculated your move direction as usual
moveDirection = ... // your code
// and than you should change it so it will point not in the wall, but along the wall
if (isTouchingWall)
{
//get the direction that will be your move direction reflected off the wall
Vector3 reflectedDir = Vector3.Reflect(moveDirection, wallNormal);
//and get the middle center direction between the two
moveDirection *= reflectedDir;
rb.AddForce(...); //your code to move the rigidbody
}
}
Your answer
Follow this Question
Related Questions
Inconsistent Jump height 3d 3 Answers
When I look around, my character rotates in a weird circle and it causes it to move around. 0 Answers
3D Model problems 1 Answer
How to rotate an object 360 degrees around a sphere with collisions? 0 Answers
Velocity powered rigidbody on a moving platform without parenting. 3 Answers