My character controller sometimes speed up. I haven’t noticed this problem so far if I put everything in the Update. Any idea why my private IEnumerator MoveCoroutine() speed up?
InputActions:
Action Properties
Action Type: Value
Control Type: Vector 2
Binding Properties
Composite Type: 2D Vector
Mode: Digital Normalized
public void Move(Vector2 input)
{
MoveInput = input;// Vector2.ClampMagnitude(input, 1);
if (MoveInput != Vector3.zero)
{
if (IsMoving) return;
IsMoving = true;
StartCoroutine(MoveCoroutine());
}
else
{
IsMoving = false;
}
}
Based on the code sniplets posted i dont see why your movement as a whole would speed up. You are multiplying gravity with Time.deltaTime twice tho. Why use Coroutines in this case anyways? Coroutines are… horrible, really. In 9/10 cases they are detrimental, as they dont offer any major advantages and quickly deteriorate code readability. Get rid of IsMoving, get rid of the Coroutine. You already know how to solve your problem. What speaks against this solution?
The problem with coroutines is many of them can run within the same frame, since they do a whole separate function. So obviously the move script is running twice, or more, each frame.
Like Yoreki states, I personally hate coroutines. I much rather know what is running when, and on what frame. But I’ve seen this issue before, and found the result was a coroutine created many “timed” instances(was user error, to be fair). Either way, I don’t like them.
I have other Coroutines for jump etc. in a special item script. It’s a Zelda style game. IsMoving is also used to test if the character is moving for other actions. As far I know using Update for everything is a bad move. Coroutine is more elegant way. In the situation when I have add/activate more items or actions and attach them as separate scripts I prefer coroutines.
“did you try to set a debug/print for ‘input’? to see what values your code is working with” yes, and I don’t see anything strange.
And you won’t see your speed any different than what it was set. What you’re not seeing is the same coroutine is running twice or more each frame. So true, move speed will still be 2, but if you say “move 2, move 2, move 2” in one frame, you’ll move by 6. ergo, moving faster
It’s very possible that it’s running 2 times because I can’t see any other explanation why this is happening. I have (IsMoving) return; but maybe _controller.Move(_movement * (Speed * Time.deltaTime)); is not ended immediately after IsMoving is set to false.
I will try
_movement = Vector3.zero;
_verticalVelocity = 0;
after while (IsMoving) maybe this solve the issue.
// A class that always exists with Update()
public static int frameCounter;
void Update()
{
frameCounter++;
}
// in problem functions
print($"Player moved {moveSpeed} at frame {class.frameCounter}");
Which I’m sure is archaic, and I’m soon to receive hate mail over it, lol…
but you’ll easily see printed:
“Player moved 1.5 at frame 36”
“Player moved 1.5 at frame 36”
Ok so i dont wanna be that guy, and there is a touch of subjective opinion in this, as always. But…
That’s even worse then.
Why do you think that? Coroutines are worse in pretty much every regard, be it readability, maintainability, debugging, probably even performance (the latter being a non-issue tho). The only argument for Coroutines is if something doesnt need to run every frame. However for easy cases you may aswell implement your own timer mechanic running in Update, and for complex cases i would prefer Update over Coroutines any day, for debugging reasons.
I dont intend this to sound rude, but isnt you needing help debugging this rather simple scenario evidence enough for how Coroutines are harder to reason about? And this is a simple case. Imagine doing something more complex, where you keep the object and start or stop it, while potentially also having it manipulated / created through different sources. Coroutines are fine for odd jobs here and there, or for prototyping. Building your game architecture around them is asking for spaghetti code.
If you insist on using Coroutines i would suggest making sure that only one per task can ever exist. You will still have to deal with an annoying overhead to make sure you handle this Coroutine object properly, ie you need to detect if it still runs, not create a new one if it does, but recreate it if it still exists but stopped. Im not even sure if this description is entirely correct tho, as i simply dont bother with Coroutines. Why anybody would ever want to work that way is beyond me, when Update exists.
I asked this right at the beginning… but why Coroutines? I realise you like them. But why? What advantage do you see with them that makes you insist on using them over Update? Maybe it’s just a misconception that drives you to work this way, in which case im sure we can clear that up.
As much as I hate coroutines, they do have some good places. Like particle effects, or even death animations(if object pooling, and want returned quickly to the pool), and I’m sure there’s at least one other thing… maybe…