Follow the mouse

Two shapes chasing the same target, one with lerp and one with move_toward. The lag between them is the whole lesson.

The editor above is running this project. Change a line and it reloads.

Godot classes used

Node2DPolygon2DInputEventMouseMotion

The code

scripts/main.gd
extends Node

const LERP_WEIGHT: float = 2.6
const MOVE_SPEED: float = 380.0
const GAP: float = 96.0
const DRIFT_SPEED: float = 1.5

var pointer: Polygon2D
var smooth: Node2D
var steady: Node2D
var target: Vector2
var center: Vector2
var span: Vector2
var drifting: bool = true
var elapsed: float = 0.0


func _ready() -> void:
	_add_background()

	var view: Vector2 = get_viewport().get_visible_rect().size
	center = view * 0.5
	span = view * 0.32
	target = center

	pointer = _make_circle(10.0, Color('#f3d48d'))
	pointer.position = target
	add_child(pointer)

	smooth = _make_follower('lerp', Color('#8da5f3'))
	smooth.position = center - Vector2(GAP, 0)
	add_child(smooth)

	steady = _make_follower('move_toward', Color('#8eef97'))
	steady.position = center + Vector2(GAP, 0)
	add_child(steady)

	_add_label('lerp closes a fraction of the gap each frame, move_toward covers a fixed distance', Vector2(40, 40), Color('#999999'))

	print('move the mouse, both shapes chase it')


func _input(event: InputEvent) -> void:
	if event is InputEventMouseMotion:
		target = event.position
		drifting = false


func _process(delta: float) -> void:
	elapsed += delta

	if drifting:
		target = center + Vector2(cos(elapsed * DRIFT_SPEED), sin(elapsed * DRIFT_SPEED * 1.7)) * span

	pointer.position = target
	smooth.position = smooth.position.lerp(target - Vector2(GAP, 0), LERP_WEIGHT * delta)
	steady.position = steady.position.move_toward(target + Vector2(GAP, 0), MOVE_SPEED * delta)


func _make_follower(text: String, color: Color) -> Node2D:
	var follower: Node2D = Node2D.new()
	follower.add_child(_make_circle(28.0, color))

	var label: Label = Label.new()
	label.text = text
	label.position = Vector2(-54, 38)
	label.add_theme_color_override('font_color', color)
	label.add_theme_font_size_override('font_size', 20)
	follower.add_child(label)

	return follower


func _add_label(text: String, at: Vector2, color: Color) -> void:
	var label: Label = Label.new()
	label.text = text
	label.position = at
	label.add_theme_color_override('font_color', color)
	label.add_theme_font_size_override('font_size', 20)
	add_child(label)


func _make_circle(radius: float, color: Color) -> Polygon2D:
	var points: PackedVector2Array = PackedVector2Array()

	for i in 28:
		points.append(Vector2(cos(TAU * i / 28.0), sin(TAU * i / 28.0)) * radius)

	var circle: Polygon2D = Polygon2D.new()
	circle.polygon = points
	circle.color = color

	return circle


func _add_background() -> void:
	var background: ColorRect = ColorRect.new()
	background.color = Color('#12141a')
	add_child(background)
	background.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)

More Motion examples