# Can I prevent the player from moving into the direction of collision before that collision happens?

Hello, everyone!

I am trying to make a small game with a first person controller. The game allows a player to jump and adjust player’s position midair by applying forces to player’s rigidbody. This all looks and plays nice, until the moment the player hits the wall and keeps on pushing towards it. This results in player sticking to the wall. And the player keeps sticked to the wall until a player releases the button that is forcing the player’s movement in that direction (e.g. forward, backward, right, left or combination of those).
I was thinking of casting a sphere around the player and somehow detect the direction to the point where the sphere collides with the obstacle and somehow prevent the player movement in that direction.

The question is - how do I do that “somehow”?
I was thinking of using Physics.SphereCastAll and somehow calculating the vector from the hit.point, but SphereCastAll seems to be working only in one direction. I can’t place it simply around the player, it has to be casted along the ray…

Any suggestions? Thank you!

You are provided with contacts points in the collision callbacks. Only allow movement in the direction of the contact normals of the surface you’re hitting i.e. away from them. Using Vector3.Dot of the velocity & contact-normals can facilitate this.

Either control what input is allowed or clamp the velocity so that any direction into the contact points is removed.

The other way is to apply no friction on those surfaces which is an “okay” method but not always foolproof or the best.

1 Like

Removing friction is indeed not foolproof. If the surface that the player hits has a bit of a tilt - the player can sometimes launch themself into the sky

Contact points indeed allowed me to find the point I’m colliding with. I’d only wish so that I could access them in the FixedUpdate (where my movement is happening) instead of OnColliderStay.
The other part that I can’t wrap my head around is how am I supposed to use Vector3.Dot to calculate player’s new vector correctly. Let’s assume that the player is moving mostly forward but a bit to the left towards the wall that is facing the player at 45 degrees rotation on Y. How do I calculate the new velocity, so that it would prevent player from sticking to the wall but it would still have some sort of inertia?

Thank you.

But wait…Why is your player sticking to the wall?. Have you added a modified physics material to your player?.

No. It sticks because the game is pretty dynamic and the speed that the player moves with (the force) is much greater then the gravitation force. At least as I understand.

In the callback, store the contacts for use later when you make a decision from input etc.

So here’s an example I just put together. Setting the “#if true” will abort user-input if it’s moving into a contact otherwise it’ll allow it. Of course, you can also do more sophisticated things such as remove only the components of the input vector etc.

Here’s without it active which is what you’ll get where it’s pushing with a high force against a surface that has high friction (it slows/stops):
https://gyazo.com/0de61eedd7584ed9677d74855d066ace

Here’s with it active where it doesn’t allow user-movement so the solver solves the contact with the surface but the user-input no longer allows movement into the surface:
https://gyazo.com/f896a3f6013af03c7c270a96d5c45772

``````using System.Collections.Generic;
using UnityEngine;

public class QuickController : MonoBehaviour
{
public float MoveImpulse = 10f;

private Rigidbody m_Rigidbody;
private Vector3 m_Movement;
private readonly List<ContactPoint> m_ContactPoints = new List<ContactPoint>();

private void Start()
{
m_Rigidbody = GetComponent<Rigidbody>();
}

private void Update()
{
// Some basic movement input.
var x = (Input.GetKey(KeyCode.LeftArrow) ? -1f : 0f) + (Input.GetKey(KeyCode.RightArrow) ? 1f : 0f);
var z = (Input.GetKey(KeyCode.DownArrow) ? -1f : 0f) + (Input.GetKey(KeyCode.UpArrow) ? 1f : 0f);
m_Movement = new Vector3(x, 0f, z);
}

private void FixedUpdate()
{
// Add movement impulse.
if (m_Movement == Vector3.zero)
return;
#if true
// Iterate last contacts.
foreach (var contactPoint in m_ContactPoints)
{
// If we're moving against a normal then don't apply movement.
if (Vector3.Dot(m_Movement, contactPoint.normal) < 0f)
return;
}
#endif
// Write velocity.
m_Rigidbody.velocity += m_Movement * MoveImpulse * Time.deltaTime;
}

private void OnCollisionEnter(Collision col) => AnalyseContacts(col);
private void OnCollisionStay(Collision col) => AnalyseContacts(col);
private void OnCollisionExit(Collision col) => m_ContactPoints.Clear();
private void AnalyseContacts(Collision col) => col.GetContacts(m_ContactPoints);
}
``````
1 Like

You can reduce the movement (or do this to velocity after movement):

``````m_Movement -= contactPoint.normal * Vector3.Dot(m_Movement, contactPoint.normal);
``````

There’s also this which is another way.

``````m_Movement -= Vector3.Project(m_Movement, contactPoint.normal);
``````

You have to be careful here though when you have multiple contact points as you don’t want to reduce the velocity/movement to zero as you apply the same normal again and again so averaging or just being smarter with the contacts can help.

Often this is why devs just use zero friction.

1 Like

As Melv has also suggested - create a physics material with no friction and add it to your player or the walls.

1 Like