unity3d 我的角色在移动时穿过地形

h43kikqp  于 2023-01-21  发布在  其他
关注(0)|答案(2)|浏览(480)

https://youtube.com/shorts/NYgzV5Bzd5E
从这个链接可以看到,我的角色在斜坡或下坡时会穿过地形。角色有刚体和胶囊碰撞器,地形有地形碰撞器。它通过鼠标或触摸输入移动,而不是键盘输入。不使用NavMeshAgent如何解决这个问题?
这是我的代码,如果你需要其他代码,请回复我。

// State pattern is applied, so this function is excuted instead of Update() when character moves.
    protected override void UpdateMoving()
    {
        // _destPos is the point pressed by the mouse on terrain.
        Vector3 dir = _destPos - transform.position;

        // Idle State
        if (dir.magnitude < 0.1f)
        {
            State = Define.State.Idle;
        }
        // Moving State
        // Moving logic, _stat.moveSpeed is Character's move speed.
        else
        {
            float moveDist = Mathf.Clamp(_stat.moveSpeed * Time.deltaTime, 0, dir.magnitude);
            transform.position += dir.normalized * moveDist;
            transform.rotation = Quaternion.Slerp(transform.rotation,
                Quaternion.LookRotation(dir), 20 * Time.deltaTime);
        }
    }

    // This is mouse event function, not related this question directly.
    private void OnMouseEvent_IdleRun(Define.MouseEvent evt)
    {
        RaycastHit hit;
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        bool raycastHit = Physics.Raycast(ray, out hit, 70.0f);
        
        switch (evt)
        {
            case Define.MouseEvent.PointerDown:
                if (raycastHit)
                {
                    int layer = hit.transform.gameObject.layer;

                    if (layer == (int)Define.Layer.Ground)
                    {
                        _destPos = hit.point;
                        State = Define.State.Moving;
                    }
                }
                break;
            
            case Define.MouseEvent.Press:
                if (raycastHit)
                    _destPos = hit.point;
                break;
        }
    }

这是完整的代码。
x一个一个一个一个x一个一个二个x
这是我的问题的解决方案,我修改了PlayerController中的UpdateMoving()

protected override void UpdateMoving()
    {
        Vector3 dir = _destPos - transform.position;

        if (dir.magnitude < 0.1f)
        {
            State = Define.State.Idle;
        }
        else
        {
            RaycastHit hit;
            float moveDist = Mathf.Clamp(5.0f * Time.deltaTime, 0, dir.magnitude);
            Vector3 rayStart = transform.position + Vector3.up;
            Vector3 rayDir = (transform.position + dir.normalized * moveDist) - rayStart; 
            bool raycastHit = Physics.Raycast(rayStart, rayDir, out hit, 70f, _mask);
            Debug.DrawRay(rayStart, rayDir * 5, Color.blue, 1.0f);

            if (raycastHit)
            {
                transform.position = hit.point;
                transform.rotation = Quaternion.Slerp(transform.rotation,
                    Quaternion.LookRotation(dir), 20 * Time.deltaTime);
            }
        }
    }
pokxtpni

pokxtpni1#

实际移动角色的代码并没有对地形碰撞器或者你的角色刚体做任何事情。你只是不断地向目标移动变换。如果你从标准资源中观察角色控制器,你会发现它们不断地从角色到地板进行光线投射,以确定它们是否接地。
我现在在移动的上,可以稍后用代码示例编辑我的答案。

lzfw57am

lzfw57am2#

在你的代码中,你设置了玩家每一帧的位置,为了确保它不会剪切地形,你也可以根据玩家当前所在的地形高度来改变y位置。

Vector3 pos = transform.position;
  pos.y = Terrain.activeTerrain.SampleHeight(transform.position);
  transform.position = pos;

我从documentation得到这个代码
如果您的角色没有完全放置在地面上,您也可以在y位置添加偏移量。

相关问题