I already have a script, but I want the bob to always attempt to lerp to Vector3.ZERO, so it’s basically fighting against itself, like how you would make deceleration and acceleration in a movement system. And same thing once you aren’t touching the floor as well. But I’m not sure how to do that…
I’m really bad at trigonometry btw.
The current code:
class_name Player extends CharacterBody3D
#Refrences
@export_group("Refrences")
@export var head:Node3D
@export var cam:Camera3D
@export var aim:RayCast3D
@export var inventory:Inventory
@export var cam_rig:Node3D
#Stats
@export_category("Speed")
@export var walk_speed:float
@export var sprint_speed:float
@export_category("Jump")
@export var jump_power:float
@export var jump_boost:float
@export_category("Physics")
@export var ground_accelaration:float = 5
@export var ground_decelaration:float = 5
@export var air_control:float=2
@export var gravity:float = ProjectSettings.get_setting("physics/3d/default_gravity")
@export_category("Camera")
@export var bob_freq := 2.5
@export var bob_amp := 0.1
@export var base_FOV:= 80.0
@export var FOV_change := 1.5
@export var sens := 0.1
#Movement
var target_speed:float
@onready var input_dir:Vector2
var dir:Vector3
#Cam Shake
var current_rotation:Vector3
var target_rotation:Vector3
#Cam Shake Settings
var snap:float
var return_speed:float
#Cam Shake Strength
var shake_strength:Vector3
#Keep Track of Sine Wave
var bob_time:float = 0.0
#State Machine
enum states {walk, sprint}
var state:states
#Lock Mouse
func _ready():
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
#Input
func _input(event):
#Jumping
if event:
if event.is_action_pressed("jump") and is_on_floor():
jump()
#Quitting
if event.is_action_pressed("quit"):
get_tree().quit()
#Character Rotation
if event is InputEventMouseMotion:
rotate_y(deg_to_rad(-event.relative.x * sens))
head.rotate_x (deg_to_rad(-event.relative.y * sens))
head.rotation.x = clamp(head.rotation.x,deg_to_rad(-90),deg_to_rad(90))
#Movement
func _physics_process(delta:float) -> void:
#State Machine
match state:
states.walk:
target_speed = walk_speed
states.sprint:
target_speed = sprint_speed
#Add Gravity.
if not is_on_floor():
velocity.y -= gravity * delta
#Handle Sprint.
if Input.is_action_pressed("sprint"):
state = states.sprint
else:
state = states.walk
#Handle Movement Direction
input_dir = Input.get_vector("left", "right", "up", "down")
dir = transform.basis * Vector3(input_dir.x, 0, input_dir.y)
#Accel and Deccel
if is_on_floor():
if dir and velocity.length() < target_speed:
velocity.x = move_toward(velocity.x, dir.x * target_speed, delta * ground_accelaration)
velocity.z = move_toward(velocity.z, dir.z * target_speed, delta * ground_accelaration)
else:
velocity.x = move_toward(velocity.x, dir.x * target_speed, delta * ground_decelaration)
velocity.z = move_toward(velocity.z, dir.z * target_speed, delta * ground_decelaration)
else:
velocity.x = move_toward(velocity.x, dir.x * target_speed, delta * air_control)
velocity.z = move_toward(velocity.z, dir.z * target_speed, delta * air_control)
#Head Bob Process
bob_time += delta * velocity.length()
$"Head/Cam Rig/SpringArm3D".transform.origin = headbob(bob_time)
#FOV
var velocity_clamped = clamp(velocity.length(), 0.5, sprint_speed * 2)
var target_fov = base_FOV + FOV_change * velocity_clamped
cam.fov = lerp(cam.fov, target_fov, delta * 8.0)
#Begin Movement
move_and_slide()
func _process(delta:float) -> void:
target_rotation = target_rotation.slerp(Vector3.ZERO, return_speed * delta)
current_rotation = current_rotation.slerp(target_rotation, snap * delta)
#Set Camera Controllers Rotation
cam_rig.rotation = current_rotation
#Fix Z Shake
if shake_strength.z == 0:
cam_rig.global_rotation.z = 0
#Head Bob Function
func headbob(time:float) -> Vector3:
var length
var pos := Vector3.ZERO
if is_on_floor():
length = min(get_real_velocity().length(), 1.0)
else:
length = 0
pos.y = sin(time * bob_freq) * bob_amp * length
pos.x = cos(time * bob_freq/2) * bob_amp * length
return pos
#Jump Function
func jump():
velocity.y = get_real_velocity().y + jump_power
velocity.x += dir.x * jump_boost
velocity.z += dir.z * jump_boost
At the moment, the second I start slowing down, the bob snaps to Vector.ZERO, the same is true once I go mid air. It’s extremely jarring. I also noticed how jittering it is when I’m walking into walls, although that might be because it has a frequency too high.
I think it is lerping “smoothly” but I want it to kinda keep its previous inertia?
Kinda like it’s fighting against the want to go back to ZERO and keep bobbing.
That’s how head bobbing feels like in every AAA game i’ve played anyways…
I’m in simple term sync the bob to the time/frequency of my movement, this works because your camera and player are synced in movement so by altering the frequency the camera moves we can make it follow the left and right direction of the movement i’'l make a video brb