X velocity issues

Info:
OS: Arch Linux
Version: 4.2 stable
Language: GDscript

Hello!
Im working on a recoil system for a 2D game im making. You shoot a bullet and it launches you in the opposite direction.
func recoil(strength, delta): var mousepos = get_local_mouse_position() velocity.x = int(-mousepos.normalized().x * strength) velocity.y = int(-mousepos.normalized().y * strength) print(velocity)
My Code.

When I run this, the velocity on the Y axis works fine, but the distance caused by the velocity on the X axis seems to be capped at a certain number. There is no reason for this to be this way, the character script that this is in is just a simple base character script. This effect is only present on the X axis. Reply if you require more information.

the var mousepos = get_local_mouse_position() it is intended to be local_position of mouse rather than the global position?

That is the case, I tried both and local ended up working the best.

i see, but from this code alone shows nothing wrong then, can you show what does print(velocity) printing?

Outputs -750, 0 when pointing directly to the left. This seems to not be a velocity issue, but a problem with something else. Its like movement in the horizontal direction is just suddenly blocked at a point.

if it’s pointing to the left, shouldnt it be recoil to the right? and output 750,0 should be the right one, no? anyway can you show the code of how do you apply the movement from the velocity got here?

Sorry, That was a typo. I meant pointing to the right.

full characterBody code:

extends CharacterBody2D


var SPEED = 600.0

var gravity = 1250

func recoil(strength, delta):
	var mousepos = get_local_mouse_position()
	velocity.x = int(-mousepos.normalized().x * strength)
	velocity.y = int(-mousepos.normalized().y * strength)
	print(velocity)

func _physics_process(delta):
	# Add the gravity.
	if not is_on_floor():
		if velocity.y < 0:
			velocity.y += gravity * 1.5 * delta
		else:
			velocity.y += gravity * delta

	# Get the input direction and handle the movement/deceleration.
	# As good practice, you should replace UI actions with custom gameplay actions.
	var direction = Input.get_axis("left", "right")
	if direction:
		
			
		if velocity.x > 0:
			$AnimatedSprite2D.play("walkR")
		velocity.x = direction * SPEED
	else:
		$AnimatedSprite2D.play("idleR")
		velocity.x = move_toward(velocity.x, 0, SPEED)
	if Input.is_action_just_pressed("freeze"):
		velocity = Vector2(0,0)
		print(velocity)
	
	if Input.is_action_just_pressed("shoot"):
		recoil(get_node("/root/Node2D/SETTINGS/Invis").get_meta("Recoil"),delta)
	move_and_slide()

this one control where the recoil going?, what’s the function code for this? is this called inside the if Input.is_action_just_pressed("shoot"):?

Its the default move_and_slide function on CharacterBody2D. I have no clue the code for it. It is not called in the if statement you mention.

oh i see, then it made simple, put print(velocity) on the func _physics_process(delta):, run and try get recoil and check if the velocity suddenly drop from 750 to 0

I see it. So at least we know what is happening. any idea on how to solve it?

the culprit might be around here,

var direction = Input.get_axis("left", "right")
	if direction:
		
			
		if velocity.x > 0:
			$AnimatedSprite2D.play("walkR")
		velocity.x = direction * SPEED
	else:
		$AnimatedSprite2D.play("idleR")
		velocity.x = move_toward(velocity.x, 0, SPEED)

that made the velocity.x reduce without notice, try remove or comment those line and use shoot?

velocity.x = move_toward(velocity.x, 0, SPEED)

Commented out this line, It fixed the original problem but causes it to never lose momentum.

Delta in move_toward() takes a value between 0 and 1. SPEED is 600. The velocity will be set to 0 any time the player isn’t moving. I’d change it to move_toward(velocity.x, 0, SPEED*delta).

This has been corrected. Do not use.

try reduce the SPEED constant to see if it’s actually slowly decrease

What is the intent of this line? It seems to me like it would be here that you’d do dampening/friction, but you’re using move_toward which does not do that. What this actually means is “change the x velocity to a value up to 600 units closer to zero than the current value”.
So if the current speed is between -600 and 600 it will become zero here.

This is misleading. move_toward does not work like lerp.

1 Like

If you want to gradually stop, you want lerp(velocity.x, 0, 0.1)
Change that 0.1 to a value of linear dampening you want to use.
Or you could use an actual physics force, which would be more stable. Depends on your game.

Here’s the cleanest and simplest way to do this (imho):

  1. Calculate recoil as a vector opposite to direction_to vector to mouse position.
  2. Calculate velocity normally, then simply add this recoil vector to velocity at the end.
  3. Use lerp or move_toward to reduce the recoil vector every frame until it’s zero.

This way you keep your recoil and velocity calculations separate, easier to debug and understand.

var SPEED = 600.0
var gravity = 1250

var recoil: Vector2 = Vector2.ZERO
var recoil_resistance: float = 1 # adjust as needed, this is units per frame

func add_recoil(strength):
	recoil = global_position.direction_to(get_global_mouse_position()).rotated(deg_to_rad(180)) * strength

func _physics_process(delta):
	if Input.is_action_just_pressed("shoot"):
		add_recoil(get_node("/root/Node2D/SETTINGS/Invis").get_meta("Recoil")) # this hard-coded path looks really sketchy btw

	# do your normal velocity calculation without worrying about recoil
	# then just add recoil to the final velocity vector
	velocity += recoil
	recoil.move_toward(Vector2.ZERO, recoil_resistance) # reduce recoil back to zero recoil_resistance worth of units every frame

I wrote this off the top of my head without testing so I hope it works on the first run :sweat_smile:. Cheers!

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.