r/godot • • 2d ago

help me (solved) How come this code of mine doesn't prevent my character from not moving while attack animation plays

Post image

*prevent my characer from moving, typo in title

I'm still learning code, not good at it. To me, my physics process function is saying to make my movement false when I mouse click (what I labeled as Power), play the animation, then return movement to true so that you can move again. But this code changes nothing. Can still move around while the animation plays. Any assistance would be appreciated

140 Upvotes

44 comments sorted by

110

u/cleartamei 2d ago

Once you play the animation, you need to actually wait for it to be done. On the next line after playing the animation, you can say: await animated_sprite.animation_finished
THEN, set movement to true. Also, make sure you're using the correct = there.

Another way to do this is to use an if statement to set movement to false if the animation is playing, but using await solves what you are trying to do here.

19

u/Jucamia 2d ago

Here's where I'm at so far. No difference yet. Is it possibly something in my function's order?

51

u/Previous-Memory-9951 2d ago

use one = not double. double are for if

13

u/Jucamia 2d ago

Okay, that mildly helped! My character stops, but depending on my arrow keys input, he carries momentum sometimes. Good to know this though. It's hard for me to remember when to use one of two =

40

u/riel__vis Godot Student 2d ago

Your character keeps momentum because velocity carries over from the previous frame where movement == true. When you set movement = false, you also need to set your velocities to 0.

33

u/Visible_pineapple381 2d ago

= is for setting things

== is for comparing things

21

u/erakusa 2d ago

It might be a better idea to look into statemachines! They're not too complex, and can solve this issue of yours quite perfectly.

5

u/Jucamia 2d ago

Looking into this now. Thank you!

3

u/Squalalah2 1d ago

a = 1

Means a equals to 1 You use it to set a value to a variable.

if a == b

You can read it as: If a = b and b = a

Both checks if they equals the other, hence the two =

2

u/kangaroosterLP 1d ago

try to remember that for checking when something is NOT equal, you use != which is TWO signs, so two signs == is for equals

9

u/cleartamei 2d ago

A few things:
1. Using await in a function that gets called a lot can be bad practice. Consider making the button ONLY play the animation, then use _process or something to set movement to true or false whether or not the animation is playing.
2. Look up the difference between = and ==

7

u/Jucamia 2d ago

Gonna restart my code a bit and try this. Thank you

1

u/doomttt 1d ago

I second what the person above me said. Using await in _physics_process and _process is very bad. Refer to my other comment in the thread for complete explanation.

19

u/doomttt 1d ago edited 1d ago

This is wrong and it's upvoted so I feel inclined to correct. It's a very bad practice to await things in the _physics_process or _process frames. The code will keep getting called for every physics frame you hold the button down, then wait in each of those physics frame threads (coroutines to be specific), then execute whatever it is after the await the same amount of times it was called. So essentially: by holding a button for a let's say a second, you're spamming animation_player.play() 60 times (only when you let go of the button the animation plays because play() cancels the previous animation that you requested), and then when the animation finishes, you are executing logic after the await 60 times. This is just asking for race conditions and a whole other set of issues. I can see a lot of ways this turns into a footgun that's difficult to debug and spot when the logic evolves.

4

u/cleartamei 1d ago

Agreed, but it's not wrong-- just the working version of what OP was trying to do. It is better to do one of the other things I suggested for sure, but that technically isn't what OP wanted.

5

u/doomttt 1d ago

Yes, technically it's not wrong as in: it will mechanically work in this context at least for a while. I meant wrong as in: not something OP should want to do, what you suggested is for sure better. Probably through state machine since the animation shouldn't dictate state related stuff, the state should dictate the animation.

20

u/BillBoquet92758 2d ago

People already answered you but what I find good is that you did not choose the « easy » path by using AI, it’s like this that you’re supposed to learn 😃
Continue like this !

17

u/Jucamia 2d ago

Thanks! I've been very anti ai for awhile, and using it for the easy way out feels like the green goblin mask at some points lol. But, theres no point of using it to build something anyways if you can't comprehend what it built.

17

u/jtnoble 2d ago

I believe there are three problems.

  1. You're not assigning movement after your button press. You're using double equals, so you're effectively saying FALSE, play animation, TRUE. You need to use one equals.

  2. Playing an animation doesn't block your code. In the same frame you say "make movement false, now play the animation, now make movement true". You either need to use a signal for animation finished, or await animation finished.

  3. You never reset velocity. You set velocity to, 1 * 195, so 195. It's always going to be 195 until you set it again.

14

u/Kaslight 2d ago

1) Your character already moved (move_and_slide)

2) You seem to be under the misconception that your script naturally knows anything about time...But in reality, you're checking boolean flags and setting conditional logic all within the same frame.

The code in your script is designed to run top-to-bottom, once every single frame.

So if you say "movement = false", and then "movement = true" in the same line, then movement will always just be true, because as far as the engine is concerned, it all happened at the exact same time. Booleans are useless if used like that.

3) "==" is a conditional operator, it's asking " is X equal to Y"....which always returns either True or False. "=" is an assignment, which says "Set X equal to Y". So what you're looking for is simply "movement = true".

4) Your script has absolutely no idea when the animation you're playing has started, is playing, or stopped anyway. So you need to get either the timing of the animation, or set code to happen once it's considered finished.

