//// Billiard table, with moving balls. //// BAM 1B30e: Demonstrate simple classes, constructors, array of objects. More arrays. //// Swap velocities, when balls hit. //// Instantiate the balls and pockets. Pocket[] tunnels= new Pocket[6]; Ball[] balls= new Ball[3]; int score=0; void setup() { //// Setup: 600x400 (for 300x500 table). size(600,400); //// Initialize the 3 balls. balls[0]= new Ball(color(255,0,0), 100,100); balls[1]= new Ball(color(255,255,0), 100,130); balls[2]= new Ball(color(0,0,200), 100,160); //// Initialize the pockets (and tunnel ends). tunnels[0]= new Pocket( 65,65, 335,65+20 ); tunnels[1]= new Pocket( 65,335, 65,65+20 ); tunnels[2]= new Pocket( 300,65, 300,335-20 ); tunnels[3]= new Pocket( 300,335, 300,65+20 ); tunnels[4]= new Pocket( 535,65, 535,335-20 ); tunnels[5]= new Pocket( 535,335, 535,65+20 ); } void initialize() { //// Randomize the ball positions. balls[0].x=100+random(100); balls[0].y=100; balls[1].x=100+random(100); balls[1].y=130; balls[2].x=100+random(100); balls[2].y=160; } void keyPressed() { //// "R" restarts game. if (key=='R') { initialize(); } //// "Q" quits game. if (key=='Q') { exit(); } } void draw() { //// Table, with billiard balls. drawTable(); moveBalls(); drawBalls(); } void drawBalls() { //// Draw each ball. for (int k=0; k<3; k++) { balls[k].show(); } } void drawTable() { //// Draw 500x300 green light-table, with thick brown border, on tan backgroud. background( 200,150,100 ); // Tan floor. text( "BAM 1B30e: Arrays of objects. Swap v when hit.", 25, 10); fill( 255,0,0); text( "SCORE: "+score, 400, 10 ); fill( 100,100,200); //-- text( "(Ball tunnels when it goes into a pocket, and the table flashes its color).", 25, 30); fill( 0,0,200); text( "Press 'R' key to restart (randomly), 'Q' to quit.", 25, height-25); //// Table: fill( 100,200,100 ); // Light-green table. stroke( 100,50,50 ); // Brown (wood) rail. strokeWeight(25); rectMode(CORNER); rect(50,50, 500,300); // Table (with rail); //// 6 pockets. for (int j=0; j<6; j++) { fill(0); tunnels[j].drawPocket(); } } void moveBalls() { //// Move each ball, based on its velocity (dx,dy), //// and detect hits. for (int j=0; j<3; j++) { balls[j].move(); } //// Check for collisions. check(balls[0], balls[1]); check(balls[0], balls[2]); check(balls[1], balls[2]); //// Check each pocket for tunneling (if a ball is in the pocket). for (int j=0; j<6; j++) { for (int k=0; k<3; k++) { if (tunnels[j].inPocket(balls[k])) tunnels[j].wormhole(balls[k]); } } } void check( Ball p, Ball q) { //// Check for collisions; reverse both if hit. if (dist( p.x,p.y, q.x,q.y) < 20) { score += 10; /* p.dx= -p.dx; p.dy= -p.dy; q.dx= -q.dx; q.dy= -q.dy; */ // Swap velocities. float tmp; tmp = p.dx; p.dx= q.dx; q.dx= tmp; tmp = q.dx; q.dx= p.dx; p.dx= tmp; //// Eliminate "ringing" (by moving both in new direction. p.x += 2*p.dx; p.y += 2*p.dy; q.x += 2*q.dx; q.y += 2*q.dy; //// Also flash ball colors, and show text above. background(0); p.show(); q.show(); fill(255); text( "H I T !", p.x, p.y-20 ); text( "*", p.x, p.y ); text( "*", q.x, q.y ); } } ///////////////// CLASSES class Ball { //// Billiard ball. color c; float x=0,y=0; // Position of this ball. float dx=10,dy=10; // Velocity (pixels per frame). //// CONSTRUCTORS //// Ball( float x0, float y0 ) { //// 2-arg constructor sets position only. x= x0; y= y0; } Ball( color c0, float x0, float y0 ) { //// 3-arg constructor sets color & position. c= c0; x= x0; y= y0; } Ball( ) { //// Default constructor must be defined, if any others are defined! } //// METHODS //// void move() { //// Move ball by (dx,dy) x= x + dx; y= y + dy; // Bounce off walls. if (x < 75) { dx= -dx; } if (x > 525) { dx= -dx; } if (y < 75) { dy= -dy; } if (y > 325) { dy= -dy; } } void show() { //// Draw at (x,y) fill(c); //-- text(c, x, y+30); ellipseMode(CENTER); ellipse(x,y, 20,20); // Diameter is 20. } void showBlack() { //// Draw at (x,y) fill(0); ellipseMode(CENTER); ellipse(x,y, 20,20); // Diameter is 20. } } class Pocket { //// Pocket (tunnel); float x=0,y=0; // Position of this pocket. float xx=0,yy=0; // Position of tunnel end. //// CONSTRUCTOR(S); Pocket( float x0, float y0, float xx0, float yy0 ) { x= x0; y= y0; xx= xx0; yy= yy0; } //// METHOD(S) void drawPocket() { //// Draw a black pocket at (x,y). strokeWeight(0); ellipse( x,y, 30,30 ); } boolean inPocket( Ball p ) { //// Return true if ball is in this pocket. return dist(p.x,p.y, x,y) < 20; } void wormhole( Ball p ) { //// Tunneling moves ball from (x,y) to (xx,yy) p.x= xx; p.y= yy; //// Also flash ball color. fill( p.c ); drawPocket(); //-- rect(50,50, 500,300); // Table; } }