Mouse trail

A Line2D that gains a point where the pointer is and drops the oldest one once it is full. The width curve and the gradient do the fade.

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

Godot classes used

Line2DGradientCurve

The code

scripts/main.gd
extends Node

const MAX_POINTS: int = 110
const MIN_STEP: float = 7.0
const DRIFT_SPEED: float = 1.1

var trail: Line2D
var head: Polygon2D
var pointer: 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
	pointer = center

	var gradient: Gradient = Gradient.new()
	gradient.set_color(0, Color('#8da5f3', 0.0))
	gradient.set_color(1, Color('#8eef97'))

	var taper: Curve = Curve.new()
	taper.add_point(Vector2(0.0, 0.05))
	taper.add_point(Vector2(1.0, 1.0))

	trail = Line2D.new()
	trail.width = 16.0
	trail.width_curve = taper
	trail.gradient = gradient
	trail.joint_mode = Line2D.LINE_JOINT_ROUND
	trail.begin_cap_mode = Line2D.LINE_CAP_ROUND
	trail.end_cap_mode = Line2D.LINE_CAP_ROUND
	add_child(trail)

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

	_add_label('one point per frame, the oldest point leaves once the line is full', Vector2(40, 40))

	print('move the mouse, the line keeps the last ' + str(MAX_POINTS) + ' points')


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


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

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

	head.position = pointer

	if trail.get_point_count() == 0 or trail.points[-1].distance_to(pointer) > MIN_STEP:
		trail.add_point(pointer)

	while trail.get_point_count() > MAX_POINTS:
		trail.remove_point(0)


func _add_label(text: String, at: Vector2) -> void:
	var label: Label = Label.new()
	label.text = text
	label.position = at
	label.add_theme_color_override('font_color', Color('#999999'))
	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 24:
		points.append(Vector2(cos(TAU * i / 24.0), sin(TAU * i / 24.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