From 5ecd62c0f29fd50f966b7ab78e8c4434d915cb4f Mon Sep 17 00:00:00 2001 From: RandomityGuy <31925790+RandomityGuy@users.noreply.github.com> Date: Sat, 15 Nov 2025 18:49:59 +0000 Subject: [PATCH] implement momentum based scroll for touch --- src/MarbleGame.hx | 2 +- src/gui/GuiConsoleScrollCtrl.hx | 51 ++++++++++++++++++++++++++++++++- src/gui/GuiScrollCtrl.hx | 6 ++-- 3 files changed, 54 insertions(+), 5 deletions(-) diff --git a/src/MarbleGame.hx b/src/MarbleGame.hx index 09b160b6..0837e3c1 100644 --- a/src/MarbleGame.hx +++ b/src/MarbleGame.hx @@ -180,7 +180,7 @@ class MarbleGame { }); pointercontainer.addEventListener('touchend', (e:js.html.TouchEvent) -> { - // @:privateAccess Key.keyPressed[Key.MOUSE_LEFT] = -Key.getFrame(); + @:privateAccess Key.keyPressed[Key.MOUSE_LEFT] = -Key.getFrame(); }); pointercontainer.addEventListener('touchmove', (e:js.html.TouchEvent) -> { diff --git a/src/gui/GuiConsoleScrollCtrl.hx b/src/gui/GuiConsoleScrollCtrl.hx index 6e1973ba..b79aafc3 100644 --- a/src/gui/GuiConsoleScrollCtrl.hx +++ b/src/gui/GuiConsoleScrollCtrl.hx @@ -10,6 +10,7 @@ import h2d.Tile; import h2d.Graphics; import src.MarbleGame; import src.Util; +import haxe.Timer; class GuiConsoleScrollCtrl extends GuiControl { public var scrollY:Float = 0; @@ -43,6 +44,11 @@ class GuiConsoleScrollCtrl extends GuiControl { var scrollUpButton:GuiButton; var scrollDownButton:GuiButton; + var scrollVelocity:Float = 0; + var lastMoveStamp:Float = 0; + var momentumActive:Bool = false; + + static inline var MOMENTUM_DAMPING:Float = 8; public function new(scrollBar:Tile) { super(); @@ -266,6 +272,9 @@ class GuiConsoleScrollCtrl extends GuiControl { this.dirty = true; this.updateScrollVisual(); this.prevMousePos = mouseState.position; + this.scrollVelocity = 0; + this.momentumActive = false; + this.lastMoveStamp = Timer.stamp(); } } @@ -274,6 +283,18 @@ class GuiConsoleScrollCtrl extends GuiControl { this.pressed = false; this.dirty = true; this.updateScrollVisual(); + this.momentumActive = Math.abs(scrollVelocity) > 0.01; + this.lastMoveStamp = 0; + } + } + + public override function onMouseLeave(mouseState:MouseState) { + if (Util.isTouchDevice()) { + this.pressed = false; + this.dirty = true; + this.updateScrollVisual(); + this.momentumActive = Math.abs(scrollVelocity) > 0.01; + this.lastMoveStamp = 0; } } @@ -281,14 +302,42 @@ class GuiConsoleScrollCtrl extends GuiControl { if (Util.isTouchDevice()) { super.onMouseMove(mouseState); if (this.pressed) { - var dy = mouseState.position.y - this.prevMousePos.y; + var renderRect = this.getRenderRectangle(); + var scrollExtentY = renderRect.extent.y - 34 * Settings.uiScale; + var dy = (mouseState.position.y - this.prevMousePos.y) / ((maxScrollY * Settings.uiScale) / scrollExtentY); this.scrollY -= dy; this.prevMousePos = mouseState.position; + var now = Timer.stamp(); + if (lastMoveStamp > 0) { + var dt = now - lastMoveStamp; + if (dt > 0) + scrollVelocity = -dy / dt; + } + lastMoveStamp = now; + momentumActive = false; this.updateScrollVisual(); } } } + public override function update(dt:Float, mouseState:MouseState) { + super.update(dt, mouseState); + if (!pressed && momentumActive) { + var damping = Math.exp(-MOMENTUM_DAMPING * dt); + scrollVelocity *= damping; + if (Math.abs(scrollVelocity) < 0.01) { + scrollVelocity = 0; + momentumActive = false; + return; + } + var before = scrollY; + scrollY += scrollVelocity * dt; + updateScrollVisual(); + if (scrollY == 0 || scrollY == before) + momentumActive = false; + } + } + // public override function onMouseDown(mouseState:MouseState) { // var renderRect = this.getHitTestRect(); // if (mouseState.position.x >= renderRect.position.x + renderRect.extent.x - 10) { diff --git a/src/gui/GuiScrollCtrl.hx b/src/gui/GuiScrollCtrl.hx index 7828fd54..1ce67742 100644 --- a/src/gui/GuiScrollCtrl.hx +++ b/src/gui/GuiScrollCtrl.hx @@ -232,10 +232,10 @@ class GuiScrollCtrl extends GuiControl { if (Util.isTouchDevice()) { super.onMouseMove(mouseState); if (this.pressed) { - var dy = (mouseState.position.y - this.prevMousePos.y) * scrollSpeed / this.maxScrollY; - deltaY = -dy; - this.scrollY -= dy; + this.scrollY -= (mouseState.position.y - this.prevMousePos.y) / (maxScrollY * Settings.uiScale); + deltaY = -(mouseState.position.y - this.prevMousePos.y) / (maxScrollY * Settings.uiScale); this.prevMousePos = mouseState.position; + this.updateScrollVisual(); } }