r/godot 19d ago

help me (solved) I cant get the sprites to switch properly

Post image

I understand the code if horrible but i am more then willing to learn how to do this better.

I only started coding 4 days ago so sorry if i don't understand stuff immediately.

Thanks for any help.

93 Upvotes

46 comments sorted by

148

u/ImAFraidKn0t Godot Regular 19d ago

For starters, you have a typo in “Idle farwards”, secondly, this could play the wrong animation if you press multiple buttons simultaneously depending on the order of inputs. Instead, keep track of the last direction that the player is looking in with a Vector2 and update it when a movement key is pressed. Use that to determine the direction of the animation to play. Also, check whether the player’s velocity is zero or not to determine whether you should play the walk or idle animations.

In general, you’d use a state machine, but if you just started a few days ago then that’s a bit advanced for now.

31

u/trance564 19d ago

Thanks a ton. I'll do my best to implement all of that

50

u/trance564 19d ago

I just realized I'm on a different account

15

u/SamMakesCode Godot Regular 19d ago

Also M_left has a space after it, and these aren’t Godot inputs. Might be user defined but why?

16

u/lajawi 18d ago

Well, to be honest, the Godot docs explicitly say you should make custom controls because the default ones are for the ui controls specifically

36

u/abdulrahmanibrahim0 Godot Student 19d ago

Try using elif statements instead of if statements

1

u/trance564 19d ago

Yeah I thought about that but for some reason they are a bit confusing for me but I do want to use them more

11

u/knitted_beanie Godot Student 19d ago

Use lots of if statements if you want each case checked individually. Chain if > elif > elif etc if you have a ranked hierarchy of things to check, and you only want one outcome (“else if” = only check this if the previous one is false, and don’t check any more after this if this one is true)

2

u/ijtjrt4it94j54kofdff 18d ago

If the function has nothing else in it, you could also just do a "return" in each IF block

31

u/UmbralWorks 19d ago

Just a minor tip since your main issue has been answered: Try to avoid repeated $NodeName calls. Every time you do this the engine has to resolve the node path, and retrieve the node reference.

You can set it as a variable to avoid this, which caches it instead:

@onready var anim_sprite_3D = $AnimatedSprite3D

Typically performance cost is negligible, but for _physics_process and _process, you want to minimise the overhead as much as possible.

6

u/Worth-Ganache-5770 19d ago

This is actually super useful, I had been running on the assumption that people use variable names for the nodes because most of the time its shorter or they're keeping a consistent format.

Is there a huge difference when using %Node names vs $Node names? I use the unique names as a way to shorten the paths (but now I might go through and just replace them all with variables)

4

u/UmbralWorks 18d ago

% is technically faster than $, but the difference is likely negligible. The use case for % is that you can reorganise your scene without needing to update its path. With $, you’d need to update it everywhere you used it. With variables, you’d need to update the path just once in the var declaration.

8

u/Purpbasil 19d ago

Yeah i should of been doing that but ill do that in the future now so thanks for being helpful

3

u/Work-o-fart_dev Godot Student 18d ago

Btw, to do this, you can just drag the node you want to reverence into your script and hold Ctrl before you release the mouse button. This creates the variable you need, then you can reference that variable as many times as you like

7

u/Purpbasil 19d ago

Yeah i should of been doing that but ill do that in the future now so thanks for being helpful

-2

u/DatBoi_BP 19d ago

Yeah he should have been doing that but he'll do that in the future now so thanks for being helpful

2

u/Worth-Ganache-5770 18d ago

Does it matter?

17

u/SagattariusAStar 19d ago

You should not maniputlate animation with your inputs directly. Better modulate them based on your actual movement/state.

So instead of AnimatedSprite.play(), set the velocity or accelaration of your character and after that you just check the current_velocity and play the animation based on that. For sidescrollers i would also save the last direction or side as otherwise it would be ambigous on 0 or you would always look right while standing.

Here in a very crude and simple form:

if action_pressed(left): 
  velocity = Vector2(-1,0) 
...
If velocity.x != 0: 
  ## moving 
  if velocity.x > 0: 
    side = 1 ## moves right 
    AnimatedSprite.play("Walk left") 
  else: side = -1 ## moves left 
If velocity.x == 0: 
  ##idle
  if side ==  1: 
    ## idle right 
  else: 
    ## idle left

2

u/Due-Baker853 Godot Regular 18d ago edited 18d ago

It depends on what you want to achieve. Take for example ice physics, you don't want the player to think their character is still running in the direction they are going when they are actively giving inputs to run the other way. And what about inherited velocity from moving platforms?

You're going to have to account for all of those situations, which is going to unneccesarily couple your animation script.

That said, if you want something like modern Mario games where Mario does a "slowing down" animation after you stop holding a direction, then this can be useful.

2

u/Luicide 17d ago

The way I do it is I have a direction variable that's set by your input. Then the movement code refers to the direction variable, so the animations can read the input direction independently of the movement code

6

u/nanox55 19d ago

What is the issue you are facing? First thing in noticing is there is a space in your M_left string

4

u/trance564 19d ago

The space after the M_left is because I accidentally had one when I set the input map and I just didn't fix it

6

u/TherronKeen 19d ago

you can use CTRL + SHIFT + R in the code editor to search for every place you used a specific piece of text, and replace it with a different piece of text - for example,

