问题
I have been working on a object movement along a path Which i have been geting from Navmesh Unity3d I am using coroutine in which i controled it with while loop as i can show
public void DrawPath(NavMeshPath pathParameter, GameObject go)
{
Debug.Log("path Parameter" + pathParameter.corners.Length);
if (agent == null || agent.path == null)
{
Debug.Log("Returning");
return;
}
line.material = matToApplyOnLineRenderer;
line.SetWidth(1f, 1f);
line.SetVertexCount(pathParameter.corners.Length);
allPoints = new Vector3[pathParameter.corners.Length];
for (int i = 0; i < pathParameter.corners.Length; i++)
{
allPoints[i] = pathParameter.corners[i];
line.SetPosition(i, pathParameter.corners[i]);
}
StartCoroutine(AnimateArrow(pathParameter));
//StartCoroutine(AnimateArrowHigh(pathParameter));
}
#endregion
#region AnimateArrows
void RunAgain()
{
StartCoroutine(AnimateArrow(Navpath));
}
IEnumerator AnimateArrow(NavMeshPath path)
{
Vector3 start;
Vector3 end;
while (true)
{
if (index > 0)
{
if (index != path.corners.Length - 1)
{
start = allPoints[index];
index += 1;
end = allPoints[index];
StopCoroutine("MoveObject");
StartCoroutine(MoveObject(arrow.transform, start, end, 3.0f));
yield return null;
}
else
{
index = 0;
RunAgain();
}
}
else if (index == 0)
{
start = allPoints[index];
arrow.transform.position = allPoints[index];
index += 1;
end = allPoints[index];
StopCoroutine("MoveObject");
StartCoroutine(MoveObject(arrow.transform, start, end, 3.0f));
yield return null;
}
}
}
IEnumerator MoveObject(Transform arrow, Vector3 startPos, Vector3 endPos, float time)
{
float i = 0.0f;
float rate = 1.0f / time;
journeyLength = Vector3.Distance(startPos, endPos);
float distCovered = (Time.time - startTime) * speed;
float fracJourney = distCovered / journeyLength;
while (i < 1.0f)
{
// Debug.Log("fracJourney In While" + fracJourney);
arrow.position = Vector3.LerpUnclamped(startPos, endPos, fracJourney);
yield return endPos;
}
Debug.LogError("Outside While");
}
But the problem is i have to move object on a constant speed but my object is gaining speed at every loop as i have to make movement in a loop so it tends to move until user wants to end it by input guys plz help i dont understand what i am doing wrong in Coroutines that the speed of my objects is rising i wat it to stay constant but somehow its not working that way thanks
回答1:
while (i < 1.0f)
will run forever because i
is 0.0f
and 0.0f
is always < 1.0f
and there is no place inside your while loop, where you increement i
so that it will >= 1.0f. You need a way to exit that while loop. It should have looked like something below:
while (i < 1.0f){
i++ or i= Time.detaTime..... so that this loop will exist at some point.
}
Also your moving function is bad. The function below should do what you are trying to do:
bool isMoving = false;
IEnumerator MoveObject(Transform arrow, Vector3 startPos, Vector3 endPos, float time = 3)
{
//Make sure there is only one instance of this function running
if (isMoving)
{
yield break; ///exit if this is still running
}
isMoving = true;
float counter = 0;
while (counter < time)
{
counter += Time.deltaTime;
arrow.position = Vector3.Lerp(startPos, endPos, counter / time);
yield return null;
}
isMoving = false;
}
Also, in your AnimateArrow(NavMeshPath path)
function, replace these three lines of code:
StopCoroutine("MoveObject");
StartCoroutine(MoveObject(arrow.transform, start, end, 3.0f));
yield return null;
with
yield return StartCoroutine(MoveObject(arrow.transform, start, end, 3.0f));
Doing this will wait the MoveObject
function to finish before returning and running again in the while
loop. You have to replace these inside if (index != path.corners.Length - 1)
and else if (index == 0)
回答2:
As an alternative, you could utilize Unity's AnimationCurve class to map out all kinds of super smooth animation types easily:
You can define the curves in the inspector, or in code
public AnimationCurve Linear
{
get
{
return new AnimationCurve(new Keyframe(0, 0, 1, 1), new Keyframe(1, 1, 1, 1));
}
}
And you can define useage in a coroutine as such:
Vector2.Lerp (startPos, targetPos, aCurve.Evaluate(percentCompleted));
Where "percentCompleted" is your timer/TotalTimeToComplete.
A full example of lerping can be seen from this function:
IEnumerator CoTween(RectTransform aRect, float aTime, Vector2 aDistance, AnimationCurve aCurve, System.Action aCallback = null)
{
float startTime = Time.time;
Vector2 startPos = aRect.anchoredPosition;
Vector2 targetPos = aRect.anchoredPosition + aDistance;
float percentCompleted = 0;
while(Vector2.Distance(aRect.anchoredPosition,targetPos) > .5f && percentCompleted < 1){
percentCompleted = (Time.time - startTime) / aTime;
aRect.anchoredPosition = Vector2.Lerp (startPos, targetPos, aCurve.Evaluate(percentCompleted));
yield return new WaitForEndOfFrame();
if (aRect == null)
{
DeregisterObject(aRect);
yield break;
}
}
DeregisterObject(aRect);
mCallbacks.Add(aCallback);
yield break;
}
Check out this Tween library for more code examples: https://github.com/James9074/Unity-Juice-UI/blob/master/Juice.cs
回答3:
Maybe you could multiply the velocity by, say, 0.95f. This will make it accelerate, then stay at a constant speed, and then when you want it to stop it will gradually decelerate. Increasing the 0.95f will cause it to accelerate/decelerate faster.
来源:https://stackoverflow.com/questions/36497187/coroutines-and-while-loop