- Home /
Howcome this coroutine loops once?
I'm having a bit of a hard time understand coroutine and lerp. This IEnumerator should iterate several times, but the loop only ever fires once. Also not sure if the Lerp is right.
Thanks for reading.
IEnumerator move_item()
{
for (float t = 0; t < 1; t += Time.deltaTime / 1f)
{
recievedItem.transform.position = Vector3.Lerp (recievedItem.transform.position, transform.position, t);
yield return null;
StartCoroutine (move_item());
}
yield return new WaitForSeconds(1f);
}
[meta] Jabes22, try not to ask multiple questions at the same time, and people here don't usually like pleasantries. Try to be as impersonal as possible.
Answer by Erethan · Jan 19, 2017 at 05:59 PM
Generally, you would want the Lerp method to have a stop condition related to the distance from object to target
IEnumerator move_item()
{
if(Vector3.Distance(recievedItem.transform.position, transform.position) > 0.01f)
{
recievedItem.transform.position = Vector3.Lerp(recievedItem.transform.position, transform.position, Time.deltaTime);
yield return null;
StartCoroutine(move_item());
}
}
Note that after every Vector3.Lerp call, recievedItem will be closer to its target (if the range is between 0 and 1). You don't need to increase your t value up to 1.
Ins$$anonymous$$d of always starting the Coroutine I think it'd be better to do it like this, no?
IEnumerator move_item()
{
while(Vector3.Distance(recievedItem.transform.position, transform.position) > 0.01f)
{
recievedItem.transform.position = Vector3.Lerp(recievedItem.transform.position, transform.position, Time.deltaTime);
yield return null;
}
}
It is indeed more efficient, but since the question was about coroutine loops, I thought to write it that way to illustrate the concept discussed.
I've done that exact code before. The ENumerator only runs once for some reason. Thanks for replying.
using UnityEngine;
using System.Collections;
public class btn_script : $$anonymous$$onoBehaviour {
// Player
public GameObject player;
public GameObject btn;
public GameObject highlightBtn;
private bool highlighted;
private GameObject highlightedID;
private GameObject recievedItem;
private bool movingItem;
// Use this for initialization
void Start () {
highlighted = false;
movingItem = false;
}
// Update is called once per frame
void Update () {
if (highlighted && highlightedID == null) {
highlightedID = (GameObject)Instantiate (highlightBtn, new Vector3 (btn.transform.position.x, btn.transform.position.y, 0f), transform.rotation);
} else if(!highlighted && highlightedID != null){
Destroy (highlightedID);
}
if (movingItem) {
}
// End update
}
void On$$anonymous$$ouseDown()
{
// Left clicked menu button
if (Input.Get$$anonymous$$ouseButton (0))
{
if(name.Contains("close"))
{
// Remove hover from all menu buttons
GameObject[] objects = GameObject.FindGameObjectsWithTag("floor_item");
foreach(GameObject item in objects)
{
if(item.GetComponent<Hover$$anonymous$$enu>() != null)
{
item.GetComponent<Hover$$anonymous$$enu>().clear();
}
}
// End if button close clicked
}else if(name.Contains ("take"))
{
// Add the item to the player
recievedItem = player.GetComponent<Character>().return_last_clicked_item();
player.gameObject.GetComponent<Character>().recieve_item();
// Remove hover from all menu buttons
GameObject[] objects = GameObject.FindGameObjectsWithTag("floor_item");
foreach(GameObject item in objects)
{
if(item.GetComponent<Hover$$anonymous$$enu>() != null)
{
item.GetComponent<Hover$$anonymous$$enu>().clear();
}
}
movingItem = true;
StartCoroutine (move_item());
// End take clicked
}
// End left clicked menu button
}
}
IEnumerator move_item()
{
while(Vector3.Distance(recievedItem.transform.position, transform.position) > 0.01f)
{
recievedItem.transform.position = Vector3.Lerp(recievedItem.transform.position, transform.position, Time.deltaTime);
yield return null;
}
}
void On$$anonymous$$ouseOver()
{
// count all opened menues
highlighted = true;
// End On$$anonymous$$ouseOver
}
void On$$anonymous$$ouseExit()
{
highlighted = false;
}
}
Try adding Debug.Log(Vector3.Distance(recievedItem.transform.position, transform.position));
before the while statement. Analyse what is going on. What are the values printed in that Debug.Log?
Answer by CesarNascimento · Jan 19, 2017 at 06:53 PM
Ah now I see. You're using Lerp incorrectly. While using it, both the StartPosition and EndPosition should stay the same, only t should change. See http://wiki.unity3d.com/index.php?title=MoveObject and http://answers.unity3d.com/questions/14288/can-someone-explain-how-using-timedeltatime-as-t-i.html as examples.
In your case I'd use Vector3.MoveTowards, unless you absolutely needs to use Lerp. Something like this
IEnumerator move_item()
{
float speed = 5f;
float step = Time.deltaTime * speed;
while(Vector3.Distance(recievedItem.transform.position, transform.position) > 0.01f)
{
recievedItem.transform.position = Vector3.MoveTowards(recievedItem.transform.position, transform.position, step);
yield return null;
}
}
Same problem with that function. There must be something else, but I can't see what. Is something missing in the IEnumerator code? I never fully grasped it beyond it being a function that could run in the background.
When I click the take button the item moves a few pics right, and stops.
That's weird. Do as @Erethan said and log the values of both positions and the step.
Both functions can be use but have different curves along the process. If you want a Lerp effect, you can use Vector3.Lerp. If you want a constant velocity, use $$anonymous$$oveTowards. However, the problem is not likely to be related to that.
Absolutely. Both methods should be working fine.
Weird. Okay, I did the log. The while loop never fires once, despite the condition being fine. The first log, before while, is a distance of 4.
IEnumerator move_item()
{
float speed = 5f;
float step = Time.deltaTime * speed;
Debug.Log ("Before While: " + Vector3.Distance(recievedItem.transform.position, transform.position));
while(Vector3.Distance(recievedItem.transform.position, transform.position) > 0.01f)
{
recievedItem.transform.position = Vector3.$$anonymous$$oveTowards(recievedItem.transform.position, transform.position, step);
yield return null;
Debug.Log ("After While: " + Vector3.Distance(recievedItem.transform.position, transform.position));
}
}
Both functions can be use but have different curves along the process.
I have to nitpick and say the curve part is not true... Both of the functions just calculate a position based on the parameters you put in.
The "curve" either one gives only depends on the parameters you feed in. $$anonymous$$any people use Lerp "the wrong way" a = Lerp(a , b, x);
, which does give an effect that i guess you mean by "the Lerp effect" but that never returns the value of b
(unless x == 1)
You get the same effect with $$anonymous$$oveTowards if you change the math to do the same thing
var distance = (b-a).magnitude;
var moveAmount = distance * x;
a = Vector3.$$anonymous$$oveTowards(a, b, moveAmount);
// Is the same as
a = Vector3.Lerp(a, b, x);
// Both move vector a 'x' percent of the way closer to b.
Your answer
Follow this Question
Related Questions
object's children not moving with it when using a Lerp-ing coroutine 0 Answers
Smooth damp the lowpass frequency in coroutine: value only changing in 1 frame 1 Answer
[HELP] How to make camera smooth change position while follow object? 1 Answer
If statement not being fullfilled until GameObject inspected in inspector. 0 Answers