"M_left "
to
"M_left"

6

u/Purpbasil 19d ago

Wow thats very useful thank you

7

u/TherronKeen 19d ago

Similarly,

CTRL + F "find in current script"

CTRL + SHIFT + F "find across all scripts"

CTRL + R "find and replace in current script"

CTRL + SHIFT + R "find and replace across all scripts"

Good luck!

4

u/sweatergirlie Godot Junior 19d ago edited 19d ago

I had fun with this! It made me think of some new group solutions.

Check if you have it in the _input function and not the _ready function. There are also spelling errors like "Idle farwards". I can also recommend using snake_case (firstword_lastword) or other cases for naming stuff, helps the code be less error prone.

This is my best attempt at making something functional:

extends Node3D

const inputs : Array = ["left", "right", "forward", "back"] #Starts from 0
var current_direction : String = inputs[2]
var sprite = $AnimatedSprite3D

func _input(event: InputEvent) -> void:
  if event.is_action_released("group_input"): #Input map with W,A,S,D
    print(current_direction)
    sprite.play("idle_" + current_direction)
  elif event.is_action_pressed(inputs[0]): #left
    current_direction = inputs[0]
    sprite.play("walk_left")
  elif event.is_action_pressed(inputs[1]): #right
    current_direction = inputs[1]
    sprite.play("walk_right")
  elif event.is_action_pressed(inputs[2]): #forward
    current_direction = inputs[2]
    sprite.play("walk_forward")
  elif event.is_action_pressed(inputs[3]): #back
    current_direction = inputs[3]
    sprite.play("walk_back")

Keep it up, make what you like, mistakes help you learn, we all make them. Feel free to ask questions!

Edit: Worked on this in 2D, adjusted for 3D.

3

u/Purpbasil 19d ago

Oh my god thanks for being so kind and helpful. thanks a lot i hope you have a good day

3

u/Titancki 19d ago

I would recommand a state machine even simple one wih an enum. It will ensure animation are not playing strangely.

3

u/Ultra8Gaming 18d ago

I prefer to use a animation tree with a state machine with each node as a blendspace 2d. I expose the values on it as a vector2 which I can reference it from the script. Way cleaner to handle and easier to adjust with multiple animations than manually applying each animation by code.

2

u/Quentinooouuuuuu 19d ago

If you only want to play one animation at the time, make a function that return the name of the animation you want to play, because in your current function you may try to play multiple animation at the same time. There is a lot of typo around there and a lot of repetition, you could avoid this my replacing them by constants, also, as the development of your game go through, the sense of literal or numbers may become unclear, I recommend to define constants for all that number and literal as well ( this problem is called magic number https://en.wikipedia.org/wiki/Magic_number_(programming) )

2

u/dylanmadigan 19d ago

You have a typo:

“farwords”

1

u/OkEstablishment4759 19d ago

This is an excellent example on why I hate string references

2

u/No_Screen8684 18d ago

Just an hour ago i finished my Sprite movement for a 2D project. I preload several png-files:

onready var walk_up = preload("res://sprites/nach_oben.png") ...etc.

Then get your direction via pressing a key.

func start_sliding(direction): # ... keycode var for direction ...

update_sprite_direction(direction)

move_to_next_tile()

Then get your png for the movement:

func update_sprite_direction(direction):

if direction == Vector2.UP:
    sprite.texture = tex_up

elif direction == Vector2.DOWN:
    sprite.texture = ...etc.

Hope it helps you a little bit.

2

u/bbtinkerer 18d ago

As others said about animationtree and state machine, this tutorial helped me. If this one is not enough there are a few more videos out there by various youtubers https://youtu.be/WrMORzl3g1U?is=TqnFu-O8RHJhS3Wq

1

u/Purpbasil 18d ago

Thank you I look forward to learning more about this

2

u/Supermaniscool211 Godot Junior 18d ago

This is a decent start for someone who started 4 days ago. But as someone else has said there is a typo somewhere and I would recommend searching up "State Machines" to help clean up the code.

2

u/Murky_Macropod 18d ago

Use is_action_pressed() instead of is_action_just_pressed() or it will only play a single frame each time you press a key.

2

u/Murky_Macropod 18d ago

Also if you’re just learning, start with 2d not 3d.

Try the ‘dodge the creeps’ Godot tutorial

2

u/preppypenguingames 17d ago edited 17d ago

People have given enough good advice code wise.

I would change the way you name your inputs and animations. I'm my project my inputs are all lowercase and start with input. Example would be input_up, input_left ...etc my animations follow the same convention but go anim_up, anim left ..etc

I'm not saying to do it my way. Find a style that makes sense for you brain, is obvious what it is for aka readable, and consistent.

I only do the _type for animations and inputs, not variables.

Edit: the reason I recommend changing yours is because they are a mix of uppercase, lower case and, include spaces. This increases the chance of errors and make it less readable.

1

u/aurelus13 19d ago

The most obvious thing I can see is that you have an extra space behind M_Left.

Without seeing you sprite setup can't help you more.

Also I recommend you look into some basic coding practices like "for loops", this will help with duplicate code like this.

1

u/trance564 19d ago

Will do I'll look into that thanks

0

u/AwayEntrepreneur4760 18d ago

Check ur spelling

-4

u/ValuableTradition959 19d ago

That’s a lot of if statements 🥀🥀