2D Direction Movement?

Godot Version

4.3

Question

Hi all,

If people recognise my name I am here with another question about a bare bones course game that I am trying to improve. It’s a top-down tank game in which you control a tank and shoot at others. I made some steps toward that just yesterday after many days of struggling basically being able to play the game repeatedly and having a reset button without resorting to the full menu of games everytime you wanted to play – hard to explain. Just a small improvement, but, I learnt a lot. Didn’t get it perfect, not by a long shot, but, a lot of small things came together.

Now the questions revolves around the movement of the game. The way it is structured does my mind in. The Left/Right arrow buttons move the tank forward and backward but based on the rotation of the tank controlled by the up/down buttons. And I can’t have that it’s not intuitive and trying to move away from an incoming missile is just not achievable - not to mention that this would be a great learning opportunity to learn something which I have never done. For instance, if you have the "tank” facing the “NW” and you want to move in that direction you have to hit the right arrow. Not good.

What I am envisioning, is using a joystick namely, the left analog joystick to control both movement and turning together, not separate button presses on the keyboard. So, if you are facing right want to move “SE”, hey, presto chango, the tank starts moving the SE direction and turning until it it hits the direction specified on the joystick. Sounds easy, but, I have no idea how to accomplish that. The turret currently controlled with the mouse will also have to be re-jigged to the right stick, but not right away. I have done it in 3D, but, instead of learning I was basically just told how to do it. Now I want to “LEARN” how to do it in 2D.

So, I don’t want people just giving me code for that – I am here to “learn”, so, I need a tutorial or YouTube vid, or even course showing how to do just that one simple thing. So, do any of you know of anything that will allow me to learn this task or get me pointed in the right direction (pun intended)?

Thankyou and Regards,

If I understand correctly you want the top down tank character to face in the direction of the player’s input? If you use Input.get_vector you can convert the resulting Vector2 into an angle with the .angle function

var input_dir := Input.get_vector("left", "right", "up", "down")
rotation = input_dir.angle()

Of course this will be an instant transition, so maybe you also want to set a maximum turn rate. With a little bit of math you can create a move_toward style function for angles to move at a consistent rate.

I was just about to post saying that I had a character2D using this movement code in a YouTube tutorial:

extends CharacterBody2D

@export var speed = 400;

func get_input():
	var input_direction = Input.get_vector("c_left","c_right","c_up","c_down");
	velocity = input_direction * speed;
	#end

func _physics_process(delta: float) -> void:
	get_input();
	move_and_slide();
	#end

You might have answered the next part of the puzzle about rotation. I have to go offline for a while, but, Ill get back to you and tell you if it worked. Instant or not I am trying to learn the pieces for what I need. So, if I have to move_towards, lerp or whatever that is the NEXT step and I’ll worry about it then.

Cheers :smiling_face_with_sunglasses:.

Ummm, yeah, I tried that code with the rotation, and, ummm yeah, it was pointing in the “correct” rotation, sometimes, it was also sometimes jumping around to the bounds of the playboard, other times jumps outside the playboard entirely.

Definitely a bit of fun, but, not what I had in mind.

I’ll search for something more concrete later,

Cheers, thanks for the response though :grinning_face:. It’s always good to have a bit of a laugh.

Ok, ok, I get what you were meaning earlier … I had to apply the rotation to the Sprite on the tank, my mistake, now I am getting some results. Things are starting to look up :smiling_face_with_sunglasses:.

It’s bed time now but it’s always good to go an a high note!

Cheers.

I made one step of progress on moving a character with the left analog stick with this code:

extends CharacterBody2D

@export var speed: 			float = 100.0;
@export var tank_offset:	float = 90.0

@onready var tank_sprite: 	Sprite2D = $Sprite2D

func _ready() -> void:
	pass
	#end


func get_input():
	var input_direction = Input.get_vector("c_left","c_right","c_up","c_down");
		
	velocity = input_direction * speed;
	tank_sprite.rotation = input_direction.angle() + deg_to_rad(tank_offset);
	print("rotation: "+str(tank_sprite.rotation) );
	#end


func _physics_process(delta: float) -> void:
	get_input();
	move_and_slide();
	#end

What I cannot do however is keep the sprite from rotating back to the “Right” when the controller is released as the analog stick is being continually polled and setting the sprite accordingly. Is there any way to do this? For example, if I had my character facing “NW” and let go off the analog controller it sets the sprite back to the “E”, the default position, with the offset. When I need for it to stay in the “NW” direction. I tried a couple of things but nothing worked.

Does anyone have any idea’s as to what I should try next?

Regards.

You can try like that:

func get_input():
	var input_direction = Input.get_vector("c_left","c_right","c_up","c_down");
	
	velocity = input_direction * speed;
	if input_direction:
		tank_sprite.rotation = input_direction.angle() + deg_to_rad(tank_offset);
		print("rotation: "+str(tank_sprite.rotation) );
	#end
1 Like
func get_input():
	var input_direction = Input.get_vector("c_left","c_right","c_up","c_down");
	
	velocity = input_direction * speed;
	if input_direction:
		tank_sprite.rotation = input_direction.angle() + deg_to_rad(tank_offset);
		print("rotation: "+str(tank_sprite.rotation) );
	#end

I missed it by that much :grinning_face_with_smiling_eyes:.

Brilliant thinking by the way. I don’t think I would’ve ever come up with that solution, in fact i don’t know HOW that actually works (it does work though), because it not a bool or a null value. Just brilliant!!!

It works, because input_direction is a Vector2, so this line

if input_direction:

is essentially the same as this line

if input_direction != Vector2.ZERO:

Therefore, your rotation will be changed only when the directional input is pressed (i.e. the input_direction is not Vector2.ZERO). Otherwise, it will not rotate and keep the same rotation it had (e.g. NW as in your example).
Without this line, you were always passing the Vector2.ZERO into your rotation logic also when no input was pressed, which translates to a default East-facing.

Hope that makes sense :slight_smile:

1 Like

So, that’s how it works! I’ll try and file that away for future reference.

Thankyou so, so much, you don’t know how much of a help that has been.

Beir bua agus beannacht! (Irish for Victory and Blessings to you).

1 Like