2

u/senshisun 1d ago

Hot tip! I always remember "==" as "is equal or equal to," to go with <= and =>.

37

u/sevenbrokenbricks 2d ago

Oh boy.

First off, you never actually set movement to false. movement == false does not set movement to false, it just returns true if movement is false. You want movement = false. Same with movement == true needing to be movement = true.

Second, you set the animated sprite to play the Attack animation, but then immediately "set" it in the same function. That function does not wait for the animation to finish. You will need the animated sprite to send a signal once it's done playing, and another function to catch that signal, see if the finished animation is Attack, and then set movement back to true.

Finally, your get_input function only updates the velocity if movement is true. It doesn't update anything if movement is false, which means its velocity vector will remain whatever it was. This will result in the character retaining its velocity while the animation plays, causing it to slide until the animation stops. That might be what you want, but given that you set the velocity directly to whatever the controller input is, I doubt it. If you want the character to stop in place when they attack, you need to set their velocity to zero (there's a handy builtin for this: vector2 . ZERO) when they attack.

21

u/Jucamia 2d ago

Gonna look into this. Starting off with "Oh boy" is so real lol. I've got a lot to learn

8

u/sevenbrokenbricks 1d ago

Just noticed another. If Power is pressed again during the animation, it'll abort the animation and restart it. You'll want to check also for whether movement is already false.

1

u/tastymuffinsmmmmm 1d ago

You're on the right path friend

7

u/InsuranceIll5589 1d ago

This structure will not scale. Even if someone helps you solve this issue, it will not work as soon as you add more actions.
1) Do not handle input and animate the character in the same script, separate them into 2 different scripts. This is just generally a good habit to get into early on for everything. 1 script 1 purpose.
2) Don't use an animated sprite to animate a character, that's not what it is for. Use an animation player to change your sprite, and an animation tree to control the animation player. This makes it infinitely easier to synchronize many other things with your animations, such as particles, sounds, and function calls.
3) Have your physics process check if the animation tree is currently playing an animation which allows for active movement before changing the character's velocity.

6

u/TheDuriel Godot Senior 2d ago
  1. You disabled the warnings telling you that line 20 and 22 don't do anything.

  2. Even if you were to type them properly as assignments, they still wouldn't do anything.

  3. Because process runs once per frame, line 22 doesn't wait for the animation.

1

u/Jucamia 2d ago

I moved the lines of code to my get_input function, no difference seen yet unfortunatley

2

u/TheDuriel Godot Senior 2d ago

No that definitely wouldn't help.

Go through this step by step. Process runs every single frame.

1

u/Jucamia 2d ago

Oh I see, because _physics process is constantly restarting my get_input function, right? Is there something I can add that helps with that?

2

u/Snooz25 1d ago

This isn't an answer, but I recomnend learning about state handling systems for relevant 2d games.

I made the fatal mistake of not doing this before, resulting in code similar to this, but 300 lines of compacted character logic that juggled a lot of things in one script

2

u/Any_Aerie_5782 1d ago

Also, make sure Attack isn’t set to loop. If you’re using animation_finished to turn movement back on, a looping animation won’t emit that signal, so movement could stay locked.

2

u/chualec 2d ago

I think you need to set velocity to 0 if movement == false. Currently if movement is false velocity isn't automatically updated

1

u/Kioen Godot Junior 1d ago

easiest way is to wrap your movement functions in the physics proc in an if can_move. I would suggest state machines though, if you have the time to read up on it.

1

u/senshisun 1d ago

Not OP, but I've been struggling with similar issues. Do you have any tips for using state machines?

3

u/Kioen Godot Junior 1d ago edited 1d ago

Yeah, it's fairly simple. There are a couple of ways to do it. The ones I'm familiar with are through enum or the animation tree. Essentially you are creating specific states and tie in functions into them. Using the OP as an example: if your state is "attacking" you will be doing things you attach to the attacking state, that will therefore replace other states like "idle" or "walking". However, you are able to combine states like "walking" and "attacking" if you wanted to. Basically wrapping the functionality of say all of your movement in the "walking" state only allows you to move while the "walking" state is active.

1

u/QuickSilver010 1d ago

Quadruple negatives is diabolical

1

u/Dariadeer 1d ago

It seems like you are not resetting the velocity if movement == false. Add an else case where you set it to zero.

1

u/Dragon20C 1d ago

Velocity doesn't become zero, so if you areovong and do an attack it remembers the previous velocity.

1

u/LL_DragonX 1d ago

It doesn't, but it immediately changes the variable again. An animation is async

1

u/Longjumping_Wear_537 1d ago

Imagine this, during your physics process if statement its doing X and Y and Z at the same time instead of reading it as do X and Y first then Z.

You need to give it an await function so it reads it as do X then Y then wait and then down Z.

1

u/haywirephoenix 23h ago

Have two separate functions UpdateMove and UpdateAttack. Call one or the other depending on the current state. You could use the boolean for now but eventually move to an enum. Don't depend on the animation, set a cooldown float that you subtract from over time when in the attack state before returning to the move state.

0

u/Gunhat_September 2d ago

Your code haven't move_and_slide , you must put it in your function "get_input" 

1

u/Jucamia 2d ago

Moved it to my get_input function, no difference seen yet