2

我不知道为什么我的代码不能按预期工作!

当我把速度= 1,它工作正常。但是如果我提高速度,它就不起作用了。

我也尝试FixedUpdate在 circle 类上使用,但没有解决问题。

我不知道我还需要做什么。

实际行为: 实际行为的链接

预期行为: 预期行为的链接

轨道等级:

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

 public class Orbit : MonoBehaviour
 {
     public Circle circlePrefab;
     public Vector2 centerPoint = Vector2.zero;
     [Range(3, 360)] public int segments = 5;
     public float xRadius = 2f;
     public float yRadius = 2f;
     public int numberOfCircles = 0;
     public float speed = 0f;

     private Vector2 initPosition = new Vector2(0, 2f);
     private Vector2[] points;
     private List<float> distances = new List<float>();
     private float totalDistance = 0;

     // Start is called before the first frame update
     void Start()
     {
         points = new Vector2[segments];

         for (var i = 0; i < segments; i++)
         {
             Vector2 point = GetPathPoint(i / (float) segments);

             if (i > 0)
                 totalDistance += AddSegment(points[i - 1], point);

             points[i] = point;
         }

         totalDistance += AddSegment(points[segments - 1], points[0]);

         StartCoroutine(InitCircles());
     }

     private Vector2 GetPathPoint(float t)
     {
         var angle = t * 360f * Mathf.Deg2Rad;
         var x = Mathf.Sin(angle) * xRadius;
         var y = Mathf.Cos(angle) * yRadius;
         return new Vector2(centerPoint.x + x, centerPoint.y + y);
     }

     private float AddSegment(Vector2 from, Vector2 to)
     {
         float distance = (from - to).sqrMagnitude;
         distances.Add(distance);
         return distance;
     }

     private IEnumerator InitCircles()
     {
         yield return new WaitForSeconds(1);

         var time = new WaitForSeconds(totalDistance / speed / numberOfCircles);

         for (var i = 0; i < numberOfCircles; i++)
         {
             Circle circle = Instantiate(circlePrefab, initPosition, transform.rotation);
             circle.transform.parent = transform;
             circle.name = "circle " + i;
             circle.points = points;
             circle.distances = distances;
             circle.speed = speed;

             yield return time;
         }
     }
 }

圈类:

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

 public class Circle : MonoBehaviour
 {
     public Vector2[] points;
     public float speed = 1f;
     public List<float> distances = new List<float>();

     private float distance = 0;
     private int currentIndex = 0;
     private float time = 0;
     private Vector2 currentPoint;
     private Vector2 nextPoint;

     // Start is called before the first frame update
     void Start()
     {
         currentPoint = points[currentIndex];
         nextPoint = points[currentIndex + 1];
     }

     // Update is called once per frame
     void Update()
     {
         if (transform.position == (Vector3) nextPoint)
         {
             currentIndex++;
             currentIndex %= distances.Count;

             time = 0;
             currentPoint = points[currentIndex];
             nextPoint = points[(currentIndex + 1) % points.Length];
         }

         time += Time.deltaTime;
         distance = time * speed / distances[currentIndex];
         transform.position = Vector2.Lerp(currentPoint, nextPoint, distance);
     }
 }
4

1 回答 1

2

一个问题是您的圈子可能会超出您的目的地,因为您正在使用Vector2.Lerp. 相反,请考虑找到您需要行驶的距离和到下一个点的距离之间的最小值,和/或使用Vector2.MoveTowards以确保您永远不会超过目的地。

您还需要跟踪您需要行进多远并循环,直到您需要行进此帧的所有距离都被覆盖:

 void Update()
 {
     float distanceToTravel = speed * Time.deltaTime;

     while (distanceToTravel > 0) 
     {
         if (transform.position == (Vector3) nextPoint)
         {
             currentIndex = (currentIndex + 1) % distances.Count;

             currentPoint = points[currentIndex];
             nextPoint = points[(currentIndex + 1) % points.Length];
         }

         float distanceThisIteration = Mathf.Min(distanceToTravel,
                 Vector2.Distance(transform.position, nextPoint));

         transform.position = 
                 Vector2.MoveTowards(transform.position, nextPoint, distanceThisIteration);

         distanceToTravel -= distanceThisIteration;
     }
 }

在问题的代码中,当/如果您确实超出了您的目的地Lerp,那么您将输入一个transform.position == (Vector3) nextPoint永远解析为的条件false。使用MoveTowards相反保证transform.position == (Vector3) nextPoint最终将解析为真(只要speed是非零!)。

此外,Vector2.sqrMagnitude这不是计算距离的可接受方法!使用Vector2.magnitudeorVector2.Distance(v1,v2)代替:

 private float AddSegment(Vector2 from, Vector2 to)
 {
     float distance = Vector2.Distance(from, to);
     distances.Add(distance);
     return distance;
 }

最后一个问题是使用WaitForSeconds. 从文档中

有一些因素可能意味着实际等待的时间量与指定的时间量不完全匹配:

  1. 在当前帧结束时开始等待。如果您在长帧中以持续时间“t”启动 WaitForSeconds(例如,具有阻塞主线程的长操作,例如某些同步加载),协程将在帧结束后返回“t”秒,不是在它被调用后几秒钟。

  2. 允许协程在 't' 秒过去后的第一帧恢复,而不是正好在 't' 秒过去之后。

因此,由于 Unity 通常会在t几秒钟后的第一帧恢复协程,因此它实际上会增加几分之一秒的错误。所以,每次你WaitForSeconds连续屈服时,你都会把那个错误加起来,这会导致第一个和最后一个Circle非常接近。

要解决此问题,您可以创建一个协程,该协程将创建WaitForSeconds从同一帧开始的所有球体:

private IEnumerator InitCircles()
{
    yield return new WaitForSeconds(1);


    for (var i = 0; i < numberOfCircles; i++)
    {
        StartCoroutine(WaitCreateCircle(i));
    }
}

private IEnumerator WaitCreateCircle(int index)
{
    var time = index * totalDistance / speed / numberOfCircles;

    yield return new WaitForSeconds(time);
    Circle circle = Instantiate(circlePrefab, initPosition, transform.rotation);
    circle.transform.parent = transform;
    circle.name = "circle " + index;
    circle.points = points;
    circle.distances = distances;
    circle.speed = speed;

}
于 2019-09-03T23:32:31.243 回答