我不知道为什么我的代码无法按预期工作!
当我将速度= 1时,它工作正常。但是,如果我提高速度,那是行不通的。
我也尝试在circle类上使用FixedUpdate
,但是并不能解决问题。
我不知道我还要做什么。
实际行为:
预期的行为:
轨道舱:
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);
}
}
答案 0 :(得分: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
将永远解析为{{1 }}。相反,使用false
可以保证MoveTowards
最终将解析为true(只要transform.position == (Vector3) nextPoint
为非零!)。
此外,speed
也不是计算距离的一种方法!使用Vector2.sqrMagnitude
或Vector2.magnitude
代替:
Vector2.Distance(v1,v2)
最后一个问题是,使用 private float AddSegment(Vector2 from, Vector2 to)
{
float distance = Vector2.Distance(from, to);
distances.Add(distance);
return distance;
}
时会出现四舍五入的错误。来自the documentation:
有些因素可能意味着实际等待的时间与指定的时间不完全匹配:
在当前帧的末尾开始等待。如果您在较长的帧中以持续时间“ t”开始WaitForSeconds(例如,执行较长的操作会阻塞主线程,例如同步加载),则协程将在帧结束后返回“ t”秒,不是被调用后的“ t”秒。
允许协程在经过“ t”秒之后的第一帧继续播放,而不是在经过“ t”秒之后的确切时刻。
因此,由于Unity通常会在WaitForSeconds
秒过去后的第一帧恢复协程,因此实际上它只增加了错误的几分之一秒。因此,每次连续产生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;
}