[Best way to] Character movement + input handling, animation

Good evening, I was recently working on my character, and I was unsure about the best way to make it work, the best way to implement functional movement. Currently, my code is like this:

extends CharacterBody2D

const SPEED = 100

func _physics_process(delta: float) -> void:
	var input = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
	if input.length() > 0:
		velocity = input * SPEED
	else:
		velocity = velocity.move_toward(Vector2.ZERO, SPEED)
	move_and_slide()


Looking at it, I already feel like it’s waaaaay better than the first version I made.

extends CharacterBody2D

const speed = 50
var current_dir = "none"

var accept_input:bool = true

func _physics_process(delta):
	if (accept_input):
		player_movement(delta)
		move_and_slide()

func player_movement(_delta):
	
	if Input.is_action_pressed("ui_right"):
		current_dir = "right"
		play_anim(1)
		velocity.x = speed
		velocity.y = 0
	elif Input.is_action_pressed("ui_left"):
		current_dir = "left"
		play_anim(1)
		velocity.x = -speed
		velocity.y = 0
	elif Input.is_action_pressed("ui_down"):
		current_dir = "down"
		play_anim(1)
		velocity.y = speed
		velocity.x = 0
	elif Input.is_action_pressed("ui_up"):
		current_dir = "up"
		play_anim(1)
		velocity.y = -speed
		velocity.x = 0
	else:
		play_anim(0)
		velocity.x = 0
		velocity.y = 0
	
	move_and_slide()
	
func play_anim(movement):
	var dir = current_dir
	var anim = $AnimatedSprite2D
	
	if dir == "right":
		anim.flip_h = true
		if movement == 1:
			anim.play("side_walk")
		elif movement == 0:
			anim.play("idle_back")
			
	if dir == "left":
		anim.flip_h = false
		if movement == 1:
			anim.play("side_walk")
		elif movement == 0:
			anim.play("idle_front")
			
	if dir == "up":
		anim.flip_h = true
		if movement == 1:
			anim.play("back_walk")
		elif movement == 0:
			anim.play("idle_back")
			
	if dir == "down":
		anim.flip_h = true
		if movement == 1:
			anim.play("front_walk")
		elif movement == 0:
			anim.play("idle_front")
			


The Yanderedev drama taught me a lot about not using if/else statements for absolutely everything (lol). Well, I don’t need super-code, my character just needs the ability to ‘interact’ with NPCs and the environment (I’m using the ‘Dialogue Manager’ plugin, made by Nathan Hoad) and - obviously - use animations for when it’s standing still or moving in different directions. What’s the best way to do this properly?

You can either use if / else statements (frankly I wouldn’t worry too much about overusing them) to check what direction the player is going in, or you can input the vector into an AnimationTree which will automatically pick the correct animation for the input vector.

1 Like

Looks good to me. I’ll take a look!

1 Like

But what about the rest? Is it good?

You should have a separate de-acceleration constant instead of using speed. Right now, it moves towards zero by 100 per frame, which is too fast. You need to multiple it by delta. Also, it’s recommended that you make your own actions instead of using the built-in UI actions since those were specifically made for UI.

Oh, the reason it’s so fast is that I’m still in the testing phase. I don’t plan on making any speed changes, like running, etc. The idea is to make it look like a NES/SNES game. Do I really need acceleration instead of just a constant speed?

And, how to properly make my own actions in the right way?

It’s your game, if you want acceleration you can have acceleration. If you don’t want it that’s fine too.

To make your own actions, simply open project settings, go to the input map, type in a name, press the + sign, and then press the key you want to assign to that action.

1 Like

Thanks for the clarification! I had mistaken ‘actions’ for something else. AnimationTree seems much more functional, thanks for the tip.

Regarding acceleration, visually speaking, do you think it’s a good idea to have at least a minimum change? As they say here in Brazil, ‘the devil is in the details’.

I don’t know what type of game you’re making. Acceleration makes the character feel floaty and less responsive though.

Oh, in that case it doesn’t sound like a good idea.

But after some testing, it seems like the character moves faster diagonally than in other x & y directions… Is this just a mistake on my part? And if not, is it possible to fix it?

get_vector normalizes the input for you, it shouldn’t move faster diagonally, you can print out the velocity to check if you want to

1 Like

The funniest thing is that it feels like a Mandela Effect. I must have heard about it somewhere, but apparently there’s nothing wrong here.

Thanks for the help, once again!

1 Like

Yeah the normalization thing is a common problem in beginner gamedev, and some people don’t use the get_vector method and end up with the issue

1 Like

Hi, you could use this simple way

@export var velocidad: float = 100.0

func _physics_process(delta):
	var direccion: Vector2 = Input.get_vector("ui_left", "ui_right", "ui_up","ui_down")	
	position += direccion * velocidad * delta
        move_and_slide()

Input.get_vector is already normalized “The vector has its length limited to 1”

This isn’t optimal, you are setting the position directly instead of using velocity, which won’t make physics calculation work correctly.

Im using delta . This variable comming from the physics process and changes when the fps of the game changes too.

Move and slide also uses delta

1 Like

I know this is almost a year old, but wow! This is a really nice movement function.
Consider it translated to C#.

	public override void _PhysicsProcess(double delta)
	{
		Vector3 _velocity = Velocity;
		Vector2 _inputDirection = Input.GetVector("move_forward", "move_back", "move_left", "move_right");

		if (_inputDirection.Length() > 0)
		{
			_velocity.X = Mathf.Clamp(_inputDirection.X * _acceleration * (float)delta, _terminalVelocity * -1, _terminalVelocity);
			_velocity.Z = Mathf.Clamp(_inputDirection.Y * _acceleration * (float)delta, _terminalVelocity * -1, _terminalVelocity);
		}
		/* else
		{ i have no speed constant, since velocity is always changing with acceleration until it reaches terminal, which i probably did wrong.
			_velocity = _velocity.MoveToward(Vector2.Zero, Speed)
		} */

		//i added gravity
		if (!IsOnFloor())
		{
			_velocity.Y -= _gravity * (float)delta;
		}
		Velocity = _velocity;
		MoveAndCollide(Velocity * (float)delta);
	}