Collision & Colors

edited November 2017 in Questions about Code

I wanted to change the aspects of a previous game I posted on here before but this time I built it again from the ground up (code below) and managed to get classes working this time.

I wanted to have it so that when a ball connects with a colored box, the ball changes to the color of the box (e.g. ball touches blue box, ball becomes blue, then if it touches green box, blue ball becomes green, etc.)

This is the code I have:

Ball b1 = new Ball();
Ball b2 = new Ball();
Ball b3 = new Ball();
Ball b4 = new Ball();

Chamber c1 = new Chamber();
Chamber c2 = new Chamber();
Chamber c3 = new Chamber();
Chamber c4 = new Chamber();
Chamber c5 = new Chamber();
Chamber c6 = new Chamber();

void setup() {
  size(640, 440);
  smooth();
  b2.ballY = 80;
  b2.ballXV = 3;
  b2.ballYV = 5;
  b3.ballX = 100;
  b3.ballY = 150;
  b3.ballYV = 5;
  b4.ballX = 300;
  b4.ballY = 300;
  b4.ballXV = 6;

  //red
  c1.chamberX = 0;
  c1.chamberY = 0;
  //blue
  c2.chamberX = 600;
  c2.chamberY = 0;
  //green
  c3.chamberX = 0;
  c3.chamberY = 400;
  //purple
  c4.chamberX = 600;
  c4.chamberY = 400;
  //yellow
  c5.chamberX = 300;
  c5.chamberY = 0;
  //cyan
  c6.chamberX = 300;
  c6.chamberY = 400;
}

void draw() {
  background(240);
  b1.drawAndMoveBall();
  b2.drawAndMoveBall();
  b3.drawAndMoveBall();
  b4.drawAndMoveBall();
  //red
  c1.drawChamber1();
  //blue
  c2.drawChamber2();
  //green
  c3.drawChamber3();
  //purple
  c4.drawChamber4();
  //yellow
  c5.drawChamber5();
  //cyan
  c6.drawChamber6();
}

class Ball {

  int ballX = 50;
  int ballY = 50;
  int ballXV = 4;
  int ballYV = 2;
  int ballDimension = 25;
  int ballRadius = ballDimension/2;
  color c;

  void drawAndMoveBall() {
    ballX += ballXV;
    ballY += ballYV;

    //checks to see if ball touches edges and bounces back
    if (ballX + ballRadius > width) {
      ballXV = -ballXV;
    }
    if (ballX - ballRadius < 0) {
      ballXV = -ballXV;
    }
    if (ballY + ballRadius > height) {
      ballYV = -ballYV;
    }
    if (ballY - ballRadius < 0) {
      ballYV = -ballYV;
    }

    c = color(255);
    strokeWeight(2);
    fill(c);
    ellipse(ballX, ballY, ballDimension, ballDimension);
  }
}

class Chamber {

  int chamberX = 0;
  int chamberY = 0;

  void drawChamber1() {
    fill(255, 0, 0);
    rect(chamberX, chamberY, 40, 40);
  }

  void drawChamber2() {
    fill(0, 255, 0);
    rect(chamberX, chamberY, 40, 40);
  }

  void drawChamber3() {
    fill(0, 0, 255);
    rect(chamberX, chamberY, 40, 40);
  }

  void drawChamber4() {
    fill(255, 0, 255);
    rect(chamberX, chamberY, 40, 40);
  }

  void drawChamber5() {
    fill(255, 255, 0);
    rect(chamberX, chamberY, 40, 40);
  }

  void drawChamber6() {
    fill(0, 255, 255);
    rect(chamberX, chamberY, 40, 40);
  }
}

