From 1d71bf0c49693c9a896a653d9755e612ead8f6e4 Mon Sep 17 00:00:00 2001 From: lonkaars Date: Tue, 27 Jul 2021 17:08:33 +0200 Subject: better menu bar physics --- components/controls.tsx | 95 +++++++++++++++++++++++++++---------------------- 1 file changed, 53 insertions(+), 42 deletions(-) diff --git a/components/controls.tsx b/components/controls.tsx index b7df330..d544c6b 100644 --- a/components/controls.tsx +++ b/components/controls.tsx @@ -18,29 +18,35 @@ export function MenuBarControls({ next, previous, menu }: controlsPropsType) { var canvasRef = useRef(null); var options = { - margin: 100, // screen margin - friction: 0.0, // friction - edgeForce: 1.0, // force outside margin (inwards to edges) - centerForce: 0.6, // force inside margin (outwards to edges) - maxForce: 50, // limit force to not go over this value + margin: 24, // screen margin + friction: 0.2, // friction + edgeForce: 0.4, // force outside margin (inwards to edges) + centerForce: 0.4, // force inside margin (outwards to edges) + maxForce: 10, // limit force to not go over this value doneTolerance: 0.5, // if movement per frame goes below this value the animation is considered done + releaseSlopeAverageCount: 3, }; + var positionHistory: [number, number][] = []; + var slopeAverage: [number, number][] = []; + useEffect(() => { var canvas = canvasRef.current as HTMLCanvasElement; var ctx = canvas.getContext('2d'); - function line([x1, y1]: [number, number], [x2, y2]: [number, number]) { - ctx.beginPath(); - ctx.moveTo(x1, y1); - ctx.lineTo(x2, y2); - ctx.stroke(); - } + var physicsObject = { + velocity: [0, 0], + position: [0, 0], + }; var mouseX = 0; var mouseY = 0; + var mouseDown = false; function draw() { + positionHistory.push([mouseX, mouseY]); + if (positionHistory.length >= options.releaseSlopeAverageCount + 1) positionHistory.shift(); + var box = { outer: { x: 0, @@ -86,57 +92,61 @@ export function MenuBarControls({ next, previous, menu }: controlsPropsType) { ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.lineWidth = 2; - ctx.strokeStyle = '#ff00ff'; - - var center = findCenter(mouseX, mouseY); - var mouse = [mouseX, mouseY]; - // line(center, mouse as [ number, number ]); + var center = findCenter(physicsObject.position[0], physicsObject.position[1]); + var position = physicsObject.position; - var slope = (mouse[1] - center[1]) / (mouse[0] - center[0]); + var slope = (position[1] - center[1]) / (position[0] - center[0]); if (Math.abs(slope) < 1) { - var right = mouse[0] > center[0]; + var right = position[0] > center[0]; if (right) { var x = box.inner.x + box.inner.width; - var y = (x - mouseX) * slope + mouseY; + var y = (x - position[0]) * slope + position[1]; } else { var x = box.inner.x; - var y = (mouseX - x) * -slope + mouseY; + var y = (position[0] - x) * -slope + position[1]; } } else { - var slope = (mouse[0] - center[0]) / (mouse[1] - center[1]); - var bottom = mouse[1] > center[1]; + var slope = (position[0] - center[0]) / (position[1] - center[1]); + var bottom = position[1] > center[1]; if (bottom) { var y = box.inner.y + box.inner.height; - var x = (y - mouseY) * slope + mouseX; + var x = (y - position[1]) * slope + position[0]; } else { var y = box.inner.y; - var x = (mouseY - y) * -slope + mouseX; + var x = (position[1] - y) * -slope + position[0]; } } - var offset = [mouse[0] - x, mouse[1] - y]; - var outside = mouse[0] < box.inner.x - || mouse[0] > box.inner.x + box.inner.width - || mouse[1] < box.inner.y - || mouse[1] > box.inner.y + box.inner.height; + var offset = [position[0] - x, position[1] - y]; + var outside = position[0] < box.inner.x + || position[0] > box.inner.x + box.inner.width + || position[1] < box.inner.y + || position[1] > box.inner.y + box.inner.height; offset = offset.map(o => o * options[outside ? 'edgeForce' : 'centerForce']); var distance = Math.sqrt(offset[0] ** 2 + offset[1] ** 2); offset = offset.map(o => o * -Math.min(1, options.maxForce / distance)); - ctx.strokeStyle = '#ff0000'; - line([mouseX + offset[0], mouseY + offset[1]], [mouseX, mouseY]); + if (mouseDown) { + physicsObject.position = [mouseX, mouseY]; + for (let i = 1; i < positionHistory.length; i++) { + slopeAverage[i - 1] = [ + positionHistory[i][0] - positionHistory[i - 1][0], + positionHistory[i][1] - positionHistory[i - 1][1], + ]; + } + physicsObject.velocity[0] = slopeAverage.reduce((a, b) => a + b[0], 0) / slopeAverage.length; + physicsObject.velocity[1] = slopeAverage.reduce((a, b) => a + b[1], 0) / slopeAverage.length; + } else { + physicsObject.velocity[0] += offset[0]; + physicsObject.velocity[1] += offset[1]; + } - ctx.strokeStyle = '#00ffff'; + ctx.fillStyle = '#ff00ff'; + ctx.fillRect(physicsObject.position[0], physicsObject.position[1], 10, 10); - line([box.inner.x, box.inner.y], [box.inner.x + box.inner.width, box.inner.y]); - line([box.inner.x + box.inner.width, box.inner.y + box.inner.height], [ - box.inner.x + box.inner.width, - box.inner.y, - ]); - line([box.inner.x, box.inner.y + box.inner.height], [ - box.inner.x + box.inner.width, - box.inner.y + box.inner.height, - ]); - line([box.inner.x, box.inner.y], [box.inner.x, box.inner.y + box.inner.height]); + physicsObject.position[0] += physicsObject.velocity[0]; + physicsObject.position[1] += physicsObject.velocity[1]; + physicsObject.velocity[0] *= 1 - options.friction; + physicsObject.velocity[1] *= 1 - options.friction; requestAnimationFrame(draw); } @@ -151,6 +161,7 @@ export function MenuBarControls({ next, previous, menu }: controlsPropsType) { canvas.addEventListener('mousemove', e => { mouseX = e.clientX; mouseY = e.clientY; + mouseDown = (e.buttons & (1 << 0)) > 0; }); }, []); return
-- cgit v1.2.3