Player snaps to starting rotation when in the air. How do I stop this?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By bipolarkitkat

So, I’m making a game in 3D and whenever the player is in the air and I’m not holding one of the direction buttons, the player will always snap to face the same direction it was looking in when the scene loaded. What is causing this and how do I fix it?

Here is the script for controlling the player:

extends KinematicBody

export var speed = 10 
export var jump_strength = 20
export var gravity = 50 
export var controller_sensitivity = 5

var velocity = Vector3.ZERO 
var snap_vector = Vector3.ZERO

onready var spring_arm: SpringArm = $SpringArm 
onready var model: Spatial = $Skin

func _ready(): 	
 Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) 	

func _unhandled_input(event): 	
 if event.is_action_pressed("click"): 		 
  Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) 	 	
 if event.is_action_pressed("toggle_mouse_captured"): 		
  if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED: 			 
   Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) 		
 else: 			
   Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)

func _physics_process(delta): 	
 var move_direction = Vector3.ZERO 	
 move_direction.x = Input.get_action_strength("move_right") - Input.get_action_strength("move_left") 	
 move_direction.z = Input.get_action_strength("move_back") - Input.get_action_strength("move_forward") 	
 move_direction = move_direction.rotated(Vector3.UP, spring_arm.rotation.y).normalized() 	
 velocity.x = move_direction.x * speed 	
 velocity.z = move_direction.z * speed 	
 velocity.y -= gravity * delta
 var just_landed = is_on_floor() and snap_vector == Vector3.ZERO
 var is_jumping = is_on_floor() and Input.is_action_just_pressed("jump")
 if is_jumping:
  velocity.y = jump_strength 
  snap_vector = Vector3.ZERO 	
 elif just_landed: 	
  snap_vector = Vector3.DOWN 	 	

 velocity = move_and_slide_with_snap(velocity, snap_vector, Vector3.UP, true) 	 	

 if velocity.length() > 0.2: 		
  var look_direction = Vector2(velocity.z, velocity.x) 		
  model.rotation.y = look_direction.angle()

func _process(delta): 	
 spring_arm.translation = translation

Maybe this part is the problem? Have you tried moving it above the code for move_and_slide_with_snap()?

if velocity.length() > 0.2:        
  var look_direction = Vector2(velocity.z, velocity.x)      
  model.rotation.y = look_direction.angle()

Ertain | 2022-01-11 00:40

Doing that makes it worse. It causes the snap issue to happen even when on the ground.

bipolarkitkat | 2022-01-11 02:04

Then maybe it’s with these lines? Maybe it would be better (or easier to read) by refactoring the code?

var just_landed = is_on_floor() and snap_vector == Vector3.ZERO
var is_jumping = is_on_floor() and Input.is_action_just_pressed("jump")

Ertain | 2022-01-11 09:37

It’s not with those lines either.

I’ve actually managed to fix the bug with the addition of a few lines of code, but I’d still like to know what caused it in the first place. I’ve tried removing and changing every bit of the code but I still can’t figure out the cause.

bipolarkitkat | 2022-01-11 19:39

:bust_in_silhouette: Reply From: J0hnBoB0n

I set up my rotation exactly like this by following a GDQuest tutorial and had the exact same issue. It seems like something about our jumping process is fighting with our rotation statement. I’m guessing it’s either our velocity.y variable being affected by the jump or it’s our snap_vector being set to Vector3.ZERO. Not sure how or why those would affect it.

Anyways, replacing the if statement for the rotation with the below code seems to fix it:

if Vector2(velocity.z, velocity.x).length() > 0.2:
	var look_direction = Vector2(velocity.z, velocity.x)
	 model.rotation.y = look_direction.angle()

Thanks to the Youtube commenters for figuring this one out. Still not sure why this works, or why it was a problem in the first place, but this solution seems to work out fine.