- Home /
How to apply equal force back to player when colliding with a wall?
I tried asking this question previously but I was unclear, so I did some experimenting and I think I can clarify my question now.
My player's character controller moves each frame by a variable called positionChange. Essentially, this variable is the character's speed. The issue is that the only time the player ever slows down is when they are not holding down movement keys. I need the player to slow down when they collide with walls though. For example, if the player is moving 1 unit per second in the x direction, and they run into a wall that is completely flat, then the player's positionChange should decrease to 0,0,0, because 1 unit of force should be applied back to the player. How can I calculate the amount of force needed to be applied back to the player by walls?
In the below image, I have depicted the player moving 1 unit per second in both the x and z axis, and I drew a black arrow representing the direction the player will travel this frame. Since the player is moving into the wall they can not move through it, but the positionChange will not decrease. I need to decrease it though, which means I need to know by how much the player is moving into the wall; How do I decrease the positionChange by the same amount that they are moving into the wall by? (This value is represented by the blue arrow.)
Answer by BastianUrbach · Nov 19, 2019 at 02:47 PM
Unity has a builtin Physics Engine to handle those kind of things for you but you probably know that so I'll assume you have good reasons not to use it.
A wall's direction could be given in a number of ways. What you need is the wall's normal vector (a vector that is perpendicular to the wall and has a magnitude of 1). If the wall is described by one or multiple triangles, you can get a perpendicular vector with the cross product (Vector3.Cross) of two of the triangle's sides. If you have two endpoints a and b of a vertical wall, then new Vector3((b - a).z, 0, (a - b).x)) is perpendicular to it. Once you have a perpendicular vector, you just need to normalize it with Vector3.normalized.
Often 3D models contain normals anyway, you can read them with Mesh.normals. Finally, RaycastHits also contain the normal vector of the surface that was hit.
Once you have the normal vector, it's relatively simple. Calculate the dot product (Vector3.Dot) of normal and player velocity. This gives you a number indicating how quickly the player is moving towards the wall. Then just subtract this value times the normal vector from the velocity vector.
velocity -= Vector3.Dot(velocity, normal) * normal;
You mentioned that Unity has it built in; Yes, I know, but... $$anonymous$$aybe I don't? I am using a character controller for my player as opposed to rigidbodies, which I know can fairly easily do all that work for me. I made the decision to go with a character controller at the start of development, so it's fairly irreversible now. Is there any way I can have Unity do the heavy lifting for me with a character controller? I have a feeling the way I set up the positionChange variable (the velocity, basically), I might not be able to.
Character Controllers should be able to do that all by themselves. $$anonymous$$ake sure that your walls have colliders and use CharacterController.$$anonymous$$ove to move the character.
I am, but the issue is that the positionChange variable doesn't change, so if the player slides past the wall, then they instantly accelerate to the velocity they were at when they collided with the wall. The issue isn't them going through it, it's that the value that stores velocity does not change. Eg, going 1 unit up and 1 unit forwards, straight into a wall, the player will travel 1 unit up until passing the wall, then instantly go full speed forwards. Ins$$anonymous$$d, the player should have to accelerate to full speed ins$$anonymous$$d of instantly.
Answer by $$anonymous$$ · Nov 21, 2019 at 06:29 PM
add material to both player and wall collider, set bounce to 1.
I am not sure that works with character controllers, and I would prefer to do this mathematically ins$$anonymous$$d of through Unity's built-ins.