【问题标题】:Why is the camera not rotating to face the first waypoint?为什么相机不旋转以面对第一个航路点?
【发布时间】:2019-02-28 05:30:05
【问题描述】:

游戏开始时,会从数组中随机选择一个航路点。然后相机应旋转以面向选定的随机航点并开始向其移动。

一旦相机到达路点,它应该等待 3 秒,然后再旋转面对并朝着下一个随机路点移动。

我的问题出在Start()。在开始向第一个航点移动之前,相机不会旋转以面对第一个航点。相反,它向后移动到第一个航路点。然后,当它到达路点时,它会等待 3 秒旋转并朝下一个路点移动。

除了相机不旋转以面对第一个选定的随机航点外,它工作正常。它在没有先旋转面对它的情况下向后移动。

这是我的代码:

航点脚本

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Waypoints : MonoBehaviour
{
    public GameObject[] waypoints;
    public GameObject player;
    public float speed = 5;
    public float WPradius = 1;
    public LookAtCamera lookAtCam;

    private int current = 0;
    private bool rot = false;

    public void Init()
    {
        waypoints = GameObject.FindGameObjectsWithTag("Target");

        if(waypoints.Length > 0)
        {
            StartCoroutine(RotateFacingTarget(waypoints[UnityEngine.Random.Range(0, waypoints.Length)].transform));
        }
    }

    void Update()
    {
        if (waypoints.Length > 0)
        {
            if (Vector3.Distance(waypoints[current].transform.position, transform.position) < WPradius)
            {
                current = UnityEngine.Random.Range(0, waypoints.Length);
                rot = false;
                StartCoroutine(RotateFacingTarget(waypoints[current].transform));

                if (current >= waypoints.Length)
                {
                    current = 0;
                }
            }

            if (rot)
                transform.position = Vector3.MoveTowards(transform.position, waypoints[current].transform.position, Time.deltaTime * speed);
        }
    }

    IEnumerator RotateFacingTarget(Transform target)
    {
        yield return new WaitForSeconds(3);

        lookAtCam.target = target;
        rot = true;
    }
}

看相机脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LookAtCamera : MonoBehaviour
{
    //values that will be set in the Inspector
    public Transform target;
    public float RotationSpeed;

    //values for internal use
    private Quaternion _lookRotation;
    private Vector3 _direction;

    // Update is called once per frame
    void Update()
    {
        //find the vector pointing from our position to the target
        if (target)
        {
            _direction = (target.position - transform.position).normalized;

            //create the rotation we need to be in to look at the target
            _lookRotation = Quaternion.LookRotation(_direction);

            //rotate us over time according to speed until we are in the required rotation
            transform.rotation = Quaternion.Slerp(transform.rotation, _lookRotation, Time.deltaTime * RotationSpeed);
        }
    }
}

我该如何解决这个问题?

【问题讨论】:

  • 你是从某个地方打电话给Waypoints.Init()吗?我没有看到 waypoints 变量在哪里设置了任何值。
  • @Eliasar 是的,我有第三个脚本附加到生成航点的空 GameObject 上,在生成航点后我调用 Init() 方法。
  • 作为一个命名点(命名约定),因为它运行了不止一次,我将它重命名为 RefreshWaypoints 而不是 Init。此外,由于您多次刷新它,您的协程将多次触发而不是等待处理。您可能有多个协同程序正在运行。

标签: c# unity3d


【解决方案1】:

假设 Waypoints.Init() 正在被调用,而您的 waypoints 变量的数组为 3。

  • Waypoints.Init() 启动协程
    • 您的协程等待 3 秒
    • 3 秒后,您将相机目标设置为 Slerps 朝向该位置
  • Update 在第一帧上写着waypoints.Length &gt; 0 == true
    • 它没有靠近它的目标,rot 为假,所以它不动

现在,您正在等待 3 秒,不旋转,也不移动。

  • 您的协程的 3 秒等待时间已到,并开始向您的目标旋转
  • rot 现在在轮换开始时为 true,因此您的 Update 方法也开始向目标移动

