关于在p5.js(canvas)中实现带in-back缓动的鼠标跟随效果的问询
Got it, let's build that overshoot-then-snap mouse follow effect you're after! I'll walk you through a complete implementation that matches the core follow logic you referenced, plus adds that satisfying 10% overshoot before settling on the mouse position.
Core Concept
The "in-back" style easing you want (where the follower overshoots the target then snaps back) is perfectly achieved with an easeOutBack缓动函数. This function creates a curve that briefly exceeds the target value as it approaches 100% completion, then pulls back to the exact target. We'll pair this with position interpolation to make the follower move smoothly.
Complete Code
let followerPos; // Current position of the following object let startPos; // Starting position when mouse moves let targetPos; // Target mouse position let easingProgress = 0;// Tracks how far along the easing animation we are const EASE_DURATION = 60; // Frames to complete one easing cycle (~1 second at 60fps) const OVERSHOOT_AMOUNT = 1.70158; // Controls overshoot (~10% at this value) function setup() { createCanvas(600, 400); // Initialize follower at center of canvas followerPos = createVector(width / 2, height / 2); startPos = followerPos.copy(); targetPos = followerPos.copy(); } function mouseMoved() { // Update start/target positions when mouse moves, reset progress startPos = followerPos.copy(); targetPos = createVector(mouseX, mouseY); easingProgress = 0; } // Custom easeOutBack function to create the overshoot effect function easeOutBack(t) { t /= 1; // Normalize t to 0-1 range t--; return t * t * ((OVERSHOOT_AMOUNT + 1) * t + OVERSHOOT_AMOUNT) + 1; } function draw() { background(220); // Animate the follower if we're still easing towards the target if (easingProgress < 1) { easingProgress += 1 / EASE_DURATION; const easedT = easeOutBack(easingProgress); // Interpolate between start and target using the eased progress value followerPos = p5.Vector.lerp(startPos, targetPos, easedT); } // Draw the follower fill(255, 0, 0); noStroke(); ellipse(followerPos.x, followerPos.y, 30, 30); // Optional: Draw target marker for debugging fill(0, 255, 0); ellipse(targetPos.x, targetPos.y, 10, 10); }
Key Details Explained
- Easing Function: The
easeOutBackfunction is the magic here. Whent(progress from 0 to 1) nears 1, the calculation briefly returns a value >1, which makes our follower interpolate past the target position. It then snaps back to exactly 1 asthits 1, settling the follower on the mouse.- Adjust
OVERSHOOT_AMOUNTto tweak how far the follower overshoots: higher values = more overshoot, lower values = less (1.7 gives roughly 10% overshoot).
- Adjust
- State Tracking: Every time the mouse moves, we capture the follower's current position as the starting point and reset the animation progress. This ensures smooth transitions even if the mouse moves repeatedly.
- Smooth Interpolation:
p5.Vector.lerphandles the linear interpolation between start and target positions, and our easing function warps that interpolation to create the overshoot effect.
Real-Time Follow Variant (For Continuous Mouse Movement)
If you want the follower to track the mouse continuously (instead of triggering an animation on each mouse move), use this adjusted draw loop:
function draw() { background(220); const target = createVector(mouseX, mouseY); const direction = p5.Vector.sub(target, followerPos); const distance = direction.mag(); // Only move if we're far enough from the target to avoid jitter if (distance > 1) { const easeFactor = 0.05; // Controls how fast the follower moves const easedT = easeOutBack(easeFactor); direction.mult(easedT); followerPos.add(direction); } // Draw follower fill(255, 0, 0); noStroke(); ellipse(followerPos.x, followerPos.y, 30, 30); }
This variant applies the easing logic every frame, so the follower will overshoot and settle even as you move the mouse around continuously.
内容的提问来源于stack exchange,提问作者Andreas Lundqvist

