How to make a character move in the last recorded direction of an analog stick

Godot Version

<v4.2.2.stable.official [15073afe3]>

Question

Hi, I have been trying to figure out this mechanic for my platformer for days, and can’t quite seem to figure it out. I want to make a character mode where when an action is pressed, the character will move in a straight line in the last recorded direction of the stick. I want the stick to be disabled during this mode, so the player cannot change the direction without letting go of the action. I have a variable mapped to the analog stick vector, but I’m having trouble saving the velocity from the vector when the stick stops sending inputs. Here is my code as of now for this character mode. Currently when the action is pressed, I can move the character in all directions with the stick, but when I let go of the stick the player velocity goes to 0 and stops moving.
any help is much appreciated!

var input_direction := Input.get_vector("left", "right", "up", "down")
	var last_direction = input_direction
	#handles wave mode
	if Input.is_action_pressed("wave") and not is_on_floor():
		if input_direction:
			rotation = input_direction.angle() + 1.55
			velocity = last_direction * wave_speed
		if input_direction.length() <= 0:
			velocity = last_direction * wave_speed

I think that’s because a vector (0,0) doesn’t pass the if input_direction. Since your not moving, input direction is 0,0

I also have a rotation code that works as intended, it uses the input_direction.angle(). Velocity can’t take .angle, but that’s the direction I want the character to move.

Can you just add “and not Input.is_action_pressed(“wave”)” to whatever handles your analog input? Or nest your analog input in an if not Input.is_action_pressed(“wave”) :

I tried but its not very easy in this circumstance. Couldn’t make it work. I’m like a noob. I’m still not sure how to continue the velocity after the stick is disabled. I asked chatgpt, and it kept telling me to make two variables, one mapped to the stick, and one mapped to the to the first variable. Then it had an if statement to disable the stick. It still didn’t work.

It’s hard to help without a clearer idea of what your code structure looks like. Personally, I’d go with one of two options.

First is a state machine, which you can google all kinds of information on. It’s handy for a platformer, and in your case you’d implement a “wavedashing” state and work from there. Solid YT video on what I’m talking about https://www.youtube.com/watch?v=BNU8xNRk_oU

Second would be the following :

const WAVESPEED = 4
var waveDirection

func _on_input_event(viewport, event, shape_idx):
	if event is InputEventJoypadMotion and Input.is_action_pressed("wave") == false:
		# Code for handling analog joypad input goes here
		pass
		
	if event.is_action_just_pressed("wave"):
		# Snapshots the analog stick's vector when 'wave' is first pressed
		waveDirection = Input.get_vector("Left", "Right", "Up", "Down")
	
	if event.is_action_pressed("wave"):
		rotation = waveDirection.angle() + 1.55
		velocity = waveDirection * WAVESPEED

	if event.is_action_just_released("wave"):
		waveDirection = null
		# Code for handling what happens when the player releases 'wave'
		

Using AI i was able to keep the velocity when the input from the stick stopped with this code.
func wave_mode(delta):
var input_direction := Input.get_vector(“left”, “right”, “up”, “down”)

if Input.is_action_pressed("wave") and not is_on_floor():
	if input_direction.length() > 0:
		# Update last_direction when there is input
		last_direction = input_direction.normalized()
		rotation = input_direction.angle() + 1.55
	else:
		# If input_direction.length() <= 0, use the last direction
		input_direction = last_direction

	velocity = input_direction * wave_speed

Now to figure out how to disable the stick without messing anything up. I’m trying to use the just pressed concept you suggested. I’ll work on it more tomorrow.

Make sure to paste your code in a code block. Press the </> button on a new line to create three ticks and paste into that, like so

```
type or paste code here
```

to disable the stick couldn’t you use a boolean variable?

var stick_disabled = true
if Input.is_action_pressed("wave") and not is_on_floor():
	if input_direction.length() > 0 and stick_disabled == false:
		last_direction = input_direction.normalized()
		rotation = input_direction.angle() + 1.55
	else:
		input_direction = last_direction

	velocity = input_direction * wave_speed
1 Like

Thanks for letting me know about the code block.

The boolean variable does disable the stick, but it also kills the velocity and rotation.

(I hope these questions aren’t too dumb, I’m new at this…)

Always good qustions. You are right I see how this would kill the rotation. I believe killing the velocity has to be relevant elsewhere, one thing to consider is as you move to a neutral position on the stick it will reach very close to, but not exactly zero. Perhaps in these small value cases length() returns >0 while normalized() returns (0,0,0).

Regardless I think these changes will be a good next step, using length_squared cuts out a square-root calculation; better to use this where possible for performance and potentitally more accurate values. And separating the and into two ifs so rotation is not cut off.

var stick_disabled = true
if Input.is_action_pressed("wave") and not is_on_floor():
	if input_direction.length_squared() > 0.1:
		if stick_disabled == false:
			last_direction = input_direction.normalized()
		rotation = input_direction.angle() + 1.55
	else:
		input_direction = last_direction

	velocity = input_direction * wave_speed

How does the stick_disabled variable disable the stick inputs?
I tried both of your code snippets, the first one freezes the rotation and velocity to 0, and disables the stick. the second one freezes the velocity unless there is stick input, and the stick isn’t disabled.

Is there a way to stop receiving inputs from the stick via input mapping?

stick_disabled is just an example, you would have to set it to false when/where ever you want to disabled the stick. You could un-map the stick but that seems excessive.

I still can’t quite get it right. The Boolean variable either isn’t working or I’m not doing it right. Seems like it should be simpler than this to disable an input than this.

Finally figured it out! I got the boolean variable to work properly. Here is the code below for any future internet travelers. Thanks to all the people who helped out!

func wave_mode(delta):
	if input_enabled == true:
		input_direction = Input.get_vector("left", "right", "up", "down")
	
		
	if Input.is_action_pressed("wave") and not is_on_floor():
		if input_direction.length_squared() > 0.1:
			# Update last_direction when there is input
			last_direction = input_direction.normalized()
			rotation = input_direction.angle() + 1.55
			input_enabled = false
		else:
			# If input_direction.length() <= 0, use the last direction
			input_direction = last_direction
	
		velocity = input_direction * wave_speed
	else:
			last_direction = input_direction.normalized()
			rotation = 0
			input_enabled = true