#coroutine
1 messages · Page 1 of 1 (latest)
made a thread
so here's the code again
IEnumerator RunForTime(float duration) {
float endTime = Time.time + duration;
while (Time.time < endTime) {
transform.position += Vector3.up * Time.deltaTime;
}
}
We're missing the yield return null; line here.
That is very important.
oh right
Coroutines aren't really "special". I used to think they were actually running in parallel or something
They don't. They run exactly like any other method.
because it doesn't return a waitforseconds
The only exception is that you can yield to pause the method
and then Unity can resume it later
This will run forever and freeze your game.
Time.time only increases when Unity gets to the next frame
what does "yield" do?
yield is a C# keyword. It's used in a method that returns IEnumerator.
C# does a little bit of magic when you write a method that returns IEnumerator
you can't actually "pause" a method like this in C#
that's not a thing
but what you can do is make a little class that remembers all of the local variables
and remembers where you were
that's what the IEnumerator winds up being!
i have a question
An IEnumerator is a thing that can give you values when you ask for them
foreach (Transform child in transform) {
Debug.Log("My child is named: " + child.name);
}
you use enumerators whenever you use foreach
can i for example use something like this:
startingTime=time.Time
coroutine...
endingTime =time.Time
When you yield return something, the enumerator produces a new value
and pauses until you ask for another value
public IEnumerator<int> GiveMeInts() {
yield return 1;
yield return 2;
yield return 3;
}
foreach (var num in GiveMeInts()) {
Debug.Log(num):
}
and in the coroutine use something like
while (endingTime-startingTime < 5f)
This would log
1
2
3
You would probably just write
my c# knowledge of classes is a bit bad
while (Time.time - startingTime)
i don't really know exactly what this looks like either :p
it's not too important
gotcha
so, vitally
if you never yield return inside that while loop
the enumerator never finishes
Time.time only goes up when you get to the next frame
If you yield return null; inside a coroutine, Unity will resume your method on the next frame
you can also do stuff like yield return new WaitForSeconds(1f); to ask Unity to resume your method in one second
void FixedUpdate()
{
if (!isInCoRoutine)
{
StartCoroutine(MoveForSecond());
}
}
IEnumerator MoveForSecond()
{
isInCoRoutine = true;
rb.velocity = new Vector3(xSpeed, 0, 0);
yield return new WaitForSeconds(timeCoRoutine);
rb.velocity = Vector3.zero;
RotateEnemy();
isInCoRoutine =false;
}
so, to fix this, i have to use time.Time and a variable for the starting point?
gotcha
Actually, this looks okay to me
There's a very important difference between your code and mine
My code is updating the position every frame.
Your code is setting the rigidbody's velocity.
Once you set that velocity, Unity's physics system will move the rigidbody every physics update.
but it makes it move, then it stops, flips, wait for time and then repeat
i can send you a video
What do you want it to do instead?
make it move for 5 seconds, then flip and move in the opposite direction
is the problem that the rigidbody is slowing down and stopping?
so that it has a constant loop of movement
Your code should make it move for timeCoRoutine seconds, rotate, and then immediately start moving again
okay, your problem is that the rigidbody is slowing down
i guess
If you want to constantly set its velocity, you can write a loop like this that sets the velocity every frame
can't i make the friction 0?
Sure, that would work
it also may have drag
void FixedUpdate()
{
if (!isInCoRoutine)
{
StartCoroutine(MoveForSecond());
}
}
IEnumerator MoveForSecond()
{
while (Time.time < startingTime + timeCoRoutine)
{
startingTime = Time.time
isInCoRoutine = true;
rb.velocity = Vector3.zero;
RotateEnemy();
isInCoRoutine = false;
yield return null;
}
}
can this work?
i forgot to set startingTime
does it now?
no wait, stuff that should be outside the while loop are inside it
yes, the loop should only contain the thing that makes the enemy move
you're also setting the enemy velocity to zero right now
void FixedUpdate()
{
if (!isInCoRoutine)
{
StartCoroutine(MoveForSecond());
}
}
IEnumerator MoveForSecond()
{
isInCoRoutine = true;
startingTime = Time.time;
while (Time.time < startingTime + timeCoRoutine)
{
rb.velocity = new Vector3(xSpeed, 0, 0);
}
RotateEnemy();
isInCoRoutine = false;
yield return null;
}
void RotateEnemy()
{
transform.Rotate(0,180,0);
}
}
fixed it (i hope so)
Looks reasonable. You're just missing the thing to set the velocity to 0 at the end
but if you immediately set the velocity again, I guess that doesn't matter
also, this wouldn't make the enemy move back and forth
i removed it bc i didn't get what use it had
unless you're changing xSpeed somewhere else
why? shouldn't the enemy flip?
the velocity of a rigidbody is in world space
people told me that by flipping it, it works
it doesn't matter what the rotation of the object is
the enemy will always move in the world +X direction
you could use rb.velocity = transform.forward to make the enemy move in whatever direction is "forward" for the enemy
ok
the blue arrow is forward here
You might want transform.right instead, if the red arrow is the way the enemy is supposed to move
they are moving in the x axis
the game is taking 4 minutes to load, is it normal?
it has always taken 10 seconds or so
if it gets stuck, you can kill the editor and reopen it
i did it, but i was afraid i would have lost the code, so i copied it
i didnt lose anything
it's still stuck
i wonder wether that's something related to the code
by "stuck" do you mean the editor is frozen after trying to play the game?
while (Time.time < startingTime + timeCoRoutine)
{
rb.velocity = new Vector3(xSpeed, 0, 0);
}
it's trying to load it
what's wrong here?
Time.time doesn't change during the loop?
right, because you forgot something
yield return null
yield return Time.time?
no
it has to return something
idk
ðŸ˜
it's so complex
remember that yield return null tells Unity to resume the method one frame later
and you want to do this every frame
while (Time.time < startingTime + timeCoRoutine)
{
rb.velocity = new Vector3(xSpeed, 0, 0);
yield return null;
}
that's all you need
you set the velocity, then you pause the coroutine until the next frame
but you said that yield return null skips a frame
you do that over and over until Time.time is large enough
no, it does not skip a frame
if I'm in frame 6, the next frame is frame 7
and how does the coroutine stop?
after the while loop the isInCoRoutine is false, so it can start another coroutine, does that mean the coroutine is ended?
the coroutine ends when the method ends
once you leave the while loop, your method does some more work and then exits
ok
i have still the same issue as yesterday btw
the enemy gameObject doesn't flip
i tried with transform.Rotate, with rb.moverotate and rb.rotate but idk i don't get it
oh wait
no, nothing
to flip it i need to rotate it on the y axis, that's what i'm doing
you need to set the rotation of the rigidbody
rb.rotation *= Quaterion.AngleAxis(180, Vector3.up);
this will work
AngleAxis creates a rotation by that many degrees around a specific axis
Multiplying two quaternions combines their rotations
it cannot translate by unityengine.quaternions to system.numerics.quaternion
whatever that means
you have a bad using directive up top
there's a "Quaternion" class in System.Numerics
but this has nothing to do with Unity's Quaternion
get rid of using System.Numerics;
but there isn't a system.numerics there
show me your entire script
oh wait
yeah
done
so this should work?
maybe i got the issue
it flips, but it still goes on that direction
maybe during the coroutine, before flipping it, making its speed *= -1
are you still using rb.velocity = new Vector3(xSpeed, 0, 0);
if so, change that
rb.velocity = Vector3.right*xSpeed;
that's always going to go right
this is what i am using
Vector3.right is a constant. It's a vector pointing in the +X direction
oh and i have to rotate the object
transform.right varies. It's whatever direction is "right" for the transform
No, you don't need to do any more rotating. You just need to use the correct direction.
by using transform.forward it goes on the z
rb.velocity = transform.right * xSpeed; would make the enemy move in whatever direction is "right" for it
you mean transform.forward ?
nope
Vector3.forward will always move you into the screen
i mistook
personally, I would rotate the enemy 90 degrees around the Y axis, so that its forward vector is pointing in the direction it wants to move
now i put there transform.forward
the blue arrow here
make sure you're on "local" mode when checking this
i am on local
okay, so select the enemy and rotate it so that its blue arrow points the way it should move
then set rb.velocity = transform.forward * speed;
rb.velocity = transform.forward*xSpeed;