Trouble using mouse events to control movement of an object

Hi, I am working on a project and am relatively new to programming. I am have setup a ball class outside of main tab and am having trouble with using mouse events inside the ball class which are then called in the draw() function.

I am hoping for some advice on how I can start the ball on the grey box and when the mousePressed a line is drawn to show trajectory. When mouseReleased I want the ball to launch in the opposite direction.

Currently The ball is following the mouse and I don’t know how to implement a mouseReleased into the ball class and call it without looping continuously in draw() function. Any help is much appreciated.

/* ------------------------ Main Tab ----------------------*/
void setup()
{
   size(450,650);
   background(0);
   stroke(0); 
   
   ball = new Ball(20.0);
   //slider = new TBar(200);
}

Ball ball;
//TBar slider;

void draw()
{
  background(0);
  playingArea();
  
  ball.display();
  ball.moveBall();
  ball.edgeDetection();
  ball.mouseReleased();
  
  //slider.display();
  //slider.update();
  
}

void playingArea() 
{ 
  //centre the all shapes so x and y coord can be easily configured.
  rectMode(CENTER); // Set rectMode to CENTER
  //green
  fill(0,193,66);
  rect(width/2,height*0.5, 400,600);
  fill(150);
  //teeBox
  rect(width/2,height*0.9, 125,40);
  // hole 
  fill(0);
  ellipse(width/2, height*0.1, 20,20);
}

/*----------------------- Ball Class --------------------------------*/
public class Ball 
{
  private float xPos;
  private float yPos;
  private float diameter;
  private float xSpeed = 0.0;
  private float ySpeed = 0.0;
  private float friction = 0.996;
  
  //Constructor method
  public Ball(float diameter)
   {
      setDiameter(diameter);
   }
  
  //Draw the ball on the display window
  public void display()
  {
   fill(255);
   strokeWeight(1);
   ellipse(xPos, yPos, diameter, diameter);
  } 
  
  public void moveBall()
  {
    xPos = xPos + xSpeed;
    yPos = yPos + ySpeed;
    
    //add friction to slow the ball down after shot is taken  
    xSpeed = xSpeed*friction;
    ySpeed = ySpeed*friction;
    
     
    if(mousePressed == true)
    {
      strokeWeight(2);
      line(xPos,yPos,mouseX,mouseY);
    }
      
 
  }
  public void mouseReleased()
  {
    xSpeed = (mouseX - xPos);
    ySpeed = (mouseY - yPos);
    //noLoop();
  }
  
  public void edgeDetection()
  {
    if (xPos > width-30-diameter/2 || xPos < 30+diameter/2) {
      xSpeed *= -1.0;
    }
    if (yPos > height-30-diameter/2 || yPos < 30+diameter/2) {
      ySpeed *= -1.0;
    }

  }
  
  //getter methods
  public float getXPos()
   {  
      return xPos;
   }  

   public float getYPos()
   {
      return yPos;
   }  

   public float getDiameter()
   {
      return diameter;
   }  
   
   //setter methods
   public  void setDiameter(float diameter)
   {
     //The ball diameter must be between 20 and height/6 (inclusive)
     if ((diameter >= 20) && (diameter <= height/6)){
        this.diameter = diameter;
     }
     else {
        // If an invalid diameter is passed as a parameter, a default of 20 is imposed.
        // With this animation, if we do not supply a default value for the diameter, a ball may not be 
        // drawn on the display window.  Important note: it is not always appropriate to provide a default 
        // value at mutator level; this will depend on your design.
        this.diameter = 20;
     }
   }
  
}
1 Like

Please format yout text, press (Ctrl+shift+c) on a new line
The setup function is missing, i don’t know where you create your ball

@matheplica, thank you for responding so soon.
I have included the setup function in my post, so should open on Processing.
How would I create and use a mouse event function in the ball class that will work in my draw() function?

This would work inside the class

This won’t work inside the class. Solution: have void mouseReleased() also outside the class and call the class’ mouseReleased() from there

2 Likes

@Chrisir . I took your advice and moved the mousePressed() & mouseReleased() from the ball class into the main tab. I can now use the mouse to control the movement of the ball.

/*main tab */
Ball ball;

void setup()
{
   size(450,650);
   stroke(0); 
   
   ball = new Ball(20.0, width/2, height-40);
}
void draw()
{
  background(0,255,0);

  calculateSpeed();
  ball.display();
  ball.moveBall();
  ball.edgeDetection();
  fill(0);
  ellipse(width/2, 40, 30, 30);
  
 if(mousePressed == true)
 {
   strokeWeight(2);
   line(ball.getXPos(),ball.getYPos(),mouseX,mouseY);
 }
 println("speedX" +ball.getXSpeed()+ "speedY" +ball.getYSpeed());
}

void mouseReleased()
{  
  ball.setXSpeed(0);
  ball.setYSpeed(-3);
}
2 Likes

sorry last post was garbage, I shall recode the example before presenting.

Here is a link to my Button class, please note it is still a work in progress, but it all works fine,

https://www.openprocessing.org/sketch/857717

Thats just the button class, if you want to see it in action

take a look at the selfclick, toggle, latch, etc.

might need to copy it into your favourite editor, as the search isnt great on openprocessing.

1 Like

Nice that you got it working

Remark

You got a lot of usages of variables belonging to the class outside of it. For example in the line() command I quoted.

It would be better to have a function inside the class lineToMouse() and to make the line therein.

Then you just call the function don’t hassle with the variables of the class.

Same for mousePressed (where you didn’t follow my advice exactly)

2 Likes

After your reply, I went back to review and worked to implement your advice. I found it difficult but I have the mouse events working now (90% at least). Now that I have done it, I realize I overthink these problems and make it harder on myself by using to many variables.
Can I get your advice on collision detection in my program?

/*--------- main tab ----------*/
Ball ball;
Hole hole;

void setup()
{
   size(450,650);
   stroke(0); 
   
   ball = new Ball(20.0, width/2, height-40);
   hole = new Hole(30.0, width/2, 40);
}

void draw()
{
  background(0,255,0);

  ball.display();
  ball.moveBall();
  ball.stopBall();
  ball.edgeDetection();
  
  hole.display();
  
  if(mousePressed == true)
  {
    ball.lineToMouse();   
  }
  println("speedX" +ball.getXSpeed()+ "speedY" +ball.getYSpeed());
  
  boolean collision = hitHole(hole, ball);
  if(collision == true)
  {
   hit();
  }
}

void mouseReleased()
{ 
  ball.launchBall();
}

boolean hitHole(Hole hole, Ball ball)
  {
    //checking distance between ball and hole centres.
    float circleDistanceX = abs(ball.getXPos() - hole.getXPos());
    float circleDistanceY = abs(ball.getYPos() - hole.getXPos());
    float circleDistance = sqrt((circleDistanceX*circleDistanceX) + (circleDistanceY*circleDistanceY));
   
    //The distance between ball and hole radius is less tha ball diameter. Collision detected.
    if (circleDistance <= (ball.getDiameter()/2) + (hole.getDiameter()/2))
    {
      return true;
    }
   
    return false;
  }

 //will use laater for collision
  public void hit ()
  {
    //ball.setXSpeed(0);
    //ball.setYSpeed(0);
    //ball.setXPos(225);
    //ball.setYPos(50);
    hole.setXPos(random(50,400));
    hole.setYPos(random(50,400));
  }

/* --------- ball class --------*/
public class Ball 
{
  private float xPos;
  private float yPos;
  private float diameter;
  private float xSpeed;
  private float ySpeed;
  private float friction = 0.96;
  
  //Constructor method
  public Ball(float diameter, float xPos, float yPos)
   {  
     setDiameter(diameter);
     setXPos(xPos);
     setYPos(yPos);
   }
  
  //Draw the ball on the display window
  public void display()
  {
   fill(255);
   strokeWeight(1);
   ellipse(xPos, yPos, diameter, diameter);
  } 
  public void  lineToMouse()
  {
    strokeWeight(2);
    line(xPos, yPos,mouseX,mouseY);
  }
  
   public void launchBall()
  {
    xSpeed = mouseX - xPos; //set the speed in the direction of the mouse
    ySpeed = mouseY - yPos; 
  }
  
  public void moveBall()
  {
    xPos = xPos + xSpeed;
    yPos = yPos + ySpeed;
    //add friction to slow the ball down after shot is taken  
    xSpeed = xSpeed*friction;
    ySpeed = ySpeed*friction;
    
  }
  
  public void stopBall()
  {
    if(abs(xSpeed)<0.15 && abs(ySpeed)<0.15)
    {
      xSpeed = 0;
      ySpeed = 0;
    }
  }
  
  public void edgeDetection()
  {
    if (xPos > width-diameter/2 || xPos < diameter/2) {
      xSpeed *= -1.0;
    }
    if (yPos > height-diameter/2 || yPos < diameter/2) {
      ySpeed *= -1.0;
    }

  }
  
  //getter methods
  public float getXPos()
   {  
      return xPos;
   }  

   public float getYPos()
   {
      return yPos;
   }  
    public float getXSpeed()
   {  
      return xSpeed;
   }  

   public float getYSpeed()
   {
      return ySpeed;
   }
   public float getDiameter()
   {
      return diameter;
   }  
   
   //setter methods
   public  void setDiameter(float diameter)
   {
     if ((diameter >= 20) && (diameter <= height/6)){
        this.diameter = diameter;
     }
     else {
        this.diameter = 20;
     }
   }
   
   public  void setXPos(float xPos)
   {
     if ((xPos >=(diameter/2) && (xPos <= width -(diameter/2)))){
        this.xPos = xPos;
     }
     else {
        this.xPos = width/2;
     }
   }
  public  void setYPos(float yPos)
   {
     if ((yPos >(diameter/2) && (yPos <= height -(diameter/2)))){
        this.yPos = yPos;
     }
     else {
        this.yPos = height/2;
     }
   }
   public  void setXSpeed(float xSpeed)
   {
     if ((xSpeed >=0 && (xSpeed <= 10))){
        this.xSpeed = xSpeed;
     }
     else {
        this.xSpeed = 5;
     }
   }
  public  void setYSpeed(float ySpeed)
   {
     if ((ySpeed >(0) && (ySpeed <= 10))){
        this.ySpeed = ySpeed;
     }
     else {
        this.ySpeed = 5;
     }
   }
}

/*---------- hole class --------*/
public class Hole 
{
  private float xPos;
  private float yPos;
  private float diameter;

  //Constructor method
  public Hole(float diameter, float xPos, float yPos)
   {  
     setDiameter(diameter);
     setXPos(xPos);
     setYPos(yPos);
   }
  
  public void display()
  {
  fill(0);
  ellipse(width/2, 40, 30, 30);
  } 
  
  
  
  //getter methods
  public float getXPos()
  {  
    return xPos;
  }  

  public float getYPos()
  {
    return yPos;
  }  

  public float getDiameter()
  {
    return diameter;
  }  
  
   public  void setDiameter(float diameter)
  {
    //The ball diameter must be between 20 and height/6 (inclusive)
    if ((diameter >= 22) && (diameter <= height/6)) {
      this.diameter = diameter;
    } else {
      // value at mutator level; this will depend on your design.
      this.diameter = 22;
    }
  }
  
   public  void setXPos(float xPos)
   {
     if ((xPos >=(diameter/2) && (xPos <= width -(diameter/2)))){
        this.xPos = xPos;
     }
     else {
        this.xPos = width/2;
     }
   }
  public  void setYPos(float yPos)
   {
     if ((yPos >(diameter/2) && (yPos <= height -(diameter/2)))){
        this.yPos = yPos;
     }
     else {
        this.yPos = height/4;
     }
   }
}
1 Like

for sphere-sphere-reflection:
see https://www.processing.org/examples/bouncybubbles.html

but remove gravity

I had time to look into this.

I implemented a new screen where it is shown (red text) when you had a hit before the game goes on.

  • I changed: draw() (now based on boolean hit!), hitHole(), hit(), mouseReleased() (now based on boolean hit!),

  • class Ball: edgeDetection()

  • class Hole : display()

Suggestions

I would suggest that a hit is only allowed when the ball speed is below a certain speed. When it’s too fast he would skip over it.

At the moment, it is enough to click in the center of the hole. Which is a bit lame though. :wink:

Also the ball could get a new position after a hit.

Chrisir

Entire Code

//--------- main tab ----------/
Ball ball;
Hole hole;

boolean hit=false; 

void setup() {
  size(450, 650);
  stroke(0);

  ball = new Ball(20.0, width/2, height-40);
  hole = new Hole(30.0, width/2, 40);
}

void draw() {
  background(0, 255, 0);

  if (hit) {

    hole.display();
    ball.display();

    fill(255, 2, 2); 
    textSize(38);
    text("H I T", width/2-textWidth("H I T")/2, height/2);
    textSize(19);
    text("Click mouse", width/2-textWidth("Click mouse")/2, height/2+33);
  } else {

    ball.display();
    ball.moveBall();
    ball.stopBall();
    ball.edgeDetection();

    hole.display();

    if (mousePressed) {
      ball.lineToMouse();
    }
    // println("speedX" +ball.getXSpeed()+ "; speedY" +ball.getYSpeed());

    boolean collision = hitHole(hole, ball);
    if (collision) {
      hit();
    }
  }
}

void mouseReleased() {

  if (hit) {

    // reset 

    hit=false;

    hole.setXPos(random(50, 400));
    hole.setYPos(random(50, 400));
  } else {
    ball.launchBall();
  }
}

boolean hitHole(Hole hole, Ball ball) {
  //checking distance between ball and hole centres.

  if (dist(ball.getXPos(), ball.getYPos(), hole.getXPos(), hole.getYPos() ) <= hole.getDiameter()/3) {
    println("hit"); 
    ball.fullStop(); 
    return true;
  }

  /*
  float circleDistanceX = abs(ball.getXPos() - hole.getXPos());
   float circleDistanceY = abs(ball.getYPos() - hole.getXPos());
   float circleDistance = sqrt((circleDistanceX*circleDistanceX) + (circleDistanceY*circleDistanceY));
   
   //The distance between ball and hole radius is less tha ball diameter. Collision detected.
   if (circleDistance <= (ball.getDiameter()/2) + (hole.getDiameter()/2)) {
   return true;
   }
   */
  return false;
}

//will use later for collision
public void hit ()
{
  //ball.setXSpeed(0);
  //ball.setYSpeed(0);
  //ball.setXPos(225);
  //ball.setYPos(50);

  hit=true; 
  //hole.setXPos(random(50, 400));
  //hole.setYPos(random(50, 400));
}

/* --------- ball class --------*/
public class Ball
{
  private float xPos;
  private float yPos;
  private float diameter;
  private float xSpeed;
  private float ySpeed;
  private float friction = 0.96;

  //Constructor method
  public Ball(float diameter, float xPos, float yPos)
  {
    setDiameter(diameter);
    setXPos(xPos);
    setYPos(yPos);
  }

  //Draw the ball on the display window
  public void display()
  {
    fill(255);
    strokeWeight(1);
    ellipse(xPos, yPos, diameter, diameter);
  }
  public void lineToMouse()
  {
    strokeWeight(2);
    line(xPos, yPos, mouseX, mouseY);
  }

  public void launchBall()
  {
    xSpeed = mouseX - xPos; //set the speed in the direction of the mouse
    ySpeed = mouseY - yPos;
  }

  public void moveBall()
  {
    xPos = xPos + xSpeed;
    yPos = yPos + ySpeed;
    //add friction to slow the ball down after shot is taken
    xSpeed = xSpeed*friction;
    ySpeed = ySpeed*friction;
  }

  public void stopBall()
  {
    if (abs(xSpeed)<0.15 && abs(ySpeed)<0.15)
    {
      xSpeed = 0;
      ySpeed = 0;
    }
  }

  void fullStop() {
    xSpeed = 0;
    ySpeed = 0;
  }

  public void edgeDetection()
  {
    if (xPos > width-diameter/2 ) {
      xSpeed = - abs(xSpeed);
    }

    if ( xPos < diameter/2) {
      xSpeed = abs(xSpeed);
    }

    // -------------
    if (yPos > height-diameter/2 ) {
      ySpeed  = - abs(ySpeed);
    }

    if ( yPos < diameter/2) {
      ySpeed = abs(ySpeed);
    }
  }//func 

  //getter methods
  public float getXPos()
  {
    return xPos;
  }

  public float getYPos()
  {
    return yPos;
  }
  public float getXSpeed()
  {
    return xSpeed;
  }

  public float getYSpeed()
  {
    return ySpeed;
  }
  public float getDiameter()
  {
    return diameter;
  }

  //setter methods
  public void setDiameter(float diameter)
  {
    if ((diameter >= 20) && (diameter <= height/6)) {
      this.diameter = diameter;
    } else {
      this.diameter = 20;
    }
  }

  public void setXPos(float xPos)
  {
    if ((xPos >=(diameter/2) && (xPos <= width -(diameter/2)))) {
      this.xPos = xPos;
    } else {
      this.xPos = width/2;
    }
  }
  public void setYPos(float yPos)
  {
    if ((yPos >(diameter/2) && (yPos <= height -(diameter/2)))) {
      this.yPos = yPos;
    } else {
      this.yPos = height/2;
    }
  }
  public void setXSpeed(float xSpeed)
  {
    if ((xSpeed >=0 && (xSpeed <= 10))) {
      this.xSpeed = xSpeed;
    } else {
      this.xSpeed = 5;
    }
  }
  public void setYSpeed(float ySpeed)
  {
    if ((ySpeed >(0) && (ySpeed <= 10))) {
      this.ySpeed = ySpeed;
    } else {
      this.ySpeed = 5;
    }
  }
}

//---------- hole class --------/
public class Hole
{
  private float xPos;
  private float yPos;

  private float diameter;

  //Constructor method
  public Hole(float diameter, float xPos, float yPos)
  {
    setDiameter(diameter);
    setXPos(xPos);
    setYPos(yPos);
  }

  public void display()
  {
    fill(0);
    ellipse(xPos, yPos, 30, 30);
  }

  //getter methods
  public float getXPos()
  {
    return xPos;
  }

  public float getYPos()
  {
    return yPos;
  }

  public float getDiameter()
  {
    return diameter;
  }

  public void setDiameter(float diameter)
  {
    //The ball diameter must be between 20 and height/6 (inclusive)
    if ((diameter >= 22) && (diameter <= height/6)) {
      this.diameter = diameter;
    } else {
      // value at mutator level; this will depend on your design.
      this.diameter = 22;
    }
  }

  public void setXPos(float xPos)
  {
    if ((xPos >=(diameter/2) && (xPos <= width - (diameter/2)))) {
      this.xPos = xPos;
    } else {
      this.xPos = width/2;
    }
  }
  public void setYPos(float yPos)
  {
    if ((yPos >(diameter/2) && (yPos <= height -(diameter/2)))) {
      this.yPos = yPos;
    } else {
      this.yPos = height/4;
    }
  }
}
//
1 Like