Help with Smoothing

Godot Version 4.4

Question

So I made this player Controller similar to the one in Helldivers (2015)

extends CharacterBody3D

const SPEED = 5.0
const JUMP_VELOCITY = 4.5
var rayOrigin = Vector3()
var rayEnd = Vector3()
var isAiming

@onready var camera: Camera3D = $Camera

var aim_direction: Vector3 = Vector3.ZERO

func _physics_process(_delta: float) -> void:
	var input_dir := Input.get_vector("left", "right", "up", "down")
	var direction: Vector3 = (transform.basis.x * input_dir.x + transform.basis.z * input_dir.y).normalized()
	
	
	if direction != Vector3.ZERO:
		velocity.x = direction.x * SPEED
		velocity.z = direction.z * SPEED
	else:
		velocity.x = move_toward(velocity.x, 0, SPEED)
		velocity.z = move_toward(velocity.z, 0, SPEED)
	
	if Input.is_action_pressed("aimpc"):
		isAiming = true
	else:
		isAiming = false
	if  isAiming:
		var space_state = get_world_3d().direct_space_state
		var mouse_position = get_viewport().get_mouse_position()
		
		rayOrigin = camera.project_ray_origin(mouse_position)
		rayEnd = rayOrigin + camera.project_ray_normal(mouse_position) * 2000
		var query = PhysicsRayQueryParameters3D.create(rayOrigin, rayEnd)
		
		var Intersection = space_state.intersect_ray(query)
		
		if not Intersection.is_empty():
			var pos = Intersection.position
			$Mesh.look_at(Vector3(pos.x, global_position.y, pos.z), Vector3(0, 1, 0))
	elif not isAiming:
		if direction != Vector3.ZERO:
			$Mesh.look_at(position + direction, Vector3.UP)

	move_and_slide()

Everything works great but my question is, in

if direction != Vector3.ZERO:
	$Mesh.look_at(position + direction, Vector3.UP)

how would I smooth between different rotations because right now it just snaps and looks ugly
(I would show a vid but I can’t upload anything)

Rather than look_at() the thing directly, keep the old position, get the new position, and interpolate between old and new via lerp().

So something like:

#untested...

const TOTAL_LOOK_TIME = 3.0

var old_dir = Vector3.ZERO
var new_dir = Vector3.ZERO
var look_time = 0.0

[...]

if direction != Vector3.ZERO:
    if direction != new_dir: # Set up for a new look dir?
        old_dir = new_dir
        new_dir = direction
        look_time = 0.0

    look_time += delta
    if look_time > TOTAL_LOOK_TIME: # Are we done?
        look_time = TOTAL_LOOK_TIME
        direction = Vector3.ZERO

    # Look at the interpolated point.
    var cur = old_dir.lerp(new_dir, look_time / TOTAL_LOOK_TIME)
    $Mesh.look_at(position + cur, Vector3.UP)
1 Like

this works well but
1.

hat to be changed to var look_time = 0.0

when pressing A and then D or W and then S it still snaps

Thanks! I corrected the typo.

You’ll probably have to do more to make it fit your needs, but the example should give you the tools to do it. The general idea is, don’t directly look_at() something, rather look_at() an interpolated point between where you used to be looking and where you want to look. It may be you’ll need to compensate for other things. You may also need to handle things like where you’re initially looking, or what happens if you teleport.

sure, thanks for your help

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