Another Animation Question?

Godot Version

4.2.2

Question

I am trying to create animation for when the player is on a wall, I just recently set it the game to deal with animation for a ladder so I tried basically to do the same thing with the walls by using this code:

    ##---------------------------------------------------------
	#the way to get sprite animation to play on the walls?!?
	if(charOnWall):
		if(wall_up):
			print("going up wall");
			hero_sprite.play("wall_up");
		elif(wall_down):
			print("going down wall");
			hero_sprite.play("wall_down");
		else:
			print("idling_on_wall");
			hero_sprite.play("wall_idle");
	##------------------------------------------------------------

I made sure that there is no other wall animations are playing before this code to override what is happening, and all the conditions are being met. That is, if the character is going up on the wall, “going up wall” is printed in the debugger, same with wall down, and if no movement, “idling_on_wall” is printed.

But only the first frame is being played which happens to be the same frame for all three. Actually, can now confirm it is dropping through to the first frame of the idle animation when Idle, and playing the first frame of the other animations.

I really can’t see the problem here, so, all help is greatly appreciated.

Regards.

1 Like

This codes is not enough :sweat_smile:, please show full codes

1 Like

The reason for not showing you the full code is because I don’t want you to have an aneurysm and die of shock. I was hoping that the snippet might be enough to diagnose the problem.

I know this code is all over the place and should be done better, I have seen how it should be done better using states, but, this is my code, done with much hard work, much thinking and much twiddling of thumbs and much tears.

So, please keep that in mind before ripping me a new one.

I’ll post the code later tonight when I am able, and made sure I’ve censored it correctly.

2 Likes
  • Focus on the Snippet: Even without the full code, the snippet you can provide might be enough to identify potential issues. Sometimes a small section can reveal underlying problems.
  • Explain the Problem: If you can describe the specific behavior you’re encountering, that might give clues without needing the complete code.
  • Focus on Solutions: Instead of dwelling on how the code could be better structured, let’s explore potential solutions to the specific problem you’re facing. We can discuss strategies using states or other approaches without needing to see the entire codebase.
  • Be Kind: There’s no need to worry about me getting upset. My goal is to help you improve your code, not judge your process.

As promised full character code below. Also of note I am not responsible for any result in the destruction of any brain matter.

extends CharacterBody2D
#bound to player node

#access to sprite
@onready var hero_sprite = $AnimatedSprite2D

#access to the HUD - 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"

## Raycast 2D
@onready var wallchecker = $Wallchecker


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

#changed vars
#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")

#acess the jump sound???
@onready var jump_sfx = $JumpSFX

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

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

var maxJumps;	#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 new_ice: bool = false
#var to set 'friction'
var acceleration = 100;
var deceleration = 100;
var friction: float = 0.1

var direction : float

#-------------------------------
#Jumping and wall vars
var isJumping : bool = false;
var wallCheck : bool = false;
var wallSlideGravity :int = 100;
var onRock : bool = false;
var onWallAnim: bool = false
#---------------------------
# For wall animations
var charOnWall: bool = false;
var wall_up : bool	= false;
var wall_down: bool = false;
#--------------------------------

#----------------------------------------------------------------


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