您的逻辑似乎在操作顺序的工作方式上是错误的。如果它需要按你描述的那样操作,我建议你对目标进行不同的操作。

我使用枚举实现了以下功能:

航点

public class Waypoints : MonoBehaviour
{
    private GameObject[] waypoints;
    private Transform currentWaypoint;

    private enum CameraState
    {
        StartRotating,
        Rotating,
        Moving,
        Waiting
    }

    private CameraState cameraState;

    public GameObject player;
    public float speed = 5;
    public float WPradius = 1;
    public LookAtCamera lookAtCam;

    private int current = 0;
    private bool isCameraRotating = false;

    void Start()
    {
        cameraState = CameraState.StartRotating;
    }

    void Update()
    {
        switch (cameraState)
        {
            // This state is used as a trigger to set the camera target and start rotation
            case CameraState.StartRotating:
            {
                // Sanity check in case the waypoint array was set to length == 0 between states
                if (waypoints.Length == 0)
                    break;

                // Tell the camera to start rotating
                currentWaypoint = waypoints[UnityEngine.Random.Range(0, waypoints.Length)].transform;
                lookAtCam.target = currentWaypoint;
                cameraState = CameraState.Rotating;

                break;
            }

            // This state only needs to detect when the camera has completed rotation to start movement
            case CameraState.Rotating:
            {
                if (lookAtCam.IsFinishedRotating)
                    cameraState = CameraState.StartMoving;

                break;
            }

            case CameraState.Moving:
            {
                // Move
                transform.position = Vector3.MoveTowards(transform.position, currentWaypoint.position, Time.deltaTime * speed);

                // Check for the Waiting state
                if (Vector3.Distance(currentWaypoint.position, transform.position) < WPradius)
                {
                    // Set to waiting state
                    cameraState = CameraState.Waiting;

                    // Call the coroutine to wait once and not in CameraState.Waiting
                    // Coroutine will set the next state
                    StartCoroutine(WaitForTimer(3));
                }

                break;
            }
            case CameraState.Waiting:
                // Do nothing. Timer has already started
                break;
        }
    }

    IEnumerator WaitForTimer(float timer)
    {
        yield return new WaitForSeconds(timer);
        cameraState = CameraState.StartRotating;
    }

    public void RefreshWaypoints()
    {
        waypoints = GameObject.FindGameObjectsWithTag("Target");
    }
}

LookAtCamera

public class LookAtCamera : MonoBehaviour
{
    // Values that will be set in the Inspector
    public Transform target;
    public float RotationSpeed;

    private float timer = 0.0f;
    public bool IsRotationFinished
    {
        get { return timer > 0.99f; }
    }

    // Update is called once per frame
    void Update()
    {
        if (target != null && timer < 0.99f)
        {
            // Rotate us over time according to speed until we are in the required rotation
            transform.rotation = Quaternion.Slerp(transform.rotation,
                Quaternion.LookRotation((target.position - transform.position).normalized),
                timer);

            timer += Time.deltaTime * RotationSpeed;
        }
    }
}

【讨论】:

  • 尝试了您的解决方案。相机永远不会面向下一个目标旋转。它正在移动到下一个目标,但仍然像一开始一样面对。根据下一个航路点的位置,它只是从右向左直线向前移动。
  • LookAtCamera 中为目标放置一些调试语句,以及在Waypoints 中设置目标的位置。他们对选定的目标有什么看法?
  • 我发现了问题所在。在 LookAtCamera 脚本就行了: if (target != null && timer
  • 然后在设置目标的时候把时间设置为0.0。制作一个方法来重置它,或者制作一个重置计时器并设置目标的方法,而不是直接在 Waypoints 中设置目标
  • 好的,它似乎正在工作。我添加了一个获取浮动的新方法,然后将计时器设置为浮动 0.0f,但是一旦相机旋转并完成面向新目标的旋转,那么它会在开始移动之前再等待 3 秒或更长时间。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-22
  • 1970-01-01
相关资源
最近更新 更多