1

I have an application where I want a user to be able to throw/flick an object across the screen. Essentially they would drag the element across the screen quickly and let go, then it would keep moving in the direction they dragged it in at the same speed, then slowing down until it stops.

Answers in any language, or pseudocode would be appreciated. Or if there is a name for this algorithm that you can point me to that would also be helpful. Thanks

Rich
  • 21
  • 1

2 Answers2

2

I would find the speed at which the mouse is moving and set the speed of the object to the speed of the mouse. Speed of object = speed of mouse then per tick lower that speed, until it reaches 0.

If you want to make it more realistic, I would look here: https://physics.stackexchange.com/questions/391318/how-to-calculate-a-change-in-velocity-as-a-result-of-friction

1

Here's my stab at it:

  1. User starts dragging the object at position (x1, y1) at time t1
  2. User releases the object at position (x2, y2) at time t2
  3. Basic trigonometry using the points (x1, y1) and (x2, y2) gives you the direction of movement, and the distance between both points.
  4. Use the distance and the time difference between t1 and t2 to calculate the initial velocity of movement.
  5. Define a constant to define the decrease in velocity over time, let's call it deceleration.
  6. For every tick:
    1. Calculate the current velocity based on the previous velocity and the amount of deceleration.
    2. Use the current velocity along with the direction to calculate the new location of the object.
  7. End when the current velocity reaches zero.

Here's a very basic JavaScript implementation that just uses a directional vector instead of calculating direction and velocity separately:

class Flick {
  static tick = 10;
  static deceleration = .875;
  
  constructor(element) {
    this.element = element;
    this.element.addEventListener('dragstart', (e) => this.start(e));
    this.element.addEventListener('dragend', (e) => this.end(e));
    this.interval = null;
  }
  
  start(e) {
    const {screenX, screenY} = e;
    this.p1 = [screenX, screenY];
    this.t1 = Date.now();
    this.clear();
  }
  
  end(e) {
    const {screenX, screenY} = e;
    this.p2 = [screenX, screenY];
    this.t2 = Date.now();
    this.animate();
  }
  
  animate() {
    const [x1, y1] = this.p1
    const [x2, y2] = this.p2
    const [dx, dy] = [x2 - x1, y2 - y1];
    const t = this.t2 - this.t1
    
    this.move(dx, dy);
    this.vector = [dx * Flick.tick / t, dy * Flick.tick / t];
    this.interval = setInterval(() => {
      const [dx, dy] = this.vector;
      
      if (Math.abs(dx) < 1 && Math.abs(dy) < 1) {
        this.clear();
      } else {
        this.move(dx, dy);      
        this.vector = [dx * Flick.deceleration, dy * Flick.deceleration];
      }
    }, Flick.tick);
  }
  
  move(dx, dy) {
    const {x, y} = this.element.getBoundingClientRect();
   
    this.element.style.left = Math.round(x + dx) + 'px';
    this.element.style.top = Math.round(y + dy) + 'px';
  }
  
  clear() {
    this.interval && clearInterval(this.interval);
  }
}

new Flick(document.getElementById('object'));
#object {
  width: 50px;
  height: 50px;
  background-color: teal;
  position: absolute;
}
<div id="object" draggable="true"></div>
Robby Cornelissen
  • 91,784
  • 22
  • 134
  • 156
  • That part I understand. The part I'm having trouble with is how do I keep it moving in the same direction? And how do I move it a certain speed? I’m guessing I would have a loop that would move it for each iteration and dampen the velocity each time until went to zero. But based on the trajectory how do I calculate the x,y values for each iteration of the loop? And how do I control the timing to make it start moving at the same velocity? Thanks – Rich Jun 18 '21 at 02:58
  • My answer explains all that though... Direction of movement is just a vector you can calculate as explained in step 3. How you use that information to update the object's location is explained in step 6. It's just basic trigonometry and arithmetic. – Robby Cornelissen Jun 18 '21 at 03:13
  • Thanks, I tried running it, but it just seems to drag the object and it doesn't continue to move after you let go, or the bock just disappears. – Rich Jun 18 '21 at 14:02