Has anyone had problem like this?
Notice input Dir

Whenever i land with character, it rotates in 3.14 direction for some reason..
Doesnt happen when i switch from walk/run/idle only when i switch from midair to landed.
My code is not complex, it just in many files.. and i cant find why does it rotate when landed..
What my statemachine does, is this..
Idle > jump
idle.gd
extends State
@onready var player: Player = get_parent().get_parent()
@onready var debug_ui: DebugUI = $"../../DebugUI"
var slow_down_acceleration:float = 20
var custom_blend:float = 0.5
var animation_speed_scale := 1.0
func enter(_previous_state:State=null) -> void:
previous_state = _previous_state
player.anim_player.speed_scale = animation_speed_scale
player.anim_player.play("Idle_90",custom_blend)
func physics_update(delta:float) ->void:
if player.input_dir != Vector2.ZERO:
state_machine.change_state("walk")
if player.is_crouching:
state_machine.change_state("crouch")
if player.velocity.length() >= 0.01:
player.move(0,slow_down_acceleration,delta)
if player.jump_request:
state_machine.change_state("jump")
player.jump_request = false
player.move_and_slide()
jump.dg
extends State
@onready var player: Player = get_parent().get_parent()
@onready var debug_ui: DebugUI = $"../../DebugUI"
var slow_down_acceleration:float = 20
var custom_blend:float = 0.1
var custom_speed:float = 2.0
var animation_speed_scale := 0.6
func enter(_previous_state:State=null) -> void:
previous_state = _previous_state
debug_ui.add_label("jump")
player.anim_player.play("JumpAscend_9_G",custom_blend,custom_speed)
player.anim_player.animation_finished.connect(animation_done)
player.anim_player.speed_scale = animation_speed_scale
func physics_update(delta:float) ->void:
debug_ui.update_label("jump","Jump: %s / %s" % [player.anim_player.current_animation_length,player.anim_player.current_animation_position] )
player.move(player.speed,player.acceleration,delta)
player.move_and_slide()
func animation_done(animation_name:String=""):
if animation_name != "":
print("animation done: by signal")
else:
print("animation done: by anim track")
player.velocity.y = player.jump_velocity
player.anim_player.animation_finished.disconnect(animation_done)
state_machine.change_state("jumpmidair", self)
midair.gd
extends State
@onready var player: Player = get_parent().get_parent()
@onready var debug_ui: DebugUI = $"../../DebugUI"
var slow_down_acceleration:float = 20
var custom_blend:float = 0.1
var custom_speed:float = 1.0
var animation_speed_scale := 1.0
func enter(_previous_state:State=null) -> void:
previous_state = _previous_state
player.anim_player.play("JumpMidair_66_G",custom_blend,custom_speed)
player.anim_player.speed_scale = animation_speed_scale
func physics_update(delta:float) ->void:
player.move(player.speed,player.acceleration,delta)
player.move_and_slide()
if player.is_on_floor():
state_machine.change_state("jumplanded")
landed.gd
extends State
@onready var player: Player = get_parent().get_parent()
@onready var debug_ui: DebugUI = $"../../DebugUI"
var slow_down_acceleration:float = 20
var custom_blend:float = 0.1
var custom_speed:float = 3.0
var animation_speed_scale := 0.6
func enter(_previous_state:State=null) -> void:
previous_state = _previous_state
player.anim_player.play("JumpLanded_13_G",custom_blend,custom_speed)
print("Jump landed Start")
player.anim_player.animation_finished.connect(animation_done)
player.anim_player.speed_scale = animation_speed_scale
func physics_update(_delta:float) ->void:
player.move_and_slide()
func animation_done(animation_name:String=""):
if animation_name != "":
print("animation done: by signal")
else:
print("animation done: by anim track")
player.anim_player.animation_finished.disconnect(animation_done)
print("Jump landed finished")
if player.input_dir == Vector2.ZERO and player.is_sprinting == false and !player.is_midair:
state_machine.change_state("idle")
if player.input_dir != Vector2.ZERO and !player.is_midair:
state_machine.change_state("walk")
if player.is_sprinting and !player.is_midair:
state_machine.change_state("run")
if player.is_crouching and !player.is_midair:
state_machine.change_state("crouch")
and here is walk state
walk.gd
extends State
@onready var player: Player = get_parent().get_parent()
@onready var debug_ui: DebugUI = $"../../DebugUI"
var custom_blend:float = 0.2
var char_speed :float = 1.4
var frames_for_one_step := 16
var animation_fps := 30
var step_travel_length := 0.82
var animation_speed_for_unit :=0.0
var animation_speed_scale := 1.0
func enter(_previous_state:State=null) -> void:
previous_state = _previous_state
player.anim_player.speed_scale = animation_speed_scale
player.speed = char_speed
player.anim_player.play("Walking_32_G",custom_blend)
func physics_update(delta:float) ->void:
animation_speed_for_unit = (step_travel_length / frames_for_one_step) * animation_fps
animation_speed_scale = player.velocity.length() / animation_speed_for_unit
player.anim_player.speed_scale = animation_speed_scale
if player.input_dir == Vector2.ZERO and player.is_sprinting == false:
state_machine.change_state("idle")
if player.is_sprinting:
state_machine.change_state("run")
if player.is_crouching:
state_machine.change_state("crouch")
if player.jump_request:
state_machine.change_state("jump")
player.jump_request = false
player.move(player.speed,player.acceleration,delta)
player.move_and_slide()
Node tree

