使用字符控制器使对象靠近边缘时掉落

时间:2019-05-09 21:24:28

标签: c# unity3d

我正在使用单位的字符控制器工具。

问题是,如果与默认角色控制器的胶囊对撞机之间存在碰撞,除非无法检测到与表面的任何接触,否则它将不会下滑或掉落。

它是这样的: enter image description here

我正像这样使用自己的重力:

private void ApplyGravity() {
        if (!characterController.isGrounded) {
            gravity += Physics.gravity * Time.deltaTime * gravityFactor;
            if (gravity.y > 0 && !Input.GetButton(jumpButton))
                gravity += Physics.gravity * Time.deltaTime * gravityFactor * (lowJumpMultiplier - 1);
        }
        else if (!isJumping) gravity = Vector3.down;

        CheckCollisionFlags();
        movement += gravity;
    }

我还没有找到任何方法来修改角色控制器的属性以应用任何滑移或添加新的对撞机来进行碰撞。

我已经尝试减小胶囊对撞机的半径,但这导致角色可以稍微穿过墙壁。

我已经考虑过使用多条射线来检查身体中部是否超出边缘,然后施加力使其掉落,但是我认为这可能是解决此问题的更简便,更优化的方法。

1 个答案:

答案 0 :(得分:0)

我终于设法解决了这个问题。

我首先要去检查角色中间是否接地。我通过在物体的位置发射射线来实现这一点。 然后,我想让两个人知道哪一侧没有与表面碰撞。我又拍摄了四束光线,每一次指向胶囊对撞机周围的红衣主教。 我检索了所有未接地的点,并计算了与当前字符位置的差异。它给了我一个添加到对象运动中的坐标,该坐标将一直增加直到下降。

让我们看看:

这就是我创建每条射线的方式。我需要两个值(x,z)来修改必须放置每条射线的基点。然后,我通过减去胶囊对撞机高度的一半来将y设置在地面上。

private Ray CreateEdgeCheckRay(float x, float z) {
        Vector3 rayPos = transform.position;
        rayPos.y -= characterController.height / 2;
        rayPos.x += x;
        rayPos.z += z;
        return new Ray(rayPos, Vector3.down);
    }

我使用此方法只是一次创建每条光线:

private Ray[] CreateSideRays() {
        Ray[] sideRays = new Ray[4];
        sideRays[0] = CreateEdgeCheckRay(0.5f, 0);
        sideRays[1] = CreateEdgeCheckRay(-0.5f, 0);
        sideRays[2] = CreateEdgeCheckRay(0, 0.5f);
        sideRays[3] = CreateEdgeCheckRay(0, -0.5f);

        return sideRays;
    }

我使用Physics.RaycastNonAlloc以长度为1的数组检索结果以提高性能。

private bool RayGrounded(Ray ray) {
        return Physics.RaycastNonAlloc(ray, rayResults, groundRayLength) < 1;
    }

最后,我将所有内容结合在一起。之前我实现了重力,所以不需要任何垂直移动。

private void CheckGroundRays() {
        Ray middleRay = CreateEdgeCheckRay(0, 0);
        if (RayGrounded(middleRay)) {
            Vector3 inEdgeMovement = Vector3.zero;
            foreach(Ray ray in CreateSideRays()) {
                if(RayGrounded(ray))
                    inEdgeMovement += (ray.origin - transform.position);
            }
            inEdgeMovement.y = 0;
            movement += inEdgeMovement;
        }
    }