Make player not go through walls

I’m using a very simple script but I’m trying to make it so my player cant phase through walls, any help is appreciated.


void Update()

{

    if (Input.GetKeyDown(KeyCode.Q))

    {

        transform.position += Vector3.left; ;

    }

    if (Input.GetKeyDown(KeyCode.D))

    {

        transform.position += Vector3.right;

    }

    if (Input.GetKeyDown(KeyCode.Z))

    {

        transform.position += Vector3.up;

    }

    if (Input.GetKeyDown(KeyCode.S))

    {

        transform.position += Vector3.down;

    }

}

Hi ! Finaly I finded a solution whose works well to avoid players pass through walls !

At the moment, I am creating a 3D labyrinthe game and the player can move and run in first person.
My main issue iswas that my character could run between walls and pass through it ! And in a labyrinthe game, it’s very embarrasing ! So, this is my solution :

      • Select all walls in the
        hierarchy (with “shift” or “control”)
      • Add a component
        on every walls (if you had selected
        all walls, just do it one time)
      • Check if the box “IsTrigger” is
        unchecked to use the collisions and
        not the triggers
      • Check the button “Edit
        Collider” to see all box colliders
        points
      • The width of every wall’s
        collider must be at the minimum
        superior or egal to the player’s
        collider width (radius if it’s acapsule collider)
      • With the walls’ box colliders
        points, adjust them so that they
        can be merged to their extremities

178034-avoid-player-pass-through-walls.png

      • Create a (right click in the “Project” > “Create” > “Physic Material”)
      • Put all parameters at 0 (“Dynamic Friction”, “Static Friction”, “Bounciness”) and “Friction Combine” to “Minimum” and “Bounce Combine” to “Minimum”. It’s for avoid frictions between the player and walls and it may cause vibrations and may permit the player pass through walls.
      • Put this in the (or other player’s collider) in the parameter “Material” of the player
      • The player must have a “Rigidbody” to collide with walls (and others elements). Check them parameters : “Mass : 1”, “Drag : 0”, “Angular Drag : 0.05”, “Use Gravity : checked”, “Is Kinematic : unchecked”, “Interpolate : None”, “Collision Detection : Discrete”, “Constraints _ Freeze Position : all unchecked”, “Constraints _ Freeze Rotation : all checked

/::: if “Is Kinematic” is checked, the player will pass through all elements, if “Interpolate” is not egal to “None”, when the player will collide, there will be a little shift of the position, we block all “freeze rotation” (x,y,z), because it’s avoid the player fall when he collide with an element :::/

      • In C# in the player’s script :

/*::: We use "FixedUpdate" and not "Update", because for the displacements of the player, the
"FixedUpdate" is better to calculate more frames :::*/ 
private void FixedUpdate() {
          transform.Translate(Vector3.right * 4f * Time.deltaTime * Input.GetAxis("Horizontal"));
           if (Input.GetAxis("Vertical") != 0) {
                transform.Translate(Vector3.forward * 3f * Time.deltaTime * Input.GetAxis("Vertical"));  
           } else {
               if (Input.GetAxis("Vertical") < 0) {
                     transform.Translate(Vector3.forward * 3f * Time.deltaTime * Input.GetAxis("Vertical"));      
               }
           }
   }

That so, I hope this mini tutorial will be helpful for you ! I am just a gameplay programmer and it’s possible that this solution not works well for you, but I don’t find a good tutorial for avoid that player pass through walls, so I do it myself !

Use Rigidbody.MovePosition(rb.position + movement) instead.

Hi! Your code is a great start to learn how to use inputs and how to move objects by using their transform component, but as you already noticed, it’s no good when it comes to stop your objects from phasing through walls. The reason why this is happening it’s because you aren’t adding any extra code to check if your object is colliding with a wall or to add a limit to how far it can travel.

In order to stop this from happening, you could do several things, the easiest one is adding a rigidbody component to your gameobject in the Inspector tab and using the code I wrote to move your object. With this method you are using Unity’s physics engine which will make all the collision calculations by itself, you just need to tell the rigidbody how to move without using transform.position or any other method that bypasses the rigidbody physics.

Edit: Added rotation towards moveInput to the script.

using UnityEngine;

public class RigidbodyTesting : MonoBehaviour
{
    public float moveSpeed = 0.25f;
    public float rotationRate = 15f;
    public Transform target;

    private Rigidbody _Rigidbody;

    // Vector3 to store player inputs.
    private Vector3 moveInput;

    private void Awake()
    {
        // To store the component Rigidbody in the property _Rigidbody
        // so that you can use it anywhere in your code.
        TryGetComponent(out _Rigidbody);
    }

    private void Update()
    {
        /* To add values to the moveInput property you write "new Vector3 (x, y, z)" and fill those
        values with the inputs that you would like to use. In my case I used for the X axis
        Input.GetAxis("Horizontal") to get the input values from the default
        keys A, D, Left Arrow and Right Arrow and for the Z axis Input.GetAxis("Vertical") to
        get the default input values from the keys W, S, Up Arrow and Down Arrow.
        */

        // Try to always get your player inputs in the Update method.
        moveInput = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
    }

    private void FixedUpdate()
    {
        // Rigidbody actions are handled by Unity's physics engine, so you should always mess with
        // rigidbody stuff inside FixedUpdate, this will guarantee consistent physics behaviour.
        
        // After this you just simply use your rigidbody position with a += moveInput (like you did) and multiply
        // that Vector3 by a property I called moveSpeed so that you can control how fast your object should move.
        _Rigidbody.position += moveInput * moveSpeed;

        // sqrMagnitude is a value that goes up when any of the buttons from moveInput are pressed,
        // I added this check here to make sure that our object stays on the last registered rotation
        // (just before the player released the buttons). If you want your object to return to a default
        // rotation, remove this if condition.
        if (moveInput.sqrMagnitude > 0)
        {
            // We create a Quaternion, the type of variable we use to represent rotations and
            // we use Quaternion.LookRotation to look at our moveInput vector which always points
            // towards the moving direction, and we say that we want to rotate the Vector3.up (Y axis).
            Quaternion rotation = Quaternion.LookRotation(moveInput, Vector3.up);

            // Then we pass that rotation to our Rigidbody rot using Quaternion.Lerp which is a method
            // to interpolate between two quaternions by a given time. In our case we use as the first
            // Quaternion the _Rigidbody.rotation and as a second Quaternion our previously calculated rotation,
            // then we add time by writing Time.fixedDeltaTime (fixed cuz we are in the method FixedUpdate)
            // and we multiply that by a rotationRate to make it go faster or slower.
            _Rigidbody.rotation = Quaternion.Lerp(_Rigidbody.rotation, rotation, Time.fixedDeltaTime * rotationRate);
        }
    }
}

Make sure that the gameobject you want to move has this script attached, a rigidbody and a collider. Also make sure you have a gameobject below to act as a ground and some walls (all with colliders).

I’m sorry if this approach to the problem is out of the question but wouldn’t it be easier to use box colliders?

@ tadadosi, Thanks you help me out 2.