Hey all! Working on a small part of my project and I need an interesting answer that I am having trouble finding. Essentially making a machine building game. I am starting in on the actual machine functionality and starting simple. I need a machine to rotate exactly 90 degrees within a set amount of time, then stop. Going from the 12 o’clock position to the 3 o’clock position (0 degrees to 90 degrees) within 2 seconds, then stop. I can find plenty of code to make a UI object spin, and I can add in a timer but that won’t get me to the exact degrees needed (unless I mess with the time and speed but it always breaks eventually)
Anyone know what lines of code I should be looking at?
Here’s one of the parts of the code where I just get it spinning. Will very likely be moving this code to a coroutine since those are easier for me to think through.
public float rotationTime = 3f; //in seconds
public float rotationSpeed = 0.5f; //tound per second
float timeLeft;
void Update()
{
timeLeft -= Time.deltaTime;
if (timeLeft > 0)
{
transform.Rotate (0, 0, Time.deltaTime * rotationSpeed * 360);
}
else
{
timeLeft = rotationTime;
}
}
The above lerp will “max out” and keep returning Rot2 forever. You may wish to submerge the above in a coroutine if you want to know when it ends, perhaps by a delegate callback.
ALTERNATELY, if you want a dial gauge that can constantly move smoothly towards a target, a target that changes over time, use almost the same construct as this:
Smoothing movement between any two particular values:
Thanks for the suggestions! I’ll have to test which I like best in a bit. Thankfully I am working on a simple square grid so I don’t have to worry about moving objects too much, just the rotation of the machines. I’ll give them a go!
I am trying the code you have listed, but Unity crashes when I hit play, I can’t see where this code would lock up unity, but I also can’t find anything else that would cause the crash.
public class Spinner : MonoBehaviour
{
private float time;
private float timeInterval = 1.0f;
private float rot1 = 0.0f;
private float rot2 = 90.0f;
void Start()
{
StartCoroutine (TurnForward ());
}
public IEnumerator TurnForward()
{
while (true)
{
time += Time.deltaTime;
float fraction = time / timeInterval;
float angle = Mathf.Lerp (rot1, rot2, fraction);
transform.rotation = Quaternion.Euler (0, 0, angle);
yield return null;
}
StartCoroutine (Open ());
}
public IEnumerator Open()
{
yield return new WaitForSeconds (1);
StartCoroutine (TurnBackward ());
}
public IEnumerator TurnBackward()
{
while (true)
{
time += Time.deltaTime;
float fraction = time / timeInterval;
float angle = Mathf.Lerp (rot2, rot1, fraction);
transform.rotation = Quaternion.Euler (0, 0, angle);
yield return null;
}
StartCoroutine (Close ());
}
public IEnumerator Close()
{
yield return new WaitForSeconds (1);
StartCoroutine (TurnForward ());
}
}
Here’s what I have right now, seems like it should all work just fine for now. My last question is how can I run the Open/Close coroutines when the TurnForward/TurnBackward coroutines finish?
Coroutines like that get real awkward real quickly when you start trying to chain them on.
Really the only way to debug them is MASSIVE amounts of debug.log statements to show you exactly what is running, and even then it can be fragile and sensitive to a single frame of timing difference in some cases.
You might want to consider more of a state machine that tracks and progresses changes in open/close and/or facing direction.
That way whatever the priority is (open close or turn around) would operate until it is satisfied, then the other would operate. The “smoothly move” thing at the bottom of my first post above can be very helpful here.
Alternately, if this is just going to happen mindlessly forever, just delete all your code and make an animation!!
Hm that is a good point, maybe coroutines aren’t the best way to go about this. I’l look into either animations or state machines. I’m more familiar with state machines, but since these things will be just mindlessly looping forever, animations might not be a bad way to go. I’ll look into those for better replacements!
While Kurt is a coroutine hater, and nothing over the years I’ve said has ever managed to dissuade him, I think they’re significantly better than traditional state machines. They ARE state machines afterall. The ability to easily chain linear sequencing without ridiculous amount of boilerplate code is divine. My entire game, from top to bottom starting from the main menu all the way to the game over is done with coroutines.
The problem with your solution right now is that your coroutines never actually finish, so of course it’s hard to keep track of their state. Here’s a solution that’s more streamlined:
private const float duration = 1.0f;
private const float rot1 = 0.0f;
private const float rot2 = 90.0f;
void Start()
{
StartCoroutine(Sequence());
}
public IEnumerator Sequence()
{
yield return StartCoroutine(Turn(rot1, rot2));
yield return StartCoroutine(Open());
yield return StartCoroutine(Turn(rot2, rot1));
yield return StartCoroutine(Close());
StartCoroutine(Sequence());
}
public IEnumerator Turn(float a, float b)
{
float time = 0f;
while(time < duration)
{
time += Time.deltaTime;
transform.rotation = Quaterion.Euler(0, 0, Mathf.Lerp(a, b, time / duration));
yield return null;
}
}
public IEnumerator Open()
{
yield return new WaitForSeconds(1);
}
public IEnumerator Close()
{
yield return new WaitForSeconds(1);
}
I used parameters for your Turn, so you don’t need to copy and paste code, any time you find yourself doing that you should think to yourself “how can I not do this”. The entire “state machine” is now found within the Sequence coroutine, which runs all of the other sequences in turn. I assume your Open and Close will have more logic to them, so I left them as is, even though right now they’re kind of pointless.
I love you Grozz… that is a slight mischaracterization however.
I just think that a lot of problems out there have highly-rated Youtube videos suggesting coroutines and that often isn’t the best solution, that’s all.
Look, I love coroutines! Here are some of my favorite projects:
Total count: 31
kurtina:atgm kurt$ grp -c StartCoroutine \*.cs
Total count: 46
kurtina:flight kurt$ grp -c StartCoroutine \*.cs
Total count: 42[/code]```
That’s some advanced coroutine writing there! Well from my perspective lol. But also really good to know! I didn’t know you could write them out like they are in the Sequence() function. That is pretty cool! And yes the Open() and Close() functions will eventually have more code, but baby steps for me!
Now I have a “devil and angel on my shoulder” situation XD I guess I’ll try both methods and see which I like better.