Moving ball and drawing a circle

edited May 19 in Questions about Code

Hi all! In this simple code I would that, every time I press a key, an empty circle be drawn in the exact position of the bouncing ball, with the ball that keep moving mainteining fill and stroke.

int r=20;
float x,y;
float speedx=4;
float speedy=3.5;
float xdir=1;
float ydir=1;

void setup() {
  size(500,500);
  ellipseMode(RADIUS);
  x=width/3;
  y=height/3;
}

void draw() {
  background(100);
  x=x+(speedx*xdir);
  y=y+(speedy*ydir);

  if((x>width-r) || (x<r)) {
    xdir*=-1;
  }
   if((y>height-r) || (y<r)) {
    ydir*=-1;
  }

  if(keyPressed) {
    noFill();
    stroke(0);
    ellipse(x, y, r, r);
  }

  ellipse(x,y,r,r);
}
Tagged:

Answers

  • edited May 19

    Here's a sketch that shows you what's going on.

    int r=20;
    float x,y;
    float speedx=4;
    float speedy=3.5;
    float xdir=1;
    float ydir=1;
    
    void setup() {
      size(500,500);
      ellipseMode(RADIUS);
      x=width/3;
      y=height/3;
    }
    
    void draw() {
      //background(100);
      x=x+(speedx*xdir);
      y=y+(speedy*ydir);
    
      if((x>width-r) || (x<r)) {
        xdir*=-1;
      }
       if((y>height-r) || (y<r)) {
        ydir*=-1;
      }
    
      if(keyPressed) {
        pushStyle();
        fill(255,0,0);//noFill();
        stroke(0);
        ellipse(x, y, r, r);
        popStyle();
      }
       noFill();
      ellipse(x,y,r,r);
    }
    

    Notice that in this example, the background is NOT being redrawn every frame, so everything is just drawn on top of everything that was already drawn. The moving ellipse now has no fill (so you can see when the filled ellipse appears), and the ellipse is filled when a key is pressed.

    Notice also that SEVERAL ellipses are in fact drawn when a key is pressed - not just one. This is because draw() is running over and over again very fast, and so it runs several times while the key is being held down! If you only want to do a thing once per key press, you should use the keyPressed() FUNCTION.

  • Answer ✓

    The other problem you have is that you need to remember where the stationary circles should be drawn, and draw them every time. To remember their positions, you will want a dynamic data structure that stores positions. An ArrayList of PVectors would be ideal for this. Then when a key is Pressed, we can just add a new PVector to the ArrayList. And we'll need to loop over all the locations to draw them too. Like so:

    int r=20;
    float x, y;
    float speedx=4;
    float speedy=3.5;
    float xdir=1;
    float ydir=1;
    
    ArrayList<PVector> hoops = new ArrayList();
    
    void setup() {
      size(500, 500);
      ellipseMode(RADIUS);
      x=width/3;
      y=height/3;
    }
    
    void draw() {
      background(100);
      x=x+(speedx*xdir);
      y=y+(speedy*ydir);
    
      if ((x>width-r) || (x<r)) {
        xdir*=-1;
      }
      if ((y>height-r) || (y<r)) {
        ydir*=-1;
      }
    
      noFill();
      stroke(0);
    
      for ( int i = 0; i < hoops.size(); i++) {
        ellipse(hoops.get(i).x, hoops.get(i).y, r, r);
      }
    
      fill(255);
      noStroke();
      ellipse(x, y, r, r);
    }
    
    void keyPressed(){
      hoops.add( new PVector(x,y) );
    }
    
  • Understood, thanks. But: there is a way to obtain that result withouth using arrays? So, basically, there is a way using only "if", "for" and only "setup" and "draw" functions? I'm in the early stages of learning Processing and maybe it might be useful study in deep the first stages of coding, even with the risk of stretching the code. Thanks again!

  • edited May 19

    ... a way to obtain that result without using arrays?

    Comment out background(). So anything already drawn stays. ;;)

  • edited May 19

    Nope, I mean, the result of them last code by TfGuy44

  • Answer ✓

    This next code only keeps track of the last click. However you need some sort of container to keep track of multiple hits. A simple array[] could work but it is inefficient. For example, if you defined it to store 100 objects, then at the beginning you need 100 clicks to lead the array. Otherwise you have to continuously be checking that you are not trying to draw an null position and you have to check you are not overflowing your array. Doable but it is more work. An ArrayList is more efficient as it grows as more data is input on it. No need to do overflow checking because everything in the array should be drawn (in your case for example)

    Kf

    int r=20;
    float x, y;
    float speedx=4;
    float speedy=3.5;
    float xdir=1;
    float ydir=1;
    
    float px, py;
    
    void setup() {
      size(500, 500);
      ellipseMode(RADIUS);
      x=width/3;
      y=height/3;
    }
    
    void draw() {
      background(100);
      x=x+(speedx*xdir);
      y=y+(speedy*ydir);
    
      if ((x>width-r) || (x<r)) {
        xdir*=-1;
      }
      if ((y>height-r) || (y<r)) {
        ydir*=-1;
      }
    
      fill(255);
      ellipse(x, y, r, r);
    
    
      noFill();
      ellipse(px, py, r, r);
    }
    
    void mouseReleased() {
      px=x;
      py=y;
    }
    
  • With an ArrayList, you add a PVector (storing the then position of the ball) to it each click, and if the number of PVectors in the ArrayList exceeds 100 (or whatever), remove the oldest of the PVectors.

  • edited May 20

    I've refactored @TfGuy44's version. Check it out at the link below: :bz
    https://OpenProcessing.org/sketch/429575

    /**
     * List of Hoops (v1.1)
     * Dmale & TfGuy44 (2017-May-19)
     * GoToLoop modded
     *
     * forum.Processing.org/two/discussion/22667/
     * moving-ball-and-drawing-a-circle#Item_8
     *
     * OpenProcessing.org/sketch/429575
     */
    
    static final int DIAM = 40, RAD = DIAM >> 1;
    static final float VX = 4, VY = 3.5;
    
    import java.util.List;
    final List<PVector> hoops = new ArrayList<PVector>();
    
    final PVector ball = new PVector(), vel = new PVector();
    
    void setup() {
      size(650, 500);
      smooth(3);
      frameRate(60);
    
      ellipseMode(CENTER);
      strokeWeight(1.5);
    
      final float x = random(RAD, width  - RAD);
      final float y = random(RAD, height - RAD);
      ball.set(x, y);
    
      final float dx = random(1) < .5? -1 : 1;
      final float dy = random(1) < .5? -1 : 1;
      vel.set(VX * dx, VY * dy);
    }
    
    void draw() {
      background(0200);
    
      displayHoops();
      displayBall();
    
      update();
      bounce();
    }
    
    void keyPressed() {
      hoops.add(ball.get());
    }
    
    void mousePressed() {
      if (mouseButton == LEFT)  keyPressed();
      else                      hoops.clear();
    }
    
    void displayHoops() {
      noFill();
      stroke(0);
      for (final PVector v : hoops)  ellipse(v.x, v.y, DIAM, DIAM);
    }
    
    void displayBall() {
      fill(-1);
      noStroke();
      ellipse(ball.x, ball.y, DIAM, DIAM);
    }
    
    void update() {
      ball.add(vel);
    }
    
    void bounce() {
      final float x = ball.x, y = ball.y;
    
      if (x > width  - RAD | x < RAD) {
        vel.set(-vel.x, vel.y);
        ball.add(vel.x, 0);
      }
    
      if (y > height - RAD | y < RAD) {
        vel.set(vel.x, -vel.y);
        ball.add(0, vel.y);
      }
    }
    
  • edited May 20

    And now the same code w/o using a List for the hoops. :D
    This way, we can have as many hoops w/o slowing down the whole sketch: \m/
    https://OpenProcessing.org/sketch/429577

    /**
     * Unlist of Hoops (v1.0)
     * Dmale & TfGuy44 (2017-May-19)
     * GoToLoop modded
     *
     * forum.Processing.org/two/discussion/22667/
     * moving-ball-and-drawing-a-circle#Item_9
     *
     * OpenProcessing.org/sketch/429577
     */
    
    static final int DIAM = 40, RAD = DIAM >> 1;
    static final float VX = 4, VY = 3.5;
    static final boolean IS_JAVA = 1/2 != 1/2.;
    
    //import java.util.List;
    //final List<PVector> hoops = new ArrayList<PVector>();
    
    final PVector ball = new PVector(), vel = new PVector();
    
    PGraphics pg;
    
    void setup() {
      size(650, 500);
      smooth(3);
      frameRate(60);
      ellipseMode(CENTER);
    
      final float x = random(RAD, width  - RAD);
      final float y = random(RAD, height - RAD);
      ball.set(x, y);
    
      final float dx = random(1) < .5? -1 : 1;
      final float dy = random(1) < .5? -1 : 1;
      vel.set(VX * dx, VY * dy);
    
      pg = createGraphics(width, height);
      pg.beginDraw();
    
      pg.smooth(3);
      pg.background(0200);
      pg.ellipseMode(CENTER);
    
      pg.noFill();
      pg.stroke(0);
      pg.strokeWeight(1.5);
    
      pg.endDraw();
    }
    
    void draw() {
      //background(0200);
      if (IS_JAVA)  background(pg);
      else          image(pg, 0, 0);
    
      displayBall();
      update();
      bounce();
    }
    
    void keyPressed() {
      //hoops.add(ball.get());
      makeHoop();
    }
    
    void mousePressed() {
      if (mouseButton == LEFT)  keyPressed();
      //else                      hoops.clear();
      else {
        pg.beginDraw();
        pg.background(0200);
        pg.endDraw();
      }
    }
    
    void makeHoop() {
      pg.beginDraw();
      pg.ellipse(ball.x, ball.y, DIAM, DIAM);
      pg.endDraw();
    }
    
    //void displayHoops() {
    //  noFill();
    //  stroke(0);
    //  for (final PVector v : hoops)  ellipse(v.x, v.y, DIAM, DIAM);
    //}
    
    void displayBall() {
      fill(-1);
      noStroke();
      ellipse(ball.x, ball.y, DIAM, DIAM);
    }
    
    void update() {
      ball.add(vel);
    }
    
    void bounce() {
      final float x = ball.x, y = ball.y;
    
      if (x > width  - RAD | x < RAD) {
        vel.set(-vel.x, vel.y);
        ball.add(vel.x, 0);
      }
    
      if (y > height - RAD | y < RAD) {
        vel.set(vel.x, -vel.y);
        ball.add(0, vel.y);
      }
    }
    
  • @GoToLoop If not Java, then what exactly?

  • Can't you guess? Haven't you seen it running online in your browser? I-)
    http://ProcessingJS.org

  • Of course, slipped my mind :P
    I never tried to see it running in my browser, considering that I'm using a tablet (it works on that too).

  • edited May 21 Answer ✓

    @dmale -- re:

    every time I press a key, an empty circle be drawn in the exact position of the bouncing ball [...] there is a way to obtain that result without using arrays?

    The two approaches above solve the problem like this:

    ArrayList:

    1. create an ArrayList
    2. save the location of each new circle as data (add to an ArrayList)
    3. each frame:
      • redraw the updated list of circles onto a fresh screen
      • draw the new ball location

    PGraphics:

    1. create an off-screen image buffer (PGraphics)
    2. save the location of each new circle as pixels (draw on a PGraphics)
    3. redraw the buffer (the circles) onto the screen each frame -- then draw the ball.
    4. each frame:
      • re-copy the updated image of circles onto a fresh screen
      • draw the new ball location
  • @jeremydouglass thanks, very clear!

  • @jeremydouglass I'm not sure I understand this-

    each frame:

    • re-copy the updated image of circles onto a fresh screen.
    • draw the new ball location.

    Why do you need to re-copy (whatever you mean by that)?

  • edited May 22

    Good question -- why "re-copy"? I was trying to emphasize that this is being done each time draw() is called -- as opposed to situations in which there is no background() and the main sketch itself is an image accumulator.

    1. The ArrayList approach uses saved data and draws the circles onto the main canvas -- in fact, it redraws them, each time draw() is called.

      for(int i=0;i<cs.size();i++){
        ellipse(cs.get(i).x, cs.get(i).y, w, h);
      }
      
    2. The PGraphics approach accumulates circles in a buffer image, then copies that image onto the main canvas -- in fact, it re-copies that image, each time draw() is called.

      image(pg, x, y);
      

    P.S. I mean "copy" above in the sense of copying a set of pixels from one place (the buffer) to another place (the canvas) -- not in the OO sense of making a copy of an Object (a new PGraphics).

Sign In or Register to comment.