Changing animations?

Godot Version

4.2.2

Question

Now, I have the code for the player pasted below. The problem with the code is that the ladder climbing animations will not play it sits at the first frame and stays there, and I can’t understand why. I don’t have much understanding of the way to set and change animations as well as the physics involved. I just can’t seem to wrap my mind around it - it’s like I need to separate all of them out but don’t see how. I tried to set it like my Unity code years ago - but, I’d forgtten just about all of it and got totally corrupted. I also want to add wall climbing as well and that is going to introduce more problems unless I get this sorted first.

I know the code is all over the place just like my mind so don’t laugh too much. Ok here it is:


#now using TileMap node! in Game node
#tiles need a physics layer to hold up the hero
func _physics_process(delta):
	#-- on spike----------------------------
	if (hero_sprite.animation=="hit" and hero_sprite.is_playing() ):
		return;
	else:
		onSpike = false;
		#print("... onSpike over");
	#---------------------------------------
	
	if(!on_ladder):
		ladder_up=false;
	
	##--  ladder code  ---------------------------------
	##cannot play animations at all here ##
	## assumption because of the physics below
	## don't know how to rectify that ##
	## physics works in that it stops sliding down ladder
	## and going up and down works however - no animation
	if(on_ladder):
		print(on_ladder)
		hero_sprite.play("on_ladder")
		if(Input.is_action_pressed("UP") ):
			##going up
			ladder_up=true;
			print("ladder up")
			##hero_sprite.play("climb_up")
			velocity.y = -100;
		elif(Input.is_action_pressed("DOWN") ):
			##going down
			velocity.y = 100;
		else: 
			velocity.y = -16.3;
	##-------------------------------------------------
	
	
	# Add the gravity.
	if not is_on_floor():
		velocity.y += gravity * delta;		
	#set jumpcount to zero
	if(is_on_floor() ):
		jumpCount = 0;
		
	# Handle jump.
	#handle doublue jump
	#if Input.is_action_just_pressed("jump") and is_on_floor():
	if Input.is_action_just_pressed("jump") and jumpCount < numJumps:
		#jump_sfx.play();
		
		#redirect to MediaManager - cool
		MediaManager.play_track("jump");
		##[some other code]
		velocity.y = JUMP_VELOCITY;
		jumpCount += 1;
		

	# Get the input direction and handle the movement/deceleration.
	# As good practice, you should replace UI actions with custom gameplay actions.
	var direction = Input.get_axis("move_left", "move_right")
	
	#get direction
	#if direction > 0 then we are going right
	#if direction < 0 then we are going left
	if direction > 0:
		hero_sprite.flip_h = false;
	elif direction < 0:
		hero_sprite.flip_h = true;
		
		
	#play correct animations
	#hopefully
	###this might be the case of the sprite animation problem
	if is_on_floor():
		if direction == 0:
			hero_sprite.play("idle");
		elif (direction !=0):
			hero_sprite.play("Run");
	else:
		hero_sprite.play("jumping");

	##---------------------------------------------------------
	#only way to get sprite animation to play on_ladder
	if(on_ladder):
		## single frame
		hero_sprite.play("on_ladder")
		if(ladder_up):
			#animation won't play only first frame# 
			print("going up")
			hero_sprite.play("going_up")
	##-----------------------------------------------------------
		

	##control speed
	##normal movement no ice
	if(!on_ice):
		if direction:
			velocity.x = direction * SPEED
		else:
			velocity.x = move_toward(velocity.x, 0, SPEED)
	
	##on Ice movement
	if(on_ice):
		if direction:
			velocity.x = move_toward(velocity.x, direction*SPEED, acceleration*delta)
		else:
			velocity.x = move_toward(velocity.x, 0, deceleration * delta)
	
	move_and_slide()
#-----------------------------------------------------------------------------------
#-----------------------------------------------------------------------------------

Now, any help to get everything together and extensible when I get to possible implementing wall jumping here is the biggest THANKYOU I can give.

