Player Seemingly Moves in Opposite Direction

Godot Version 4.4.1

Exactly what it says on the tin. I was following along with a GDQuest tutorial video about making a 2D game.

The only difference from the video is that I was using my own sprites instead of the ones provided. Which meant I also needed to add a basic 2D camera to my player node to see my player moving, since it was stuck in the top left corner. However, my player seems to move in the OPPOSITE direction of the key I press.

I checked my key bindings first since I assumed I must have bound them wrong. That wasn’t the issue though, see screenshot below

Here is the code I’m working with. It’s VERY basic which is why I’m confused on why it’s not working as intended. The prints were there for me to test to see what value I was getting for everything. Everything SEEMS like it’s correct (left gives me -1/-100 for direction/velocity, right is 1/100, up is -1/100, and down is 1/100) but my player sprite moves in what seems like the opposite direction. Is this a camera issue?

Please copy and paste the entire CharacterBody2D code here. Put ``` on top and bottom to format it. You aren’t doing anything with the sprites so that doesn’t matter. Your code and inputs look correct, so there’s something else going on.

Maybe if you make the speed var -100, it might fix the issue.

Shouldn’t be the problem though. How do you know that you go in the wrong direction? Maybe you have your animations set up the other way around or something? Happened to me recently ^^
Maybe drop some other sprite into the scene for orientation?

this IS all of my code. i have not coded anything else since i wanted to make sure movement worked first before working on the specific animations. or do you mean a screenshot of the character node itself?

my prints tell me that the direction (left gives me a negative x, right positive x, etc.) and velocity is correct. i even checked speed and that’s correct. the character on the screen seems to slide in the opposite direction though.

for example, i hold my left arrow down. my character on the screen slides to the right instead. the only thing i can think of is that potentially maybe the camera is the thing moving instead, so it appears that the character is moving to the right but it’s actually the camera that’s moving instead.

i’ve checked to make sure that my script is attached to the player node and not any of the child nodes also

i’ll check by dropping another sprite for orientation later when i get home, hopefully that’ll shed some light on the issue

No I meant what I said. I just assumed you had additional code. But the comment about how to add code remains for future reference.

Like I said before, everything looks correct. What you’re seeing is really weird. Try adding

.normalized()

on the end of your direction line.

Sounds like it. Did you change any of the camera’s properties, such as a negative zoom/scale? Showing your scene tree would help the most, maybe you have background elements childed to the player/camera where they shouldn’t be.

1 Like

alright i’ve done some tests and added a very barebones animator code to get visual feedback. updated code below (diagonal if statements are there for my ease of access to list out all directional combos)

extends CharacterBody2D

@export var speed := 100.0 #default speed

func _physics_process(delta: float) -> void:

	var animated_sprite := $PlayerAnimator/AnimatedSprite2D
	
	#get player input
	var direction = Input.get_vector("move_left", "move_right", "move_up", "move_down")
	print(direction)
	print(speed)
	
	velocity = direction * speed #calculate velocity
	print(velocity)
	move_and_slide()	
	
	if velocity.x > 0.0: #moving right
		if velocity.y > 0.0: #moving right and down
			
			pass
		if velocity.y < 0.0: #moving right and up
			
			pass
		else: #just moving right
			animated_sprite.play("walk_right")
			
	if velocity.x < 0.0: #moving left
		if velocity.y > 0.0: #moving left and down
			
			pass
		if velocity.y < 0.0: #moving left and up
			
			pass
		else: #just moving left 
			animated_sprite.play("walk_left")
			
	else: #not moving left or right
		if velocity.y > 0.0: #moving down
			animated_sprite.play("walk_down")
			
		if velocity.y < 0.0: #moving up
			animated_sprite.play("walk_up")
			
		else: #not moving
			animated_sprite.stop()
			pass

when running this as is, the character will face in the right direction but only the left and up animations play properly. the character will face right and down but doesn’t play the animation. the character also still looks like its sliding in the opposite direction of where it’s facing though.

i also tried it with the override camera option. the character becomes fixed to the center of the screen but will still act like the above, just without the sliding.

i tried adding

.normalized()

like you suggested but it did not change the behavior in either mode. it also didn’t change any of the values i get from the prints either.

this is going to sound dumb, but could it be possible i’m testing this wrong? i’ve been using the “run current scene” button in the top right. is that the recommended way to test these things?

1 Like

sorry if this is the wrong image, i’m still learning all the terminology. this is what you mean by scene tree right?

for the camera, the only thing i’ve changed is that i increased the zoom slightly to better see the sprites. otherwise, i havent touched any other properties on it.

1 Like

Yeah that’s the scene tree!

So! you have a Node in between your player and your sprites. This Node “PlayerAnimator” is not a Node2D so it does not have position; this means the Sprite and AnimatedSprite are not following along with the Player since the Node2D child-chain has been broken by a Node.

Change the PlayerAnimator’s type to Node2D and the Sprites will move along with the player.

1 Like

this def fixed some of the bugginess! the character faces the correct direction and the sliding is stopped but the character is now fixed in the center of the screen.

for animation, like i mentioned above, the right and down animation don’t play though the character will turn in the direction. also for sprite2d, am i supposed to set a texture to it? i originally had my sprite sheet set as a texture but it leaves a static copy underneath the animations when they play.

You may not want the Sprite2D if it’s empty.

Potentially, the character is fixed in the center of the screen because you have no other reference, the camera moves with the player at the same time so it looks like no movement.

Your right and down animations do not play because your if/else logic is flawed. This uses an if/else to find which axis the player is mostly moving, using absolute values. Then in each branch further determining which direction in that axis.

if absf(velocity.x) > absf(velocity.y): # moving right or left
    if velocity.x > 0: # moving right
        animated_sprite.play("walk_right")
    else: # moving left
        animated_sprite.play("walk_left")
else: # moving up or down
    if velocity.y > 0: # moving down
        animated_sprite.play("walk_down")
    else: # moving up
        animated_sprite.play("walk_up")
1 Like

wow it’s been a hot minute but i’m back to fiddle around with this! the only problem with this code is that the sprite is constantly moving even when there is no input after it’s given a velocity that is more than 0.

i played around with the code and found that using an else function at the end would interfere with the movement to the right and down and this is what i got to work by specifying an ==0 state. i’m not sure exactly WHY that is so if anyone can explain that be great!

ALSO WOW it really accidentally posted that before i was finished typing -_- also not sure why the code below looks so jank, everything about this post is fighting me OTL

	if absf(velocity.x) > absf(velocity.y): # moving right or left
		if velocity.x > 0: # moving right
			animated_sprite.play("walk_right")
		if velocity.x < 0: # moving left
			animated_sprite.play("walk_left")
		if velocity.x == 0: # not moving
			animated_sprite.stop()
	else: # moving up or down
		if velocity.y > 0: # moving down
			animated_sprite.play("walk_down")
		if velocity.y < 0: # moving up
			animated_sprite.play("walk_up")
		if velocity.y == 0: # not moving
			animated_sprite.stop()

Are you still using this line? Where direction is the input vector? I would recommend against normalizing the input vector, could prevent perfect-zero values.

velocity = direction * speed

ah i am! here is my full code so far. i know someone earlier suggested normalizing it, so what would you recommend instead? all of this vector stuff reminds me of how bad i was at it during geometry and physics @_@

is there a good guide for this anywhere btw? i’ve done a few of the ones listed on the godot assets list but it seems whenever i try to branch off from it, i hit a hurdle of concepts that weren’t properly explained in the tutorial.

extends CharacterBody2D


@export var speed := 100.0 #default speed

func _physics_process(delta: float) -> void:

	var animated_sprite := $PlayerAnimator/AnimatedSprite2D
	
	#get player input
	var direction = Input.get_vector("move_left", "move_right", "move_up", "move_down").normalized()
	
	#print(direction)
	#print(speed)
	
	velocity = direction * speed #calculate velocity
	print(velocity)
	move_and_slide()	
	
	if absf(velocity.x) > absf(velocity.y): # moving right or left
		if velocity.x > 0: # moving right
			animated_sprite.play("walk_right")
		if velocity.x < 0: # moving left
			animated_sprite.play("walk_left")
		if velocity.x == 0: # not moving
			animated_sprite.stop()
	else: # moving up or down
		if velocity.y > 0: # moving down
			animated_sprite.play("walk_down")
		if velocity.y < 0: # moving up
			animated_sprite.play("walk_up")
		if velocity.y == 0: # not moving
			animated_sprite.stop()

I shrimply wouldn’t normalize the vector from Input.get_vector, it is already limited to a normal unit-circle range, instead this reverts some potential control support, such as tilting the movement stick half-way when normalized is always going to be a full-press.

var direction = Input.get_vector("move_left", "move_right", "move_up", "move_down")

that makes sense! though that still doesn’t explain why right and down triggered the not moving state if i use the code below instead?

by this logic, the character should move whenever the vector is greater than or less than 0 but it only moves when less than 0.

extends CharacterBody2D


@export var speed := 100.0 #default speed

func _physics_process(delta: float) -> void:

	var animated_sprite := $PlayerAnimator/AnimatedSprite2D
	
	#get player input
	var direction = Input.get_vector("move_left", "move_right", "move_up", "move_down").normalized()
	
	#print(direction)
	#print(speed)
	
	velocity = direction * speed #calculate velocity
	print(velocity)
	move_and_slide()	
	
	if absf(velocity.x) > absf(velocity.y): # moving right or left
		if velocity.x > 0: # moving right
			animated_sprite.play("walk_right")
		if velocity.x < 0: # moving left
			animated_sprite.play("walk_left")
		else: # not moving
			animated_sprite.stop()
	else: # moving up or down
		if velocity.y > 0: # moving down
			animated_sprite.play("walk_down")
		if velocity.y < 0: # moving up
			animated_sprite.play("walk_up")
		else: # not moving
			animated_sprite.stop()

Rubberduck this piece of code. And remember; else excludes only the last if preceding it, not all ifs. So which statements will execute here if velocity.x is greater than zero?

1 Like

As normalized implies these two snippets are not the same

if velocity.y > 0: # moving down
	animated_sprite.play("walk_down")
if velocity.y < 0: # moving up
	animated_sprite.play("walk_up")
else: # not moving
	animated_sprite.stop()

## Not the same as

if velocity.y > 0: # moving down
	animated_sprite.play("walk_down")
if velocity.y < 0: # moving up
	animated_sprite.play("walk_up")
if velocity.y == 0: # not moving
	animated_sprite.stop()

You’ve updated your code to use if/else for only one branch! because of this the else will trigger if velocity.x >= 0 as that is the opposite of it’s matched if statement. You can use elif to chain multiple if statements together, this guarantees only one branch will execute, where else only executes when none of the if or elifs do.

if velocity.y > 0: # moving down
	animated_sprite.play("walk_down")
elif velocity.y < 0: # moving up
	animated_sprite.play("walk_up")
else: # not moving
	animated_sprite.stop()
2 Likes