简体   繁体   中英

Stop my first person character controller going through the wall in Unity using C#?

As seen in the video here: https://i.gyazo.com/ad45ef9e231fd2f9ec6d4cf76889aece.mp4

My code:

MouseLook.cs:

using UnityEngine;
using System.Collections;

public class MouseLook : MonoBehaviour
{
public enum RotationAxes { MouseXAndY = 0, MouseX = 1, MouseY = 2 }
public RotationAxes axes = RotationAxes.MouseXAndY;
public float sensitivityX = 3F;
public float sensitivityY = 3F;
public Camera playerCamera;

public float minimumX = -360F;
public float maximumX = 360F;

public float minimumY = -60F;
public float maximumY = 60F;



private float rotationX = 0F;
private float rotationY = 0F;

private Quaternion originalRotation;

void Update()
{
    if (axes == RotationAxes.MouseXAndY)
    {
        rotationX += Input.GetAxis("Mouse X") * sensitivityX;
        rotationY += Input.GetAxis("Mouse Y") * sensitivityY;

        rotationX = ClampAngle(rotationX, minimumX, maximumX);
        rotationY = ClampAngle(rotationY, minimumY, maximumY);

        Quaternion xQuaternion = Quaternion.AngleAxis(rotationX, Vector3.up);
        Quaternion yQuaternion = Quaternion.AngleAxis(rotationY, -Vector3.right);

        transform.localRotation = originalRotation * xQuaternion * yQuaternion;
    }

    if (axes == RotationAxes.MouseX)
    {
        rotationX += Input.GetAxis("Mouse X") * sensitivityX;
        rotationX = ClampAngle(rotationX, minimumX, maximumX);

        Quaternion xQuaternion = Quaternion.AngleAxis(rotationX, Vector3.up);
        transform.localRotation = originalRotation * xQuaternion;
    }

    if (axes == RotationAxes.MouseY || playerCamera != null)
    {
        rotationY += Input.GetAxis("Mouse Y") * sensitivityY;
        rotationY = ClampAngle(rotationY, minimumY, maximumY);

        Quaternion yQuaternion = Quaternion.AngleAxis(-rotationY, Vector3.right);

        if (playerCamera != null)
        {
            playerCamera.transform.localRotation = originalRotation * yQuaternion;
        }
        else
        {
            transform.localRotation = originalRotation * yQuaternion;
        }
    }
}

void Start()
{
    /*
    if (gameObject.GetComponent<Rigidbody>())
    {
        gameObject.GetComponent<Rigidbody>().freezeRotation = true;
    }
    */
    originalRotation = transform.localRotation;
}

public static float ClampAngle(float angle, float min, float max)
{
    if (angle < -360F)
    {
        angle += 360F;
    }

    if (angle > 360F)
    {
        angle -= 360F;
    }

    return Mathf.Clamp(angle, min, max);
}

}

FirstPersonController.cs:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
using Cursor = UnityEngine.Cursor;




public class FirstPersonController : MonoBehaviour
{
    private float speed = 5;
    private float jumpPower = 4;
    Rigidbody rb;
    CapsuleCollider col;
    public GameObject crossHair;
    bool isActive;
    float HorizontalInput;
    float VerticalInput;


    void Start()
    {
        Cursor.visible = false;
        Cursor.lockState = CursorLockMode.Locked;
        rb = GetComponent<Rigidbody>();
        col = GetComponent<CapsuleCollider>();
        crossHair = GameObject.FindWithTag("CrossHair");
    }


    void Update()
    {
        HorizontalInput = Input.GetAxisRaw("Horizontal");
        VerticalInput = Input.GetAxisRaw("Vertical");

        if (Input.GetKeyDown("escape"))
        {
            Cursor.lockState = CursorLockMode.None;
        }

        if (Input.GetButtonDown("Sprint"))
        {
            speed = 15;
        }

        if (Input.GetButtonUp("Sprint"))
        {
            speed = 5;
        }

        if (Input.GetKeyDown(KeyCode.H))
        {
            isActive = !isActive;
        }

        if (isActive)
        {
            crossHair.SetActive(true);
        }
        else
        {
            crossHair.SetActive(false);
        }

    }


    void FixedUpdate()
    {
        Vector3 xMovement = transform.right * speed * HorizontalInput * Time.deltaTime;
        Vector3 zMovement = transform.forward * speed * VerticalInput * Time.deltaTime;
        rb.velocity = new Vector3(HorizontalInput, 0, VerticalInput) * speed;



        if (isGrounded() && Input.GetButtonDown("Jump"))

        {
            rb.AddForce(Vector3.up * jumpPower, ForceMode.Impulse);
        }
    }


    private bool isGrounded()
    {
        return Physics.Raycast(transform.position, Vector3.down, col.bounds.extents.y + 0.1f);
    }
}

Is there anything wrong I am doing in this code, if so how do I fix it?

Entire project can be downloaded here: https://github.com/Some-T/FirstPersonController-CSharp

Project has relevant colliders and rigidbodies set up!

Someone has advised me to use shapecast, but I believe that may incorrect? I can't see how that would work as my player does not have character controller component added to it?

Overall how do I stop my first person character controller going through the wall like in the initial video specified above?

Upon further research I have discovered the following:

The answer is to use:

https://docs.unity3d.com/ScriptReference/Rigidbody.AddForce.html as a quick fix.

But definitively for flawlessness use:

https://docs.unity3d.com/ScriptReference/Rigidbody-velocity.html

As to how in C# I am not so sure, but here is a screen shot I did in bolt asset.

在此处输入图像描述

Currently I have movmement working with velocity but it does not work properly, not sure as to why? So overall my question now is how do I get movement working using velocity? I added a line in FirstPersonController.cs that moves the character using velocity of rb.velocity = new Vector3(HorizontalInput, 0, VerticalInput) * speed; so my only question and issue now is my player does not move in the direction the camera on my player is facing so I am not sure how to fix this specific thing overall?

  1. In your project code is different from one that you provided here.
  2. Try to enable rigidbody`s rotation constraint - freeze X and Z rotation, leave only Y. When you rotate your capsule collider (as it works in your project), it can "climb" on a wall.
  3. Do the isGrounded check when you move, and lock movement, if not grounded.
  4. Try to increase Collider.contactOffset
  5. If above does not helps, try to use Rigidbody.velocity instead of Rigidbody.MovePosition.
  6. You can also reduce Rigidbody.drag
  7. In general, pretty good technique is to use NavMesh for movement - in this way, you able to explicitly lock player from movement outside of navmesh surface. But, of course, it doesn`t fit to many gameplays.

Hope, it helps.

upd You move your player like this:

void FixedUpdate()
    {
        Vector3 xMovement = transform.right * speed * HorizontalInput * Time.deltaTime;
        Vector3 zMovement = transform.forward * speed * VerticalInput * Time.deltaTime;
    }

Note, that you not even apply it to rigidbody; But you get your input this way:

float HorizontalInput = Input.GetAxis("Horizontal");         
float VerticalInput = Input.GetAxis("Vertical");

in Update, so input just stays inside Update, and does not applied at all. You declared your variables twice, once on class top, another in Update().

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM