Search code examples
javascriptcanvasprocessingp5.js

How to get the speed of an object dragged with the mouse in P5js library


I'm trying to make a script with P5.js library that lets the user drag and drop a ball that is affected by gravity. When the user drops the ball I need to measure the speed of it. With that information then I'm able to act in two different ways:

  1. If the ball is dropped with no speed it just falls straight down affected by the gravity force.
  2. If the ball is dropped while moving horizontally then it needs to follow that trajectory and of course be affected by the gravity force.

How can I get the instant speed of the ball? Can someone help me?

the code is:

function Ball() {

    this.diameter = 50;
    this.v_speed = 0;
    this.gravity = 0.2;
    this.starty = height/2 - 100;
    this.ypos = this.starty;
    this.xpos = width/2;

    this.update = function(){

        this.v_speed = this.v_speed + this.gravity; 
        this.ypos    = this.ypos + this.v_speed;

        if (this.ypos >= height-this.diameter/2){

            this.v_speed *= -1.0; // change direction
            this.v_speed = this.v_speed*0.9; 

            if ( Math.abs(this.v_speed) < 0.5 ) {
                this.ypos = this.starty;
            }
        }
    }

    this.show = function(){
        ellipse(this.xpos, this.ypos, this.diameter);
        fill(255);
    }
}

Solution

  • Write a function, which checks if a XY coordinate is on the ball:

    this.onBall = function(x, y) {
        let dx = x - this.xpos; 
        let dy = y - this.ypos; 
        let dist = Math.sqrt(dx*dx, dy*dy)
        return dist <= this.diameter/2; 
    }
    

    And 2 functions which start and stop dragging. The start function has set this.v_speed = 0 and to notice the current x and y coordinate of the mouse:

    this.startDrag = function() {
        this.drag = true;
        this.v_speed = 0;
        this.mousex = mouseX;  
        this.mousey = mouseY;
    }
    
    this.endDrag = function() {
        this.drag = false;  
    }
    

    Use the mousePressed() and mouseReleased() event to start and stop dragging of the Ball. Dragging is stated if the mouse is on the ball:

    function mousePressed() {
        if ( ball.onBall(mouseX, mouseY))
            ball.startDrag();
    }
    
    function mouseReleased() {
        ball.endDrag();
    }
    

    In update you have to implement 2 cases 1 for dragging and 1 for gravity:

    this.update = function() {
    
        this.minY = this.diameter/2;
        this.maxY = height-this.diameter/2;
        this.minX = this.diameter/2;
        this.maxX = width-this.diameter/2;
    
        if (this.drag) {
    
            // ... draging
    
        } else {
    
           // ... gravity
    
        }
    

    In case of "dragging" set the position of the ball to the mouse position. Further you have to update the initial horizontal speed this.v_speed_x and the vertical speed this.v_speed. The speed depends on the sidewards movement, immediately after the Ball is released (dragging ends):

      this.xpos = Math.max(this.minX, Math.min(this.maxX, mouseX)); 
      this.ypos = mouseY; 
      this.v_speed_x = this.v_speed_x/2 + (mouseX - this.mousex);
      this.v_speed   = this.v_speed/2 + (mouseY - this.mousey);
      this.mousex = mouseX;
      this.mousey = mouseY;
    

    In "gravity" case the fall and bounce has to be calculated as so far. Additional the decreasing sideward movement has to be applied:

    // calculate gravity
    
    this.v_speed  = this.v_speed + this.gravity; 
    this.ypos = this.ypos + this.v_speed;
    
    if (this.ypos >= this.maxY){
        this.ypos = this.maxY;
        this.v_speed *= -1.0; // change direction
        this.v_speed = this.v_speed*0.9; 
    }
    
    // the following has to be skipped if the ball is allowed to be thrown
    // up to the sky (out of the screen at the top)
    if (this.ypos <= this.minY){
        this.ypos = this.minY;
        this.v_speed *= -1.0;
        this.v_speed = this.v_speed*0.9;
    }
    
    // calculate side movement
    
    this.xpos = this.xpos + this.v_speed_x;
    if ( this.xpos <= this.minX){
        this.xpos = this.minX;
        this.v_speed_x *= -1;
    }
    if ( this.xpos >= this.maxX){
        this.xpos = this.maxX;
        this.v_speed_x *= -1;
    }
    this.v_speed_x = this.v_speed_x * 0.99;
    

    See the example:

    function Ball() {
        
        this.diameter = 80;
        this.v_speed = 0;
        this.gravity = 0.2;
        this.ypos = height/2 - 100;
        this.xpos = width/2;
        this.drag = false;
        this.v_speed_x = 0;
    
        this.onBall = function(x, y) {
            let dx = x - this.xpos; 
            let dy = y - this.ypos; 
            let dist = Math.sqrt(dx*dx, dy*dy)
            return dist <= this.diameter/2; 
        }
    
        this.startDrag = function() {
              this.drag = true;
              this.mousex = mouseX;
              this.mousey = mouseY;
        }
    
        this.endDrag = function() {
              this.drag = false;  
        }
    
        this.update = function() {
    
            this.minY = this.diameter/2;
            this.maxY = height-this.diameter/2;
            this.minX = this.diameter/2;
            this.maxX = width-this.diameter/2;
    
            if (this.drag) {
    
                this.xpos = Math.max(this.minX, Math.min(this.maxX, mouseX)); 
                this.ypos = mouseY; 
                this.v_speed_x = this.v_speed_x/2 + (mouseX - this.mousex);
                this.v_speed   = this.v_speed/2 + (mouseY - this.mousey);
                this.mousex = mouseX;
                this.mousey = mouseY;
    
            } else {
    
                // calculate gravity
    
                this.v_speed  = this.v_speed + this.gravity; 
                this.ypos = this.ypos + this.v_speed;
                
                if (this.ypos >= this.maxY){
                    this.ypos = this.maxY;
                    this.v_speed *= -1.0;
                    this.v_speed = this.v_speed*0.9; 
                }
                if (/*false &&*/ this.ypos <= this.minY){
                    this.ypos = this.minY;
                    this.v_speed *= -1.0;
                    this.v_speed = this.v_speed*0.9;
                }
    
                // calculate side movement
    
                this.xpos = this.xpos + this.v_speed_x;
                if ( this.xpos <= this.minX){
                    this.xpos = this.minX;
                    this.v_speed_x *= -1;
                }
                if ( this.xpos >= this.maxX){
                    this.xpos = this.maxX;
                    this.v_speed_x *= -1;
                }
                this.v_speed_x = this.v_speed_x * 0.99;
            }
        }
    
        this.show = function(){
            ellipse(this.xpos, this.ypos, this.diameter);
            fill(255);
        }
    }
    
    var ball;
    
    function mousePressed() {
        if ( ball.onBall(mouseX, mouseY))
            ball.startDrag();
    }
    
    function mouseReleased() {
        ball.endDrag();
    }
    
    function setup() {
        createCanvas(600, 600);
        ball = new Ball();
    }
    
    function draw() {
        background(0);
        ball.update();
        ball.show();
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.js"></script>

    Demo