I tried cleaning up the language in the comments - please forgive me if there is still some there.

Warmest Regards.

Hmm I think it is because you have played the ladder animation and jumping animation together, to fix it try to do this:

if !on_ladder: # means if on_ladder is false
	if is_on_floor():
		if direction == 0:
			hero_sprite.play("idle");
		elif (direction !=0):
			hero_sprite.play("Run");
	else:
		hero_sprite.play("jumping");

Do same to all animations before you have played any other like:

if(on_ladder):
	## single frame
	
	if(ladder_up):
		#animation won't play only first frame# 
		print("going up")
		hero_sprite.play("going_up")
    else:
        hero_sprite.play("on_ladder")

Damn,

I really miss the use of braces makes thing so much more readable. I actually found a hard copy of the code I used in that Unity game, looking at it now it’s really complicated, like using a Rayast to find a ladder, like what was I thinking, and having everything separated to make some semblance of sense.

Back to the topic at hand, I am trying it what you suggested right now, I will report back as soon as I have finished :pray:.

Regards.

Ok, I tried what you suggested and the on_ladder animation actually played (so progress), I thought wow this is going to work, however the other 2 animations underneath that:

  • climb_up
  • climb_down

both failed to play using only the first frame. Here is climb_up animation:

	##---------------------------------------------------------
	#only way to get sprite animation to play on_ladder
	if(on_ladder):
		## single frame
		hero_sprite.play("on_ladder")
		if(ladder_up):
			#animation won't play only first frame# 
			print("going up")
			hero_sprite.play("going_up")
		elif(ladder_down):
			hero_sprite.play("climb_down")
	##-----------------------------------------------------------

It might be because on_ladder variable is still true, but the inner “if” should override that. But I don’t know. I’ll try adding an “and/&&” to see what happens. I’ve also found that sometimes the first play animations won’t play all animation that are in the game only some of them - can’t figure out why. Like, idle won’t play or run!

I don’t know what to do!?!

Just do like that:

	if(on_ladder):
		if(ladder_up):
			print("going up")
			hero_sprite.play("going_up")
		elif(ladder_down):
                        print("going_up")
			hero_sprite.play("climb_down")
        else:
            print("idling_on_ladder")
            hero_sprite.play("on_ladder")

Your codes is wrong because first you have started the on_ladder animation then started going_up animation and in the next frame of the process function, it playing the on_ladder animation again so that going_up animation stopped after a single frame. This topic is similar like this. It is a common mistake :sweat_smile:

Oh no, it can’t be that simple! Oh boy, I really stuffed up on that coding. I am so embarrassed :flushed:.

1 Like

Right, so I copied the code and put it in the project ala:

if(on_ladder):
		if(ladder_up):
			print("going up")
			hero_sprite.play("climb_up")
			#playClimbUpAnim();
		elif(ladder_down):
			print("going down")
			hero_sprite.play("climb_down")
		else:
			print("idling_on_ladder")
			hero_sprite.play("on_ladder")

and it ended up with the same result, only the idling animation on the ladder would play.

I think it’s like you were hinting at - it’s probably because as I have hit the “up” button, it goes to play the animation, but, before it can play it, the “Up” is still being pressed so it tries to play it again and when it’s released it can play the idling animation without being interfered with by a button press/release.

Now, what I want can be done, I did it in Unity, just don’t know how to do it yet in Godot a much freer environment.

Please show the full codes

You want me to post the whole code for the Character2D?

1 Like

Yes, I want that

Okey dokey, here is is it’s not that much different for what I posted in the original post. But they ARE some differences. The last function playClimbUpAnim() is not used:

#access to sprite
@onready var hero_sprite = $AnimatedSprite2D

#access to the UI elements?!?
@onready var num_jump = $"../UI/CanvasLayer/numJumpUI4"
@onready var power_up = $"../UI/CanvasLayer/PowerUpsUI"
@onready var ui = $"../UI"
@onready var currHealth = $"../UI/CanvasLayer/numJumpUI4"
@onready var maxHealth = $"../UI/CanvasLayer/PowerUpsUI"