#now using TileMap node! in Game node
#tiles need a physics layer to hold up the hero
func _physics_process(delta):
	
	#print (is_on_wall() );
	##print(is_near_wall() );
	#if(on_wall):
	#	print("... it's working ...")
		
	#-- on spike: nothing happens forcing animation to play  -------
	if (hero_sprite.animation=="hit" and hero_sprite.is_playing() ):
		return;
	else:
		onSpike = false;
	#---------------------------------------
	
	if(!on_ladder):
		ladder_up	= false;
		ladder_down	= false;
	
	##--  ladder code  ---------------------------------
	##cannot play animations at all here ##
	## assumption because of the physics below
	## 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")
			#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;
		wallCheck = false;

	# Get the input direction and handle the movement/deceleration.
	# As good practice, you should replace UI actions with custom gameplay actions.
	direction = Input.get_axis("move_left", "move_right") #defined
	
	#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;
		wallchecker.scale.x = 1;
		#wallchecker.cast_to = wallchecker.cast_to.rotated(PI)   #facing right - rotate accordingly
	elif direction < 0:
		hero_sprite.flip_h = true;
		wallchecker.scale.x = -1;
		#wallchecker.cast_to = wallchecker.cast_to.rotated(PI) ; #facing left rotate 180
		
	#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():
			isJumping =	 false;
			charOnWall = false;
			
			if direction == 0:
				hero_sprite.play("idle");
			elif (direction !=0):
				hero_sprite.play("Run");
		else:
			hero_sprite.play("jumping");

	
	##--  wall  --------------------------------------------------
	if Input.is_action_just_pressed("jump") and jumpCount < maxJumps:
			
		#redirect to MediaManager - cool
		MediaManager.play_track("jump");
		##[some other code]
		velocity.y = JUMP_VELOCITY;
		jumpCount += 1;
		isJumping = true;
		
	if( is_near_wall() and isJumping and onRock):
		##print("on_wall: "+str(isJumping)+"  near wall: "+str(is_near_wall()) );
		#print("...near wall...");
		#------------------------
		####  we are on wall  ###
		#------------------------
		velocity.y = 0.0;		#stay stationary or close to it
		charOnWall=true;
		jumpCount = 0;
		
		if(Input.is_action_pressed("jump") and Input.is_action_pressed("move_right") and direction == -1):
			print("true");
			velocity.x=450 * direction;
			velocity.y = JUMP_VELOCITY * .7
		if(Input.is_action_pressed("jump") and Input.is_action_pressed("move_left") and direction == -1):
			print("true");
			velocity.x=450 * -direction;
			velocity.y = JUMP_VELOCITY * .7
		if(Input.is_action_pressed("DOWN")):
			velocity.y = 18;
			wall_down = true;
		if(Input.is_action_pressed("UP")):
			velocity.y = -18;
			wall_up = true
		if(velocity.y == 0):
			wall_up	  = false;
			wall_down = false
		##pass
	#-------------------------------------------------------------

	##--  Wall movement w/ animation  ----------------------------
	#only way to get sprite animation to play on the walls ?!?
	if(charOnWall):
		if(wall_up):
			print("going up wall");
			hero_sprite.play("wall_up");
		elif(wall_down):
			print("going down wall");
			hero_sprite.play("wall_down");
		else:
			print("idling_on_wall");
			hero_sprite.play("wall_idle");
	##--  End Wall  -------------------------------------------

	##---------------------------------------------------------
	#the 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(new_ice == true  && direction<0):
			velocity.x = -50;
			print("New ICE")
			new_ice = false;
		if(new_ice == true  && direction>0):
			velocity.x = 50;
			print("New ICE")
			new_ice = false;
		
		if direction:
			velocity.x = lerpf(velocity.x, SPEED * direction, 1 * delta);
		else:
			velocity.x = lerpf(velocity.x, SPEED * direction, 2 * delta);	
			
	#finally
	move_and_slide()
	
#--  End Physics -------------------------------------------------------------------


#-------------------------------------------------------------------------------
## function implementing raycasting
## called: is_near_wall
func is_near_wall():
	return wallchecker.is_colliding()
	#pass
##-- end is_near_wall  ---------------------------------------------------------


func initialize():
	maxJumps	= 1;
	jumpCount 	= 0;
	
	powerUps = false ;
	print("NumJumps: " + str(maxJumps) );
	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 weird, 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);
		maxJumps=2;
	num_jump.text=str(maxJumps);
	power_up.text=str(powerUps);
	#call to upDateUI in the node UI
	#ui.updateUI();
	#pass



func setNumJumpsinUI():
	return maxJumps;

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 onspike()
#velocity.x doesn't work >:
func playHitAnamation():
	hero_sprite.play("hit");
	if(direction == 1):
		velocity.y = -200
		velocity.x = 200;
	else:
		velocity.y = -200
		velocity.x = -200;
	
	
#not used anymore - it was	
func playClimbUpAnim():
	print("Climb up")
	hero_sprite.play("climb_up");
	
func KillEnemy():
	velocity.y = -200
		
func nearRock(TFvalue):
	onRock = TFvalue;

That’s it, sorry out there to the real programmers that now what they are doing. And doubly sorry for the triple conditionals!?!

Regards.

when you get this, you can easily assume something else is trying to play animation and override the wall up/down/idle animation every frame.

what is the animation playing after the character is on wall?
is it jumping animation?

Sorry for late reply, just checked your reply, so add elif in this codes:

if(charOnWall):
	if(wall_up):
		print("going up wall");
		hero_sprite.play("wall_up");
	elif(wall_down):
		print("going down wall");
		hero_sprite.play("wall_down");
	else:
		print("idling_on_wall");
		hero_sprite.play("wall_idle");

##--  End Wall  -------------------------------------------

	elif(on_ladder): #Here you need to add elif
		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")

Make the CharOnWall to false

if(! on_ladder):  #if false
	if is_on_floor():
	        isJumping = false
		charOnWall = false
			
		if direction == 0:
			hero_sprite.play("idle")
		elif (direction !=0):
			hero_sprite.play("Run")
    else:
        charOnWall = false #Here *****
		hero_sprite.play("jumping")

And make that:

