How to fix this 1 frame hiccup on wall sliding

Hey everyone!

I’m running into an issue where after leaving a wall after performing a wall side, my character still maintains the wall slide animation for what seems like a single frame. I’ve been at this for a few days and am running out of ideas on how to fix it.

if (!this.onGround) console.log(this.hero.anims.getName())

There is one piece of data I stumbled upon while trying to determine the source of this issue that may be of some importance. When I implement the console log written above (which spits out the name of the animation thats play when the character isn’t on the ground), when I jump I still get a single log of the “idle” animation, which is under strict logic to only play when the player is on the ground.

This makes me think that when the velocity is updated by a key press, the player.body still registers being blocked by the relevant collision for a fraction of a second (I.E. the ground when jumping or the wall when moving the opposite direction).

Here is my entire update function code block:

	update() {
		this.speed = 100
		this.jumpSpeed = -110
		this.onGround = this.hero.body.blocked.down

		if (this.hero.body.blocked.right || this.hero.body.blocked.left) {
			this.onWall = true
		} else {
			this.onWall = false
		}

		if (!this.onGround) console.log(this.hero.anims.getName())

		if (this.keyA.isDown) {
			// going left
			this.hero.setVelocityX(-this.speed)

			this.hero.body.offset.x = 33
			this.hero.scaleX = -1
			if (this.onGround) {
				this.hero.play("hero-run", true)
			} else if (
				!this.fallAnimationPlayed &&
				this.hero.body.velocity.y > 1 &&
				!this.onWall
			) {
				this.hero.play("hero-fall")
				this.fallAnimationPlayed = true
			}
		} else if (this.keyD.isDown) {
			//going right
			this.hero.setVelocityX(this.speed)
			this.hero.body.offset.x = 21
			this.hero.scaleX = 1
			if (this.onGround) {
				this.hero.play("hero-run", true)
			} else if (
				!this.fallAnimationPlayed &&
				this.hero.body.velocity.y > 1 &&
				!this.onWall
			) {
				this.hero.play("hero-fall")
				this.fallAnimationPlayed = true
			}
		} else if (!this.onGround && !this.onWall) {
			// what animations to play if no collision detected
			if (this.hero.body.velocity.y < 0) this.hero.play("hero-jump")
			else {
				if (!this.fallAnimationPlayed) {
					this.hero.play("hero-fall")
					this.fallAnimationPlayed = true
				}
			}
		} else {
			this.hero.setVelocityX(0)
			if (this.hero.anims.getName() === "hero-land" && this.onGround) {
				this.hero.playAfterRepeat("hero-idle")
			} else {
				if (this.onGround) this.hero.play("hero-idle", true)
			}
		}
		if (this.onGround && this.fallAnimationPlayed) {
			this.fallAnimationPlayed = false
			this.hero.play("hero-land")
		}

		if (this.hero.body.velocity.y < 0) {
			this.hero.play("hero-jump")
		} else if (
			this.hero.body.velocity.y > 0 &&
			!this.onGround &&
			!this.onWall &&
			!this.fallAnimationPlayed
		) {
			this.hero.play("hero-fall")
			this.fallAnimationPlayed = true
		} else if (this.hero.body.velocity.y > 1 && this.onWall) {
			this.hero.play("hero-wallSlide", true)
			this.hero.setVelocityY(20)
		}

		// Hold jump to increase height mechanics
		if (this.keySpace.isDown) {
			if (this.onGround && this.jumpTimer === 0) {
				// jump is allowed to start
				this.jumpTimer = 1
				this.hero.setVelocityY(this.jumpSpeed)
			} else if (this.jumpTimer > 0 && this.jumpTimer < 28) {
				// keep jumping higher
				this.jumpTimer++
				this.hero.setVelocityY(this.jumpSpeed + this.jumpTimer * 2)
			}
		} else {
			// jump button not being pressed, reset jump timer
			this.jumpTimer = 0
		}
	}

I’m very new to Phaser so I apologize if the above code makes your eyes hurt. I’ll attempt to refactor the code once I get an iteration that works.

I appreciate any feedback in resolving this bug, and let me know if any more information is needed.

I think for jumps you want to play with animations immediately, e.g.

if (this.keyA.isDown) {
  // …
  if (this.onGround) {
    this.hero.play("hero-run", true);
  } else if (this.onWall) {
    this.hero.play("hero-fall");
    this.fallAnimationPlayed = true;
  }
}
1 Like

No dice.

	if (
				!this.fallAnimationPlayed &&
				this.hero.body.velocity.y > 1 &&
				!this.onWall
			) {
				this.hero.play("hero-fall")
				this.fallAnimationPlayed = true
			} else if (this.onGround) {
				this.hero.play("hero-run", true)
			}

Moved it up to the top of both left and right controls, and swapped the if statements. Same results as before.

Edit: I see that in your code you provided you also changed the if statement for the fall to check if the player is on the wall as opposed to not. I haven’t tried that approach yet, and upon changing that logic have run into a couple minor bugs involving the wallSlide animation itself. Will update when I get them fixed.

After spending an hour working towards your suggestion, and absolutely littering my code with console logs, I had a hunch and managed to find a solution.

if (!this.onWall) this.hero.scaleX = -1

Wrapped the scaleX modifiers inside my left and right control blocks with an if statement. Not sure why that fixed it when other solutions failed, but after spending so long on this bug, I’ll take it.

Here’s to hoping it doesn’t come up when I implement wall jumping.

Regardless, thank you for your input samme!

I might use flipX instead of negative scale.