统一刚体碰撞无法正常工作

Unity rigidbody collision not working properly

我在统一刚体碰撞时遇到了很多奇怪的问题。我有一个播放器控制器脚本,它允许我移动我的播放器,但是当它与楼梯碰撞时,它会出现故障。当它与一扇门碰撞时,它会出现故障,当它在对角线行走时与地图边缘的 2 个不可见的盒子碰撞器碰撞时,它会穿过其中一个。我已经搜索了很多但找不到任何东西。我知道要继续的内容并不多,但这里有一些可能会有所帮助的内容:

    using System;
    using UnityEngine;

public class PlayerController : MonoBehaviour{
    public Rigidbody body;

    //player movement
    private float speed = 12f;
    private float walkSpeed = 10;
    private float runSpeed = 15;
    private float gravity = -9.81f;
    public float jumpHeight = 2f;
    private Vector3 inputs;

    //player rotation
    private float targetAngle = 0f;
    private float angle = 0f;
    public float turnSmoothTime = .1f;
    public float turnSmoothVelocity;

    //player jump
    public Transform groundCheck;
    public float groundDistance = 0.4f;
    public LayerMask groundMask;
    private bool isGrounded;

    //there are 6 possible directions for gravity; positive and negative x, y and z. The direction can therefore be -3, -2, -1, 1, 2 or 3 where 1=y, 2=x, 3=z
    public int direction = 1;

    public void movePlayer(Vector2 movement){

        float horizontal = movement.x;
        float vertical = movement.y;
        
        //check if the player is standing on the ground
        isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);

        Quaternion rotation = new Quaternion();

        body.freezeRotation = true;

        if (Mathf.Abs(direction) == 1){
            //gravity in y direction
            //set the direction of the gravity
            Physics.gravity = new Vector3(0f, direction * gravity, 0f);

            //set the direction the inputs should work in
            inputs.x = horizontal;
            inputs.z = vertical;
            inputs.y = body.velocity.y;

            //calculate the angle with which the player has to be rotated and make the rotation smooth (smoothing is only possible in this orientation)
            targetAngle = Mathf.Atan2(inputs.x, inputs.z) * Mathf.Rad2Deg;
            angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime);

            //set the characters rotation
            rotation = Quaternion.Euler(0f, angle, 0f);
        }
        else if (Mathf.Abs(direction) == 2){
            //gravity in x direction
            Physics.gravity = new Vector3((direction / 2) * gravity, 0f, 0f);

            inputs.y = -horizontal;
            inputs.z = vertical;
            inputs.x = body.velocity.x;
            
            targetAngle = Mathf.Atan2(-inputs.y, inputs.z) * Mathf.Rad2Deg;

            rotation = Quaternion.Euler(targetAngle, 0f, (direction / 2) * -90f);
        }
        else if (Mathf.Abs(direction) == 3){
            //gravity in z-direction

            Physics.gravity = new Vector3(0f, 0f, (direction / 3) * -gravity);

            inputs.x = horizontal;
            inputs.y = vertical;
            inputs.z = body.velocity.z;
            
            targetAngle = Mathf.Atan2(inputs.x, inputs.y) * Mathf.Rad2Deg;

            //set the rotation in the correct order of the axis (90 degrees first and then around the correct axis)
            rotation = Quaternion.AngleAxis((direction / 3) * -90f, Vector3.right) *
                       Quaternion.AngleAxis(0f, Vector3.forward) *
                       Quaternion.AngleAxis(targetAngle, Vector3.up);
        }
        else{

            direction = 1;
        }

        /*
        if (inputs != Vector3.zero){
            body.velocity = inputs;
        }*/
        
        //rotate the player in the move direction as long as they are moving
        if (inputs.magnitude >= 0.1f){
            transform.rotation = rotation;
        }
        
    }

    void FixedUpdate(){
//move the player
        body.MovePosition(body.position + inputs * speed * Time.fixedDeltaTime);
    }

    public void flip(int changedDirection){
        inputs = Vector3.zero;
        angle = 0f;
        targetAngle = 0f;
        direction = changedDirection;
    }

    public void walk(){
        if (isGrounded){
            speed = walkSpeed;
        }
    }

    public void run(){
        if (isGrounded){
            speed = runSpeed;
        }
    }

    public void jump(){
        if (isGrounded){
            if (direction == 1){
                body.velocity = new Vector3(inputs.x, jumpHeight, inputs.z);
            }
            else if (direction == 2){
                body.velocity = new Vector3(jumpHeight, inputs.y, inputs.z);
            }
            else if (direction == 3){
                body.velocity = new Vector3(inputs.x, inputs.y, jumpHeight);
            }
        }
    }
}

P.S。该代码有一些奇怪的引力变化部分。这是游戏的其余部分,但这对这个问题并不重要。希望你们能帮助我。我很乐意提供您可能需要的任何其他信息:) 感谢您提前抽出时间!!

编辑:根据第一个答案注释掉了一部分,但这并没有解决