if (!on_ladder) and (!charOnWall): #Here *****
   if is_on_floor():
       isJumping = false;
	   charOnWall = false;
       if direction == 0:
		   hero_sprite.play("idle");
	   elif (direction !=0):
		   hero_sprite.play("Run");
	else:
		hero_sprite.play("jumping");
#......

Lets see if its works, I am not sure it will work

Yeah, I understand it must be trying to play another animation, but, what is it I can’t figure out. Unless, there is a gdscript function to find out what is playing at that exact fraction of a second, I have no idea what it could be.

When the character is on the the wall, in my case charOnWall there are three possible animations “wall-idling”, “wall-up” or “wall-down”, there really isn’t another another possibility, even if I jump off the wall completely it goes into the wall-idling animation as intended before hitting ground and going back into the on_floor animations be that whatever: run, jump, idle.

I did try this adding a line to confirm that the correct animation hero_sprite.animation == “wall_up” is playing ala this:

    ##--  Wall movement w/ animation  ----------------------------
	#only way to get sprite animation to play on the walls ?!?
	if(charOnWall):
		if(wall_up):
			print("going up wall");
			hero_sprite.play("wall_up");
			if(hero_sprite.animation=="wall_up"):
				print("confirm up");
		elif(wall_down):
			print("going down wall");
			hero_sprite.play("wall_down");
		else:
			print("idling_on_wall");
			hero_sprite.play("wall_idle");
	##--  End Wall  -------------------------------------------

It did print out the confirmation message that is/should be playing wall_up when going up.

Does that tell you anything?

Dude, how can you be late! You are helping me, I should be saying thankyou for just bothering to reply, let alone help. Helping on the forum isn’t a paid position.

My goodness you don’t need to apologize!

Right, so here, you want me to indent the code so the ladder component is an “elif”
on the wall component and not separate? Is that correct? Oh dear, I really need to refactor this.

1 Like

Is it working?

Making the changes now!

Almost working what is happening is that after I get off the wall the wall idling animation keeps playing.

Unfortunately it is 1:30 in the AM and have to go to sleepy bo-bo’s having trouble staying awake.

I think that should be fairly straightforward to figure out - operative word being “fairly” :rofl:.

Do you follows my all 3 steps?

Yes, I did follow them.

I’ll get back to it first thing tomorrow!

Ok, if some problems are still there, you can tell me later, I will try to help you

well um, from reading the code i already knew it’s because of that jumping animation is being played for every frame whenever it’s not on the floor and not on ladder. so you should somehow not play the jumping animation when it’s not on the floor and not on ladder while you are doing climbing animation
first thing to check is to put print on here:

put print every if else branch
and it will tell you which one is being accessed all the time when you are on the wall or climbing

Unfortunately, I have changed the codes that I have provided because I have wrongfully made something wrong with the tabs in codes (the 3rd code box) so you can recheck it. I think it will solve your problem

1 Like

I think you have to make sure , if the_player is_on_floor or not is_on_floor by using if,elif or else statements and try to gather them in one function . I ran over the same problem where the game was playing just the frame 0 when i pressed jump . but somehow i fixed it . Like this …

if is_on_floor():
	if is_attacking == false and is_running == false:
		if direction == 0:
			$AnimatedSprite2D.play("Idle")
		else:
			$AnimatedSprite2D.play("walk")
	elif is_attacking == false and is_running == true:
		if direction == 0:
			$AnimatedSprite2D.play("Idle")
		else:
			$AnimatedSprite2D.play("run")
	elif is_attacking == true and is_running == false :
		$AnimatedSprite2D.play("attack")
		velocity.x = 0
	elif is_attacking == true and is_running == true:
		$AnimatedSprite2D.play("run + attack")
elif not is_on_floor():
	if direction == 0:
		$AnimatedSprite2D.play("jump")
	else:
		$AnimatedSprite2D.play("jumpf")
1 Like

As expected, it was extremely easy to fix, but, I cannot figure out why it happened in the first place. There was only one place where the is_on_floor didn’t take into account that the charOnWall needed to be set to false - but, it was accounted for elsewhere. The code needs to be refactored something shocking. Especially seeing as I want to add in one other state where the knight can attack with a sword, but, that might be a step too far. Maybe I need to keep jumping as the attack or a projectile

@KingGD your code looked great, I thought it took in and accounted for every possibility, so, I must say I owe you a extreme amount of gratitude. To put up with my spaghetti code like this and be able to follow it, is really something. I am a martial artist and I’ve been hit, kicked, punched and been thrown around more than I can remember. It unfortunately takes it’s toll on the grey matter.

Thankyou, thankyou, thankyou :man_bowing: :man_bowing: :man_bowing:.

1 Like