Answers

  • A minor first step. but an important one.

    Ball b0 = new Ball();
    Ball b1 = new Ball();
    Ball b2 = new Ball();
    Ball b3 = new Ball();
    
    Chamber c0 = new Chamber();
    Chamber c1 = new Chamber();
    Chamber c2 = new Chamber();
    Chamber c3 = new Chamber();
    Chamber c4 = new Chamber();
    Chamber c5 = new Chamber();
    
    void setup() {
      size(640, 440);
      smooth();
    
      b1.ballY = 80;
      b1.ballXV = 3;
      b1.ballYV = 5;
      b2.ballX = 100;
      b2.ballY = 150;
      b2.ballYV = 5;
      b3.ballX = 300;
      b3.ballY = 300;
      b3.ballXV = 6;
    
      //red
      c0.chamberX = 0;
      c0.chamberY = 0;
      //blue
      c1.chamberX = 600;
      c1.chamberY = 0;
      //green
      c2.chamberX = 0;
      c2.chamberY = 400;
      //purple
      c3.chamberX = 600;
      c3.chamberY = 400;
      //yellow
      c4.chamberX = 300;
      c4.chamberY = 0;
      //cyan
      c5.chamberX = 300;
      c5.chamberY = 400;
    }
    
    void draw() {
      background(240);
      b0.drawAndMoveBall();
      b1.drawAndMoveBall();
      b2.drawAndMoveBall();
      b3.drawAndMoveBall();
      //red
      c0.drawChamber1();
      //blue
      c1.drawChamber2();
      //green
      c2.drawChamber3();
      //purple
      c3.drawChamber4();
      //yellow
      c4.drawChamber5();
      //cyan
      c5.drawChamber6();
    }
    
    class Ball {
    
      int ballX = 50;
      int ballY = 50;
      int ballXV = 4;
      int ballYV = 2;
      int ballDimension = 25;
      int ballRadius = ballDimension/2;
      color c;
    
      void drawAndMoveBall() {
        ballX += ballXV;
        ballY += ballYV;
    
        //checks to see if ball touches edges and bounces back
        if (ballX + ballRadius > width) {
          ballXV = -ballXV;
        }
        if (ballX - ballRadius < 0) {
          ballXV = -ballXV;
        }
        if (ballY + ballRadius > height) {
          ballYV = -ballYV;
        }
        if (ballY - ballRadius < 0) {
          ballYV = -ballYV;
        }
    
        c = color(255);
        strokeWeight(2);
        fill(c);
        ellipse(ballX, ballY, ballDimension, ballDimension);
      }
    }
    
    class Chamber {
    
      int chamberX = 0;
      int chamberY = 0;
    
      void drawChamber1() {
        fill(255, 0, 0);
        rect(chamberX, chamberY, 40, 40);
      }
    
      void drawChamber2() {
        fill(0, 255, 0);
        rect(chamberX, chamberY, 40, 40);
      }
    
      void drawChamber3() {
        fill(0, 0, 255);
        rect(chamberX, chamberY, 40, 40);
      }
    
      void drawChamber4() {
        fill(255, 0, 255);
        rect(chamberX, chamberY, 40, 40);
      }
    
      void drawChamber5() {
        fill(255, 255, 0);
        rect(chamberX, chamberY, 40, 40);
      }
    
      void drawChamber6() {
        fill(0, 255, 255);
        rect(chamberX, chamberY, 40, 40);
      }
    }
    
  • Thanks @TfGuy44, made those changes.

    Now I need the color advice, hopefully by tonight since this project is due tomorrow :D

  • edited May 2015

    Before advancing any further, you should seriously consider learning about arrays:

    That is, rather than having a series of b1, b2, b3, b4 labels, we'd have everything under 1 array label accessible w/ index:

    static final int BALLS = 4;
    final Ball[] balls = new Ball[BALLS];
    

    Doing so allows us to traverse the whole thing using some loop:

    for (Ball b : balls)  b.script();
    

    This simplifies the code a lot, believe me! :-\"

    Also, you should add some constructor to your classes:

    Ball(int x$, int y$, int vx$, int vy$) {
      x = x$;
      y = y$;
      vx = vx$;
      vy = vy$;
    }
    

    This way you can pass its initial values at the same time of using new:

    balls[0] = new Ball(50, 50, 4, 2);
    

    Noticed also that you have 6 drawChamber() methods for class Chamber.
    But the only diff. among them is its fill()'s value! :|

    Instead you shoulda declared a field to store it and pass it along its constructor:

    Chamber(int x$, int y$, color c$) {
      x = x$;
      y = y$;
      c = c$;
    }
    
    void display() {
      fill(c);
      rect(x, y, DIM, DIM);
    }
    

    Well, here's the whole tweaks I've made.
    I hope it's gonna be easier to add some collision method later on: ;)

    // forum.processing.org/two/discussion/10680/collision-colors
    // 2015-May-06
    
    static final int BALLS = 4;
    final Ball[] balls = new Ball[BALLS];
    
    static final int CHAMBERS = 6;
    final Chamber[] chambers = new Chamber[CHAMBERS];
    
    void setup() {
      size(640, 440, JAVA2D);
    
      smooth(4);
      frameRate(60);
    
      ellipseMode(CENTER);
      rectMode(CORNER);
    
      strokeWeight(Ball.BOLD);
      stroke(Ball.STROKE);
    
      balls[0] = new Ball(50, 50, 4, 2);
      balls[1] = new Ball(50, 80, 3, 5);
      balls[2] = new Ball(100, 150, 4, 5);
      balls[3] = new Ball(300, 300, 6, 2);
    
      chambers[0] = new Chamber(000, 000, #FF0000);
      chambers[1] = new Chamber(600, 000, #00FF00);
      chambers[2] = new Chamber(000, 400, #0000FF);
      chambers[3] = new Chamber(600, 400, #FF00FF);
      chambers[4] = new Chamber(300, 000, #FFFF00);
      chambers[5] = new Chamber(300, 400, #00FFFF);
    }
    
    void draw() {
      background(0350);
      for (Ball b : balls)  b.script();
      for (Chamber c : chambers)  c.display();
    }
    
    class Ball {
      static final short DIM = 25, RAD = DIM >> 1;
      static final short BOLD = 2;
      static final color STROKE = 0;
    
      int x, y, vx, vy;
      color c = -1;
    
      Ball(int x$, int y$, int vx$, int vy$) {
        x = x$;
        y = y$;
        vx = vx$;
        vy = vy$;
      }
    
      void script() {
        update();
        display();
      }
    
      void update() {
        if ((x += vx) > width  - RAD | x < RAD)  vx *= -1;
        if ((y += vy) > height - RAD | y < RAD)  vy *= -1;
      }
    
      void display() {
        fill(c);
        ellipse(x, y, DIM, DIM);
      }
    }
    
    class Chamber {
      static final short DIM = 40;
    
      int x, y;
      color c;
    
      Chamber(int x$, int y$, color c$) {
        x = x$;
        y = y$;
        c = c$;
      }
    
      void display() {
        fill(c);
        rect(x, y, DIM, DIM);
      }
    }
    
  • edited May 2015

    Boop.

  • Wow thanks a bunch, @GoToLoop!

    So if I wanted to work on the coloring the balls how would I go about it? I'm assuming I would need to make an "if" statement on draw?

  • Dang I have much slow. 8-|

  • edited May 2015
    • You're gonna need to check each Ball against each Chamber.
    • Or the inverse, your choice! :P
    • Therefore, it implies an extra double for () loop! :(|)
    • You're gonna have to implement some colliding() method too.
    • You just need to choose which of those 2 classes gonna have the extra method.
    • Of course both can have it. But let's decide for class Ball for now.
    • Now the 1st obstacle: Ball is ellipse() while Chamber is rect(). :-SS
    • So you have to choose whether to check them as quadratic or circular shapes!
    • I'd go w/ circular btW... O:-)
    • Now the 2nd obstacle, ellipseMode() is CENTER, while rectMode() is CORNER.
    • Since circular collision is based on shape's CENTER, you're gonna need to offset Chamber's top-left coordinates by adding its RAD before comparing to Ball's coordinates.
    • And before forgetting, colliding()'s signature would be something like this for Ball class:
      boolean colliding(Chamber c) { // ... }
  • How exactly do I check them as circular shapes? I haven't had any luck thus far getting this collision to work. :-SS

  • Can you show us your attempt at least? ~O)

  • Only did it for the first ball so far but here:

    // forum.processing.org/two/discussion/10680/collision-colors
    // 2015-May-06
    
    static final int BALLS = 4;
    final Ball[] balls = new Ball[BALLS];
    
    static final int CHAMBERS = 8;
    final Chamber[] chambers = new Chamber[CHAMBERS];
    
    void setup() {
      size(640, 440, JAVA2D);
    
      smooth(4);
      frameRate(60);
    
      ellipseMode(CENTER);
      rectMode(CORNER);
    
      strokeWeight(Ball.BOLD);
      stroke(Ball.STROKE);
    
      balls[0] = new Ball(50, 50, 4, 2);
      balls[1] = new Ball(50, 100, 3, 5);
      balls[2] = new Ball(100, 150, 4, 5);
      balls[3] = new Ball(300, 300, 6, 2);
    
      //red
      chambers[0] = new Chamber(000, 000, #FF0000);
      //green
      chambers[1] = new Chamber(600, 000, #00FF00);
      //blue
      chambers[2] = new Chamber(000, 400, #0000FF);
      //pink
      chambers[3] = new Chamber(600, 400, #FF00FF);
      //yellow
      chambers[4] = new Chamber(300, 000, #FFFF00);
      //cyan
      chambers[5] = new Chamber(300, 400, #00FFFF);
      //orange
      chambers[6] = new Chamber(000, 200, #FA9600);
      //purple
      chambers[7] = new Chamber(600, 200, #A100FA);
    }
    
    void draw() {
      background(0350);
      for (Ball b : balls)  b.script();
      for (Chamber c : chambers)  c.display();
    }
    
    class Ball {
      static final short dimensions = 25, radius = dimensions >> 1;
      static final short BOLD = 2;
      static final color STROKE = 0;
    
      int x, y, XV, YV;
      color c = -1;
    
      Ball(int tempX, int tempY, int tempXV, int tempYV) {
        x = tempX;
        y = tempY;
        XV = tempXV;
        YV = tempYV;
      }
    
      void script() {
        update();
        display();
      }
    
      void update() {
        if ((x += XV) > width  - radius | x < radius)  XV *= -1;
        if ((y += YV) > height - radius | y < radius)  YV *= -1;
    
        //collision detection changing color (FIRST BALL)
        if (balls[0].x <= chambers[0].x +40 && balls[0].y <= chambers[0].y +40) {
          fill(#FF0000);
        }
        if (balls[0].x <= chambers[1].x +40 && balls[0].y <= chambers[1].y +40) {
          fill(#00FF00);
        }
        if (balls[0].x <= chambers[2].x +40 && balls[0].y <= chambers[2].y +40) {
          fill(#0000FF);
        }
        if (balls[0].x <= chambers[3].x +40 && balls[0].y <= chambers[3].y +40) {
          fill(#FF00FF);
        }
        if (balls[0].x <= chambers[4].x +40 && balls[0].y <= chambers[4].y +40) {
          fill(#FFFF00);
        }
        if (balls[0].x <= chambers[5].x +40 && balls[0].y <= chambers[5].y +40) {
          fill(#00FFFF);
        }
        if (balls[0].x <= chambers[6].x +40 && balls[0].y <= chambers[6].y +40) {
          fill(#FA9600);
        }
        if (balls[0].x <= chambers[7].x +40 && balls[0].y <= chambers[7].y +40) {
          fill(#A100FA);
        }
      }
    
      void display() {
        fill(c);
        ellipse(x, y, dimensions, dimensions);
      }
    }
    
    class Chamber {
      static final short dimensions = 40;
    
      int x, y;
      color c;
    
      Chamber(int tempX, int tempY, color tempC) {
        x = tempX;
        y = tempY;
        c = tempC;
      }
    
      void display() {
        fill(c);
        rect(x, y, dimensions, dimensions);
      }
    }
    
  • And yes I added two more chambers :D

  • edited May 2015
    • It was supposed to implement a new method to check for a collision between some Ball against some Chamber... :ar!
    • Instead you tried to check each index of 1 type against each index of the other type 1 by 1.
    • It's evident it's far from complete b/c if we got 4 Ball objects and 8 Chamber objects, it's gonna take 4 x 8 = 32 if () blocks! @-)
    • That's why I've said a double loop would be required within sketch's draw()...
    • Moreover, both variables balls & chambers were declared at the top of the sketch and therefore belong to it alone!
    • Directly accessing variables which belong to some1 else is considered bad programming in OOP's point-of-view and we should avoid it as much as possible! :-@
    • That is, each class accesses its own variables (a.K.a. fields).
    • Exception for Processing's "system" variables like width, mousePressed, etc.
    • And in order to access them from others, they should be passed as function parameters instead! :-B
  • edited May 2015
    • 1 Math formula approach for colliding() would be: "the sum of the squared difference of their coordinates is less or equal to the squared sum of their radii".
    • Translating it: sq(c.x - b.x) + sq(c.y - b.y) <= sq(c.RAD + b.RAD);
    • Since I've arbitrarily chosen class Ball to have the newest method colliding(), it gets like this for example:

    boolean colliding(Chamber c) {
      return sq(c.x + Chamber.RAD - x) + sq(c.y + Chamber.RAD - y) < sq(Chamber.RAD + RAD);
    }
    

    The extra Chamber.RAD in c.x + Chamber.RAD & c.y + Chamber.RAD is to offset Chamber's rect() top-left based CORNER coordinates into CENTER coordinates just like that of Ball's ellipse().

    And I've also turned for (Ball b : balls) b.script(); into a double loop:

    for (Ball b : balls) {
      for (Chamber c : chambers)  if (b.colliding(c)) {
        b.c = c.c;
        break;
      }
    
      b.script();
    }
    

    So each Ball is checked against each Chamber.
    If method colliding() returns true, it assigns that specific Chamber's c variable to current Ball's also c variable.
    Then we finally can call Ball's script() method, which ends up display() it w/ the updated color. :-bd

  • edited April 2018

    Here's the whole working sketch. You can watch it online too here: :bz
    http://Studio.ProcessingTogether.com/sp/pad/export/ro.9qPrLGrYGkr2o

    /**
     * Ball in the Chamber (v2.04)
     * by  Rareware0192 (2015-May-06)
     * Mod GoToLoop (2015-May-07)
     *
     * Forum.Processing.org/two/discussion/10680/collision-colors#Item_14
     * Studio.ProcessingTogether.com/sp/pad/export/ro.9qPrLGrYGkr2o
     * Bl.ocks.org/GoSubRoutine/d0b7d3058d84970e83cf8685f8e69777
     */
    
    static final int BALLS = 4;
    final Ball[] balls = new Ball[BALLS];
    
    static final int CHAMBERS = 8;
    final Chamber[] chambers = new Chamber[CHAMBERS];
    
    void setup() {
      size(640, 440);
    
      smooth(3);
      frameRate(60);
    
      ellipseMode(CENTER);
      rectMode(CORNER);
    
      strokeWeight(Ball.BOLD);
      stroke(Ball.STROKE);
    
      balls[0] = new Ball(50, 50, 4, 2);
      balls[1] = new Ball(50, 80, 3, 5);
      balls[2] = new Ball(100, 150, 4, 5);
      balls[3] = new Ball(300, 300, 6, 2);
    
      chambers[0] = new Chamber(000, 000, #FF0000); // red
      chambers[1] = new Chamber(600, 000, #00FF00); // green
      chambers[2] = new Chamber(000, 400, #0000FF); // blue
      chambers[3] = new Chamber(600, 400, #FF00FF); // pink
      chambers[4] = new Chamber(300, 000, #FFFF00); // yellow
      chambers[5] = new Chamber(300, 400, #00FFFF); // cyan
      chambers[6] = new Chamber(000, 200, #FA9600); // orange
      chambers[7] = new Chamber(600, 200, #A100FA); // purple
    }
    
    void draw() {
      background(0350);
    
      for (final Ball b : balls) {
        for (final Chamber c : chambers)  if (b.colliding(c)) {
          b.c = c.c;
          break;
        }
    
        b.script();
      }
    
      for (final Chamber c : chambers)  c.display();
    }
    
    static final int sq(final int n) {
      return n*n;
    }
    
    class Ball {
      static final short DIM = 25, RAD = DIM >> 1;
      static final short BOLD = 2;
      static final color STROKE = 0;
    
      int x, y, vx, vy;
      color c = -1;
    
      Ball(int x$, int y$, int vx$, int vy$) {
        x = x$;
        y = y$;
        vx = vx$;
        vy = vy$;
      }
    
      void script() {
        update();
        display();
      }
    
      void update() {
        if ((x += vx) > width  - RAD | x < RAD)  vx *= -1;
        if ((y += vy) > height - RAD | y < RAD)  vy *= -1;
      }
    
      void display() {
        fill(c);
        ellipse(x, y, DIM, DIM);
      }
    
      boolean colliding(final Chamber c) {
        return sq(c.x + Chamber.RAD - x) + sq(c.y + Chamber.RAD - y)
          < sq(Chamber.RAD + RAD);
      }
    }
    
    class Chamber {
      static final short DIM = 40, RAD = DIM >> 1;
      static final short BOLD = 2;
      static final color STROKE = 0;
    
      final int x, y;
      final color c;
    
      Chamber(int x$, int y$, color c$) {
        x = x$;
        y = y$;
        c = c$;
      }
    
      void display() {
        fill(c);
        rect(x, y, DIM, DIM);
      }
    }
    
Sign In or Register to comment.