首先,你移动你的播放器 'twice',首先在 movePlayer 函数中你有:

//move the player
if (inputs != Vector3.zero){
    body.velocity = inputs;
}

然后在每个 FixedUpdate:

body.MovePosition(body.position + inputs * speed * Time.fixedDeltaTime);

body.MovePosition 移动您的播放器,但不会将速度归零(您在 movePlayer 函数中设置)。

通过这种方式移动玩家可以 'overshoot' 对撞机太小,所以物体会通过。

您可以向刚体添加更多阻力以稍微减速对象。

好的,对于遇到类似问题的人,我找到了答案:

问题是我使用的是 body.moveposition,实际上应该 body.addforce。

这意味着您必须更改一些代码。如果您因为遇到类似问题而需要进一步解释,请与我联系,但这是我改进的代码以帮助您入门:

using System;
using UnityEngine;

public class PlayerController : MonoBehaviour{
    public Rigidbody body;

    //player movement
    private float speed = 12f;
    private float walkSpeed = 10;
    private float runSpeed = 15;
    public float gravity = -9.81f;
    public float jumpHeight = 2f;
    private Vector3 inputs;

    //player rotation
    private float targetAngle = 0f;
    private float angle = 0f;
    public float turnSmoothTime = .1f;
    public float turnSmoothVelocity;

    //player jump
    public Transform groundCheck;
    public float groundDistance = 0.4f;
    public LayerMask groundMask;
    private bool isGrounded;

    //there are 6 possible directions for gravity; positive and negative x, y and z. The direction can therefore be -3, -2, -1, 1, 2 or 3 where 1=y, 2=x, 3=z
    public int direction = 1;

    public void movePlayer(Vector2 movement){

        float horizontal = movement.x;
        float vertical = movement.y;
        
        //check if the player is standing on the ground
        isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);

        Quaternion rotation = new Quaternion();

        body.freezeRotation = true;

        if (Mathf.Abs(direction) == 1){
            //gravity in y direction
            //set the direction of the gravity
            Physics.gravity = new Vector3(0f, direction * gravity, 0f);

            //set the direction the inputs should work in
            inputs.x = horizontal;
            inputs.z = vertical;
            inputs.y = 0;

            //calculate the angle with which the player has to be rotated and make the rotation smooth (smoothing is only possible in this orientation)
            targetAngle = Mathf.Atan2(inputs.x, inputs.z) * Mathf.Rad2Deg;
            angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime);

            //set the characters rotation
            rotation = Quaternion.Euler(0f, angle, 0f);
        }
        else if (Mathf.Abs(direction) == 2){
            //gravity in x direction
            Physics.gravity = new Vector3((direction / 2) * gravity, 0f, 0f);

            inputs.y = -horizontal;
            inputs.z = vertical;
            inputs.x = body.velocity.x;
            
            targetAngle = Mathf.Atan2(-inputs.y, inputs.z) * Mathf.Rad2Deg;

            rotation = Quaternion.Euler(targetAngle, 0f, (direction / 2) * -90f);
        }
        else if (Mathf.Abs(direction) == 3){
            //gravity in z-direction

            Physics.gravity = new Vector3(0f, 0f, (direction / 3) * -gravity);

            inputs.x = horizontal;
            inputs.y = vertical;
            inputs.z = body.velocity.z;
            
            targetAngle = Mathf.Atan2(inputs.x, inputs.y) * Mathf.Rad2Deg;

            //set the rotation in the correct order of the axis (90 degrees first and then around the correct axis)
            rotation = Quaternion.AngleAxis((direction / 3) * -90f, Vector3.right) *
                       Quaternion.AngleAxis(0f, Vector3.forward) *
                       Quaternion.AngleAxis(targetAngle, Vector3.up);
        }
        else{

            direction = 1;
        }

        //rotate the player in the move direction as long as they are moving
        if (inputs.magnitude >= 0.1f){
            transform.rotation = rotation;
        }
        
    }

    void FixedUpdate(){
        body.AddForce(inputs * speed * Time.fixedDeltaTime);
    }

    public void flip(int changedDirection){
        inputs = Vector3.zero;
        angle = 0f;
        targetAngle = 0f;
        direction = changedDirection;
    }

    public void walk(){
        if (isGrounded){
            speed = walkSpeed;
        }
    }

    public void run(){
        if (isGrounded){
            speed = runSpeed;
        }
    }

    public void jump(){
        if (isGrounded){
            if (direction == 1){
                body.AddForce(new Vector3(0, jumpHeight, 0));
            }
            else if (direction == 2){
                body.AddForce(new Vector3(jumpHeight, 0, 0));
            }
            else if (direction == 3){
                body.AddForce(new Vector3(0,0 , jumpHeight));
            }
        }
    }
}

对我来说,这在跳跃方面造成了一些额外的问题,所以这里是您需要调整以解决这些问题的值:刚体质量和阻力以及玩家控制器重力和跳跃高度。