- Home /
how to change a value over time in a coroutine ?
hey hey, first of all :i know that this kind of question has been asked many times before. i want to say that i was reading and then trying much to adapt it to my need but i didnt come to a solution.
i have a script in which the y component of transform.eulerangles is changed in an IEnumerator function using there a coroutine.
IEnumerator y_rotation()
{
while (true) // run this forever and ever
{
if (is_attacked == true) // if in attack mode, do rotation logic
{
//yRotation = Mathf.SmoothDamp(0,-90,ref Velocity,transTime);
yRotation = -90.0f;
yield return StartCoroutine(Wait());
yRotation = 90.0f;
yield return StartCoroutine(Wait());
}
yield return null; // wait a single frame to let Unity breath
}
}
which is executed in FixedUpdate :
void FixedUpdate()
{
transform.eulerAngles = new Vector3(0, yRotation, 0);
rb.AddRelativeForce(Vector3.forward * thrust);
rb.velocity = transform.forward * rb.velocity.magnitude;
}
what i want to achiefe is that it takes about 1 second until yRotation = -90
i've tried it with mathf.lerp or mathf.smoothdamp nothing works, i even tried it with a for loop (....i++) but the value is in a while loop ! so my pc went on strike. I'm pretty confused now so i would be thankfully for any help.
i've kept on trying. the only way i got the mathf.lerp to work was to set this in the update funct
yRotation += $$anonymous$$athf.LerpAngle(0.0f, -90.0f, Time.deltaTime);
this way its rotating permantly. so i thought i can fix that problem with declaring another coroutine = left(). but that doesnt really work just changing the value for 1 time. the problem is how to get the time thing like it does in update yRotation += Time.deltatime.
below is my complete script i have so far.
using UnityEngine;
using System.Collections;
public class ExampleClass : $$anonymous$$onoBehaviour
{
public float thrust;
public Rigidbody rb;
public float yRotation = 0.0F;
public bool is_attacked = false;
public float turn_factor;
public float y_left = 0.0f;
public float mytime = 0.0f;
void Start()
{
rb = GetComponent<Rigidbody>();
StartCoroutine(y_rotation());
StartCoroutine(left());
}
IEnumerator Wait()
{
yield return new WaitForSeconds(2);
}
void Update()
{
if (yRotation >= 360.0F)
{
yRotation = 0.0F;
}
if (yRotation <= -360.0F)
{
yRotation = 0.0F;
}
// yRotation += Input.GetAxis("Horizontal");
}
void FixedUpdate()
{
transform.eulerAngles = new Vector3(0, yRotation, 0);
rb.AddRelativeForce(Vector3.forward * thrust);
rb.velocity = transform.forward * rb.velocity.magnitude;
}
IEnumerator left()
{
y_left += $$anonymous$$athf.LerpAngle(0.0f, -90.0f, Time.deltaTime);
yield return new left();
}
IEnumerator y_rotation()
{
while (true) // run this forever and ever
{
if (is_attacked == true) // if in attack mode, do rotation logic
{
//yRotation = -90.0f;
yield return StartCoroutine(left());
yield return StartCoroutine(Wait());
yRotation = 90.0f;
yield return StartCoroutine(Wait());
}
yield return null; // wait a single frame to let Unity breath
}
}
}
Answer by Bunny83 · Dec 02, 2015 at 01:50 PM
If i understand you right you want, while "is_attacked" is true to smoothly pingpong rotate the object between -90 and 90 on the y axis? What's the initial rotation?
One approach would be:
IEnumerator y_rotation()
{
while (true)
{
if (is_attacked)
{
while (yRotation < 90f)
{
yRotation += 90f * Time.deltaTime;
yield return null;
}
while (yRotation > -90f)
{
yRotation -= 90f * Time.deltaTime;
yield return null;
}
}
else
yield return null;
}
}
Note: It's fine when the angle becomes negative, so don't wrap it back to 360 outside of the coroutine or the coroutine can never reach -90. If you rotate the object somewhere else where you want to limit the rotation you might want to wrap it around at -180 and 180. Also you should rotate the object in Update, not in FixedUpdate. Otherwise you will see stuttering.
Another way would be to just use Mathf.PingPong in Update. You would need a second variable if you plan to allow other rotations outside the range of -90 to 90.
float t = 0;
float yRotation = 0;
void Update()
{
if (is_attacked)
{
t += 90f * Time.deltaTime;
yRotation = Mathf.PingPong(t, 180f) - 90f;
}
transform.eulerAngles = new Vector3(0, yRotation, 0);
}
also thx for your reply ! what i want to achiefe is that this npc enemy flies wavy lines (snake like) when if(is_attacked). if not (until nothing else is declared) it should just fly straight forward
yRotation = 0. i guess thats what you mean : the initial rotation?
at the end it shall become part of an enemy AI. it will need a little bit to get through your suggestions, because i want to understand them and not only to copy and paste them.
cu soon :)
just an idea before : if it comes to a nice result being done with this coroutines, i think it would be interesting to set up a random value for waitinseconds() to make the behavior of the enemy not sooo easy to predict for the player!?
i've tried both of them and both are working. seems best for perfomance ( in my case ) is to calculate transformeulerangles still in the fixedupdate.
but i wonder why the turn is now so smooth? for sure i treid that also before : yRotation -= 90f * Time.deltaTime; but that was "stuttering"
is that avoid only by yield return null right after yRot.... ?
once more many thx for your help !
yours
yield return null; will make the coroutine wait one frame at this point. So it behaves just like Update. The loop does one iteration per frame. Time.deltaTime can only be used when you do something every frame since it contains the time between the last two frame. For example if your framerate is 60 frames per second, deltaTime will be 1/60 == 0.01666. If you accumulate the value of deltaTime every frame you will get a value of about 1.0 after 1 second. Since we multiply by 90 degrees we actually accumulate 1.5 degree each frame (==90 0.01666). If you add 1.5 to your value 60 times, you effectively have added 90 (1.5 60 == 90).
FixedUpdate is at no point something to gain performance. In your case it will just produce additional problems and make it less smooth. FixedUpdate should only be used when dealing with continuous forces, physics or accelerated movement. It's actually called from the internal physics loop. It doesn't run at a constant rate. It is just "fixed" to ensure a constant callrate over one second. FixedUpdate runs at the same time Update runs, but sometimes it might simply skip a call or even call it twice in a row to "fix" the time error. $$anonymous$$ovement in FixedUpdate is naturally more jerky than movement done in Update.
that's what i call a real in depth going explanation :) i think i did understand it basically. but the thing with the performance " in my case" was: the movement of this enemy works well in both cases but that the position of a cube which is attached to this enemyship as a child to to be used in my 3d radar wasn't fast enough updated
( stuttering movement ). i had this prob before(but that is another topic):
http://answers.unity3d.com/questions/1101263/line-renderer-jumps-when-start-end-positons-belong.html
i was playing around in the time manager again set the max. allowed time to 1 and it seems this way a can reduce that prob to a $$anonymous$$imum but only when yRot.... is calculated in Fixedupdate. a real mysterious secret of progging in unity for a beginner :)
Answer by Cherno · Dec 02, 2015 at 11:21 AM
Try this, and get rid of those left and wait CoRoutines.
float turnSpeed = 3.33f;
public IEnumerator Turn()
{
while (true) // run this forever and ever
{
if (is_attacked == true) // if in attack mode, do rotation logic
{
yRotation += turnSpeed;
}
yield return null;
}
}
However, it would be far easier to just use Transform.Roate in Update of FixedUpdate to rotate directly.
thx ! i already thought the same . seems it was a basic misunderstanding of $$anonymous$$e that it would be necessary to do this in coroutines. as well as it was hard enough for me to get it. i'm still learning.
Your answer
Follow this Question
Related Questions
Time Manager Class Implementation Like Coroutine in Unity 1 Answer
RPG Action Progress Bar always same speed 1 Answer
FixedUpdate has stopped working 0 Answers
trying to regulate character speed. 1 Answer
Slow update best practice 0 Answers