## access the sound manager
#that code didn't word

#-----------------------------
#Player Health				--
#-----------------------------
#variable to control health bar on the UI.
var MAX_Health:	 float = 100;
var CURR_Health: float = 100;

#changes made
#const SPEED = 300.0
#const JUMP_VELOCITY = -400.0
const SPEED = 130.0				#slower
const JUMP_VELOCITY = -300.0	#less height

# Get the gravity from the project settings to be synced with RigidBody nodes.
var gravity = ProjectSettings.get_setting("physics/2d/default_gravity")

#access the jump sound???  Not used anymore
@onready var jump_sfx = $JumpSFX

#--
var onSpike: bool = false;
#--

# var to pick up bomb
var canPickUp = true;
#---------------------

var numJumps;	#maximum number of jumps
var powerUps;	#boolean value

var jumpCount;

#now creating a var (bool???) to know if hero
#is "on" a ladder initally set to false
var on_ladder : bool	= false;
var ladder_up : bool	= false;
var ladder_down : bool	= false;

#var to keep track of hero is on ice
var on_ice: bool = false
#var to set 'friction'
var acceleration = 100;
var deceleration = 100;
var friction: float = 0.1

var direction: float
#----------------------------------------------------------------


func _ready():
	initialize();
	#pass # Replace with function body.

#used StaticBody2D w/ CollisionShape2D - world boundary
#now removed


#now using TileMap node! in Game node
#tiles need a physics layer to hold up the hero
func _physics_process(delta):
	#-- on spike----------------------------
	if (hero_sprite.animation=="hit" and hero_sprite.is_playing() ):
		return;
	else:
		onSpike = false;
		#print("... onSpike over");
	#---------------------------------------
	
	if(!on_ladder):
		ladder_up=false;
		ladder_down=false;
	
	##--  ladder code  ---------------------------------
	##cannot play animations at all here ##
	## assumption because of the physics below
	## don't know how to rectify that ##
	## physics works in that it stops sliding down ladder
	## and going up and down works however - no animation
	if(on_ladder):
		##print(on_ladder)
		hero_sprite.play("on_ladder")
		if(Input.is_action_pressed("UP") ):
			##going up
			ladder_up	= true;
			ladder_down = false
			##print("ladder up")
			#hero_sprite.play("climb_up")
			#up speed
			velocity.y = -90;
		elif(Input.is_action_pressed("DOWN") ):
			##going down
			ladder_up	= false;
			ladder_down	= true;
			velocity.y = 90;
		else: 
			velocity.y = -16.3;
			ladder_down = false;
			ladder_up	= false;
	##-------------------------------------------------
	
	
	# Add the gravity.
	if not is_on_floor():
		velocity.y += gravity * delta;		
	#set jumpcount to zero
	if(is_on_floor() ):
		jumpCount = 0;
		
	# Handle jump.
	#handle doublue jump
	#if Input.is_action_just_pressed("jump") and is_on_floor():
	if Input.is_action_just_pressed("jump") and jumpCount < numJumps:
		#jump_sfx.play();
		
		#redirect to MediaManager - cool
		MediaManager.play_track("jump");
		##[some other code]
		velocity.y = JUMP_VELOCITY;
		jumpCount += 1;
		

	# Get the input direction and handle the movement/deceleration.
	# As good practice, you should replace UI actions with custom gameplay actions.
	var direction = Input.get_axis("move_left", "move_right")
	
	#get direction
	#if direction > 0 then we are going right
	#if direction < 0 then we are going left
	if direction > 0:
		hero_sprite.flip_h = false;
	elif direction < 0:
		hero_sprite.flip_h = true;
		
		
	#play correct animations
	#hopefully
	###this might be the case of the sprite animation problem
	##  GD King - adding one line here  **
	if(! on_ladder):  #if false
		if is_on_floor():
			if direction == 0:
				hero_sprite.play("idle");
			elif (direction !=0):
				hero_sprite.play("Run");
		else:
			hero_sprite.play("jumping");

	##---------------------------------------------------------
	#only way to get sprite animation to play on_ladder
	if(on_ladder):
		if(ladder_up):
			print("going up")
			hero_sprite.play("climb_up")
			#playClimbUpAnim();
		elif(ladder_down):
			print("going down")
			hero_sprite.play("climb_down")
		else:
			print("idling_on_ladder")
			hero_sprite.play("on_ladder")
	##-----------------------------------------------------------
		

	##control speed
	##normal movement no ice
	if(!on_ice):
		if direction:
			velocity.x = direction * SPEED
		else:
			velocity.x = move_toward(velocity.x, 0, SPEED)
	
	##on Ice movement
	if(on_ice):
		if direction:
			velocity.x = move_toward(velocity.x, direction*SPEED, acceleration*delta)
		else:
			velocity.x = move_toward(velocity.x, 0, deceleration * delta)
	
	move_and_slide()
