【问题标题】:Make an object fall when it is near an edge using character controller使用角色控制器使物体在靠近边缘时下落
【发布时间】:2022-04-07 18:39:04
【问题描述】:

我正在使用 unity 的角色控制器工具。

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

它是这样的:

我就是这样使用自己的重力:

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;
    }

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

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

我曾考虑使用多条光线来检查身体的中部是否超出边缘,然后施加力使其下落,但我认为这可能是解决此问题的一种更简单、更优化的方法。

【问题讨论】:

  • 请重新表述您对问题的初始描述。如果人们不了解您的问题是什么,他们将无法帮助您。

标签: c# unity3d


【解决方案1】:

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

我首先要做的是检查角色的中间是否接地。我通过在物体的位置发射光线来实现这一点。 然后,我想让两个人知道哪一边没有与表面发生碰撞。我又射了四道射线,在胶囊对撞机周围的每个点基数上射了一道。 我检索了每个未接地的点,并计算了与当前字符位置的差异。它给了我一个坐标,我将它添加到对象的运动中,该坐标会一直增加直到它下落。

让我们看看:

这就是我创建每条光线的方式。我需要两个值 (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;
        }
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-26
    相关资源
    最近更新 更多