statemachine.gd
extends Node
class_name StateMachine
@export var inital_state:State
@onready var debug_ui: DebugUI = $"../DebugUI"
var current_state:State
var states: Dictionary[String,State]={}
func _ready() -> void:
debug_ui.add_label("statemachine")
for child in get_children():
if child is State:
child.state_machine = self
states[child.name.to_lower()] = child
print("State machine loaded: ",states.size())
if inital_state:
print("State: [", inital_state.name,"] loaded")
inital_state.enter()
current_state = inital_state
func _process(delta: float) -> void:
if current_state:
current_state.update(delta)
func _physics_process(delta: float) -> void:
if current_state:
current_state.physics_update(delta)
func change_state(new_state_name:String, previous_state:State=null)->void:
var new_state: State = states.get(new_state_name.to_lower())
assert(new_state,"State not found: " + new_state_name)
if current_state:
current_state.exit()
new_state.enter(previous_state)
debug_ui.update_label("statemachine", "State: " + new_state_name.to_lower(),true)
current_state = new_state
player.gd
extends CharacterBody3D
class_name Player
@onready var player_camera: PlayerCamera = $PlayerCamera
@onready var coyote_timer: Timer = $CoyoteTimer
@export var anim_player:AnimationPlayer
@onready var debug_ui: DebugUI = $DebugUI
var jump_velocity = 9
var coyote_time = 0.15
var jump_count: int = 0
var max_jump_count = 2
var is_sprinting = false
#--------- NEW ----------
var input_dir :Vector2
var direction :Vector3
var speed = 1.0
#var sprint_speed = 4.1
var acceleration = 3.0
var fps: float
var is_crouching = false
var is_ascending = false
var is_falling = false
var is_midair = false
var jump_request = false
var right_foot_down = true
signal set_foot_down
func _unhandled_input(_event: InputEvent) -> void:
input_Action_watcher()
func _ready() -> void:
#DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_DISABLED)
#Engine.physics_ticks_per_second=32
coyote_timer.one_shot = true
coyote_timer.wait_time = coyote_time
debug_ui.add_label("velocity")
debug_ui.add_label("inputdir")
debug_ui.add_label("rotation_y")
debug_ui.add_label("button_sprint")
debug_ui.add_label("is_ascending")
debug_ui.add_label("is_falling")
debug_ui.add_label("is_midair")
debug_ui.add_label("right_foot_down")
debug_ui.add_label("current_animation")
debug_ui.add_label("animation_position")
debug_ui.add_label("jump_request")
func _physics_process(delta: float) -> void:
# Add the gravity.
is_falling = velocity.y < 0 and !is_on_floor()
is_ascending = velocity.y > 0 and !is_on_floor()
debug_ui.update_label("is_falling","Falling: %s" % is_falling)
debug_ui.update_label("is_ascending","Ascending: %s" % is_ascending)
debug_ui.update_label("current_animation","Current animation: " + anim_player.current_animation)
debug_ui.update_label("jump_request","Jump request: %s" % jump_request)
debug_ui.update_label("animation_position","Current animation pos: %.4f" % anim_player.current_animation_position)
if not is_on_floor():
velocity += get_gravity() * delta
is_midair = true
else:
is_midair = false
debug_ui.update_label("is_midair","Midair: %s" % is_midair)
# Handle jump.
if Input.is_action_just_pressed("action_jump") and (is_on_floor() || (!coyote_timer.is_stopped() || jump_count < max_jump_count ) ):
#velocity.y = jump_velocity
jump_count +=1
jump_request = true
print("Jump button: ")
input_dir = Input.get_vector("action_move_left", "action_move_right", "action_move_forward", "action_move_backward")
direction = (player_camera.transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
rotation.y=lerp_angle(rotation.y,atan2(-velocity.x,-velocity.z),0.2)
# DEBUG VALUES ON SCREEN
var vel = "Velocity len: %.2f" % velocity.length()
debug_ui.update_label("velocity",vel)
var inpt_dir_string = "Input dir: %.2v" % input_dir
debug_ui.update_label("inputdir",inpt_dir_string)
var rotation_y_string = "Input dir: %.2v" % rotation
debug_ui.update_label("rotation_y",rotation_y_string)
var was_on_floor = is_on_floor()
if was_on_floor && !is_on_floor():
coyote_timer.start()
if is_on_floor() and jump_count !=0:
jump_count = 0
#jump_request = false
func input_Action_watcher():
character_states()
func character_states():
if Input.is_action_just_pressed("action_sprint"):
is_sprinting = true
debug_ui.update_label("button_sprint","Sprint: On")
if Input.is_action_just_released("action_sprint"):
is_sprinting = false
debug_ui.update_label("button_sprint","Sprint: Off")
if Input.is_action_just_pressed("action_crouch"):
is_crouching = true
debug_ui.update_label("button_sprint","Crouch: On")
if Input.is_action_just_released("action_crouch"):
is_crouching = false
debug_ui.update_label("button_sprint","Crouch: Off")
func move(move_speed:float, move_acc:float, delta:float) -> void:
velocity.x = lerp(velocity.x,direction.x * move_speed,delta * move_acc)
velocity.z = lerp(velocity.z,direction.z * move_speed,delta * move_acc)
func set_foot(_foot:String):
match _foot:
"right":
right_foot_down = true
"left":
right_foot_down = false
#right_foot_down = !right_foot_down
set_foot_down.emit(right_foot_down)
if right_foot_down:
debug_ui.update_label("right_foot_down","Foot down: Right")
else:
debug_ui.update_label("right_foot_down","Foot down: Left")
Maybe yaal can see what im missing here..