使用 NavMesh 在 Unity 中实现自行车运动的路点导航:需要建议

问题描述 投票:0回答:1

我目前正在开展一个项目,需要在 Unity 中为自行车运动系统实现路点导航。目标是在按下按钮时加速自行车并使其平稳地遵循预定义的路径点路径。

以下是我迄今为止所做工作的总结:

  • 实现了基本的自行车运动控制,包括加速 按下按钮。
  • 创建了一系列我希望自行车遵循的路径点。

但是,我不确定实现航路点导航的最佳方法。我听说 NavMesh 对于 Unity 中的寻路很有用,但我不确定它是否是自行车运动系统的正确选择。

这是我编写的代码片段以供参考:

关注.AI

public class FollowAI : MonoBehaviour
{
    MotoController motoController;
    NavMeshAgent agent;
    Transform tr;
    public Transform target;
    Transform targetPrev;
    [SerializeField] Vector3 targetPoint;

    bool targetVisible;
    bool targetIsWaypoint;

    VehicleWaypoint targetWaypoint;
    public float followDistance;

    bool close;

    [Tooltip("Percentage of maximum speed to drive at")]
    [Range(0, 1)]
    public float speed = 1;
    float initialSpeed;
    float prevSpeed;
    public float targetVelocity = -1;

    [Tooltip("Mask for which objects can block the view of the target")]
    public LayerMask viewBlockMask;
    Vector3 dirToTarget; // Normalized direction to target
    float lookDot; // Dot product of forward direction and dirToTarget
    float steerDot; // Dot product of right direction and dirToTarget
    public int MaxSteeringAngle = 45;

    private void Start()
    {
        tr = transform;
        motoController =GetComponent<MotoController>();
        agent = GetComponent<NavMeshAgent>();
        initialSpeed = speed;

        InitializeTarget();
    }
    
    public void Follow()
    {
        if (target)
        {
            if (target != targetPrev)
            {
                InitializeTarget();
            }
            targetPrev = target;
            // Is the target a waypoint?
            targetIsWaypoint = target.GetComponent<VehicleWaypoint>();
            // Can I see the target?
            targetVisible = !Physics.Linecast(tr.position, target.position, viewBlockMask);
            if (targetVisible || targetIsWaypoint)
            {
                targetPoint = target.position;
            }
            if (targetIsWaypoint)
            {
                // if vehicle is close enough to target waypoint, switch to the next one
                if ((tr.position - target.position).sqrMagnitude <= targetWaypoint.radius * targetWaypoint.radius)
                {
                    target = targetWaypoint.nextPoint.transform;
                    agent.SetDestination(target.position);
                    targetWaypoint = targetWaypoint.nextPoint;
                }
            }

            close = (tr.position - target.position).sqrMagnitude <= Mathf.Pow(followDistance, 2) && !targetIsWaypoint;
            dirToTarget = (targetPoint - tr.position).normalized;

            Vector3 relativeVector = transform.InverseTransformPoint(targetPoint);
            float SteeringAngle = (relativeVector.x / relativeVector.magnitude) * MaxSteeringAngle;

            float angleToWaypoint = Vector3.Angle(tr.forward, dirToTarget);

            float deadzoneAngle = 15f; // Adjust as needed
            float leanInput = 0f;

            if (angleToWaypoint > deadzoneAngle)
            {
                steerDot = -Mathf.Sign(steerDot) * (close ? 0 : 1);
                motoController.turnLeanAmount = SteeringAngle;
            }
            else
            {
                steerDot = 0f; // No steering needed if within deadzone
            }

            // Set accel input
            if ((tr.position - target.position).sqrMagnitude > Mathf.Pow(followDistance, 2))
            {
                motoController.customAccelerationAxis = 1f; // Start acceleration on touch down
                motoController.rawCustomAccelerationAxis = 1f;
            }
            else
            {
                motoController.customAccelerationAxis = 0f; // Start acceleration on touch down
                motoController.rawCustomAccelerationAxis = 0f;
            }

            motoController.customSteerAxis = steerDot;
            motoController.customLeanAxis = leanInput;

        }
    }

    public void InitializeTarget()
    {
        if(target)
        {
            targetWaypoint = target.GetComponent<VehicleWaypoint>();
            if (targetWaypoint)
            {
                prevSpeed = targetWaypoint.speed;
            }
        }
    }


}

移动输入控制器

public class MobileController : MonoBehaviour
{
    MotoController motoController;
    public MobileButtonHandler forward, backward, left, right, wheelie;
    private bool isTouched;
    private float touchStartTime;
    private FollowAI followAI;
    void Start()
    {
        motoController = GetComponent<MotoController>();
        followAI = GetComponent<FollowAI>();
    }

    // Update is called once per frame
    void FixedUpdate()
    {
        if(followAI != null)
        {
            if (forward.buttonPressed + backward.buttonPressed > 0)
            {
                followAI.Follow();
            }
        }
        MobileInput(left.buttonPressed+right.buttonPressed, ref motoController.customSteerAxis, motoController.steerControls.x, motoController.steerControls.y, false);
        MobileInput(forward.buttonPressed + backward.buttonPressed, ref motoController.customAccelerationAxis, 1, 1, false);
        MobileInput(left.buttonPressed+right.buttonPressed, ref motoController.customLeanAxis, motoController.steerControls.x, motoController.steerControls.y, false);
        MobileInput(forward.buttonPressed + backward.buttonPressed, ref motoController.rawCustomAccelerationAxis, 1, 1, true);
        motoController.wheelieInput = System.Convert.ToBoolean(wheelie.buttonPressed);
        
    }
    
    private void SetBreaks()
    {
        MobileInput(-1, ref motoController.rawCustomAccelerationAxis, 1f, 0.1f, false);
        MobileInput(-1, ref motoController.rawCustomAccelerationAxis, 1f, 0.1f, false);
    }
    float MobileInput(int instruction, ref float axis, float sensitivity, float gravity, bool isRaw)
    {
        var r = instruction*2;
        var s = sensitivity;
        var g = gravity;
        var t = Time.unscaledDeltaTime;

        if (isRaw)
            axis = r;
        else
        {
            if (r != 0)
                axis = Mathf.Clamp(axis + r * s * t, -1f, 1f);
            else
                axis = Mathf.Clamp01(Mathf.Abs(axis) - g * t) * Mathf.Sign(axis);
        }

        return axis;
    }

}

如果您对以下几点提出建议或见解,我将不胜感激:

  • NavMesh 是实现路点导航的合适选择吗 带有自行车运动系统的转向?
  • 如果是这样,我如何将 NavMesh 集成到我现有的代码中以实现 通过转弯实现平滑的航路点导航?
  • 是否有任何替代方法或 Unity 包可能更适合此任务?

任何帮助或指导将不胜感激。谢谢!

c# unity-game-engine game-development unityscript
1个回答
0
投票

是否有任何替代方法或 Unity 包可能更适合此任务?

从您的要求来看,听起来 Splines 是 NavMesh 的更好替代方案(可从 Unity 2022 获得)

此视频是关于设置样条线的精彩介绍:https://www.youtube.com/watch?v=n-o2e4KxbW4

这里是一个帖子的链接,其中包含一些代码,用于沿着样条线自定义对象移动:https://stackoverflow.com/a/78316304/4640357

© www.soinside.com 2019 - 2024. All rights reserved.