#-----------------------------------------------------------------------------------
#-----------------------------------------------------------------------------------



func initialize():
	numJumps = 1;
	powerUps = false ;
	print("NumJumps: " + str(numJumps) );
	print("Powerups: " + str(powerUps) );
	updateUI();



#function to call updateUI with a function here
#can't seem to just adjust the values themselves in in UI
#which I find strange
#then the function in ui.updateUI get the return values of the var
#and get them from here
#like I said wierd, unweidly but I got nothing
#hard coded the path to UI with onready seems to work?!?
func updateUI():
	#add i to jump when powerup achieved
	#yes this is bad programming practice but then again this whole game is
	#powerUps=true;
	if (powerUps==true):
		hero_sprite.scale = Vector2(1.1, 1.1);
		numJumps=2;
	num_jump.text=str(numJumps);
	power_up.text=str(powerUps);
	#ui.power_ups_ui.text	= str(numJumps);	#var numJumps;
	#ui.num_jump_ui_4.text 	= str(powerUps);	#var powerUps
	#call to upDateUI in the node UI
	#ui.updateUI();
	#pass



func setNumJumpsinUI():
	return numJumps;

func setPowerUpsinUI():
	return powerUps;
	

#remove player CURR_health by amount passed to function
#from where I can't remember
func removeHealth(remove):
	##remove=10;
	CURR_Health -= remove;
	#CURR_Health -= remove;
	print("Current Health: "+str(CURR_Health));
	
	#send value to UI ??
	#access directly - rather than using a function
	#in UI - I suppose I could do that too but this is easier
	#UPdate Bar
	ui.progress_bar.value = (CURR_Health/MAX_Health)*100;
	if (CURR_Health <= 0):
		print("... You are dead")
		



#ladder set function
func setLadder(TFvalue):
	on_ladder = TFvalue;
	
#ladder set function
func setIce(TFvalue):
	on_ice = TFvalue;


#play the hit animation
func playHitAnamation():
	hero_sprite.play("hit");
	
	
func playClimbUpAnim():
	print("Climb up")
	hero_sprite.play("climb_up");
1 Like

Remove this line, [hero_sprite.play(“on_ladder”)] from:

if(on_ladder):
		##print(on_ladder)
		#hero_sprite.play("on_ladder") #Remove this Line *****
		if(Input.is_action_pressed("UP") ):
			##going up
			ladder_up	= true;
			ladder_down = false
			##print("ladder up")
			#hero_sprite.play("climb_up")
			#up speed
			velocity.y = -90;
		elif(Input.is_action_pressed("DOWN") ):
			##going down
			ladder_up	= false;
			ladder_down	= true;
			velocity.y = 90;
		else: 
			velocity.y = -16.3;
			ladder_down = false;
			ladder_up	= false;

Then tell me what happens

I’ll be damned that bloody worked :rofl:. I don’t even remember putting that code in.

I can’t thankyou enough for this I have been working for a week trying to see the problem. And you find it in no time flat.

You sir are a bonafide genius :sunglasses:.

1 Like