Your browser does not support the canvas tag.

Week 4

maker map
discuss our design philosophy
talk about reading
paddle vs ball collision
photo cell
Pong as we left it at the end of week 3.

import processing.serial.*;
import cc.arduino.*;
Arduino arduino;
BallClass ball; 
int analogPin = 0;
PVector player1, player2; 
int playerW = 15; // width of paddle
int playerH = 60; // hieght of paddle
void setup() {
  size(600, 400); 
  smooth();// make the graphics look purdy.
  rectMode(CENTER); // draw rects from center
  player1 = new PVectorheight/2); 
  player2 = new PVector(spanstyle="color: #D94A7A;">width -20, height/2); 
  ball = new BallClass();
  arduino = new Arduino(this,Arduino.list()[15], 57600);
}
void draw () {
  background (50);// background color
  int pot1 = arduino.analogRead(analogPin); 
  player1.y = map(pot1, 0, 1023, 0, ); 
  rect(player1.x, player1.y, playerW, playerH); 
  rect(player2.x, player2.y, playerW, playerH); 
  ball.move(); 
  ball.display();
}
class BallClass {
  PVector ballLoc, velocity; 
  int ballsize = 16; // width of ball
  BallClass() {
    ballLoc = new PVectorwidth/2, height/2);
    velocity  = new PVecto(3, 1.2);
  }
  void move() {
    ballLoc.add(velocity); 
    if (ballLoc.x > width||ballLoc.x < 0) {
      velocity.x *= -1;
    }
    if (ballLoc.y > height||ballLoc.y < 0) {
      velocity.y *= -1;
    }
  }
  void display() {
    ellipse(ballLoc.x, ballLoc.y, ballsize, ballsize);
  }
}

Big problems!
1. In normal pong the ball speeds up when it hits a paddle increasing the difficulty. We could just up the velocity.x and this works, but wouldn't it be nice if is sped up in the direction it was going, not just along one axis? (answer: "yes, Joe, it would. I love learning!")
2. What if you want your pong ball to be a rect or an image that "faces" the direction it's going?

Hooray! We can solve both of these problems by adding a little trig to our code! DON'T PANIC - the computer does all the maths for us. So the ball object need two new variables, rotation that tells us which way it's headed and speed to tell us how fast it's going. Use sin and cos with the rotation and speed to get the x and y velocity. Then add the velocity to the location like we did last week. This complicates the wall bouncing slightly too. Instead of multiplying the velocity.x or velocity.y by -1 now you change the rotation variable. Fortunately this is pretty easy because our walls have a rotation of 0 or PI making the maths simple.

PVector ballLoc, velocity; 
float  r2 = .5; 
float speed = 4; 
void setup() {
  size (600, 400);
  smooth();
  ballLoc = new PVector(width/2, height/2);
  velocity = new PVector(0, 0);
  rectMode(CENTER);
}
void draw() {
  background(200);  
  velocity.x = cos(r2)*speed;  
  velocity.y = sin(r2)*speed;
  ballLoc.add(velocity); 
  pushMatrix(); // save current state
  translate(ballLoc.x, ballLoc.y); // make the "center" the new location
  rotate(r2); 
  line(0, 0, -40, 0); // draw the line and circle fromthis new center. 
  rect(0, 0, 10, 10);
  popMatrix(); // go back to current state. 
  if (ballLoc.x > width ||  ballLoc.x < 0) {
    r2 = PI - r2;
  }
  if (ballLoc.y > height || ballLoc.y < 0) {
    r2 = - r2;
  }
}

Complicated Bouncing

Okay, admittedly this get a little heady so if you want to ignore this part go ahead. But what if you want to bounce off something that's not perfectly flat or vertical? There's a couple issues. First is detecting the collision. There are a few ways to crack this nut, but one of the cleanest methods is to use two functions, one that checks to see if it has crossed the a line, the second to see if it's touching a line. These algorithms get a little tricky but it's mostly reapplying the Pythagorean theorem a couple times. The second problem is determining the angle the ball should leave at. First we calculate the angle it's coming in relative to an angle perpendicular to the angle of the line (angle of incidence). Then we calculate the angle it should go out by subtracting it from the perpendicular angle (angle of reflection). Physics!


 
PVector lineStart, lineEnd, ball, oldball, velocity; 
int balldiameter = 20; 
boolean linehit; 
color ballcolor = color(100, 200, 100); 
float rot = 2.8; 
float speedx, speedy; 
float speed = 6; 

void setup() {
  size(400, 400);
  smooth();
  lineStart = new PVector(200, 200); 
  lineEnd = new PVector(200, 200); 
  ball = new PVector(200, 200); 
  oldball = new PVector(200, 200); 
  velocity = new PVector(0, 0);
}
void draw() {
  background(200);  
  lineEnd.x = mouseX; 
  lineEnd.y = mouseY; 
  velocity.x = cos(rot)*(speed); 
  velocity.y = sin(rot)*(speed); 
  oldball.x = ball.x; 
  oldball.y = ball.y;
  ball.add(velocity); 
  if (ball.x < 0 || ball.x > width) { // side wall
    rot = PI - rot;
    linehit = false;
  }
  if (ball.y < 0 || ball.y > height) { // top & bottom
    rot = -rot; 
    linehit = false;
  }
  if (crossOverLine(ball.x, ball.y, oldball.x, oldball.y, lineStart.x, lineStart.y, lineEnd.x, lineEnd.y)) {
    bounce();
  } else  if (touchingLine(lineStart.x, lineStart.y, lineEnd.x, lineEnd.y, ball.x, ball.y, balldiameter/2)) {
    bounce();
  }
  stroke(0); 
  line (lineStart.x, lineStart.y, lineEnd.x, lineEnd.y); 
  fill(ballcolor); 
  ellipse (ball.x, ball.y, balldiameter, balldiameter);
  float ang  = atan2(lineStart.y-lineEnd.y, lineStart.x-lineEnd.x); 
  PVector crossEnd = new PVector(cos(ang + HALF_PI)*(20), sin(ang + HALF_PI)*(20)); 
  PVector crossStart = new PVector((lineEnd.x - lineStart.x)/2 + lineStart.x, (lineEnd.y - lineStart.y)/2 + lineStart.y); 
  fill(255, 0, 0); 
  ellipse (crossStart.x, crossStart.y, 6, 6); 
  line(crossStart.x, crossStart.y, crossStart.x + crossEnd.x, crossStart.y + crossEnd.y);
}

void bounce() {
  if (linehit == false) {
    linehit = true; 
    float ang  = atan2(lineStart.y-lineEnd.y, lineStart.x-lineEnd.x);
    float d = (ang + HALF_PI) - rot + PI; // get the angle between r and perpensicular
    rot =  d + (ang + HALF_PI) ; // add that angle to perpendicular
  }
}

boolean crossOverLine (float px, float py, float qx, float qy, float ax, float ay, float bx, float by) {
  float s, t, w1, w2, w3, w4, w5, w6;
  w1 = ax*(qy-py);
  w2 = (bx-ax)*(qy-py);
  w3 = px*(qy-py);
  w4= (qx-px)*ay;
  w5= (by-ay)*(qx-px);
  w6= py*(qx-px);
  s = (w3-w1+w4-w6)/(w2-w5);
  t = (ax+s*(bx-ax)-px)/(qx-px);
  if (s<0 || s>1 || qx==px || t<0 || t > 1 || w2==w5) {
    return false;
  } else {
    return true;
  }
}

boolean touchingLine (float px, float py, float qx, float qy, float cx, float cy, int rad ) {
  float dx, dy, t, rt;
  dx = qx-px; // get lenght of line
  dy = qy-py;
  t = -((px-cx)*dx+(py-cy)*dy)/((dx*dx)+(dy*dy)); 
  if (t<0.0) {
    t=0.0;
  } else if (t>1.0) {
    t = 1.0;
  }
  dx = (px+t*(qx-px))-cx;
  dy = (py +t*(qy-py))-cy;
  rt = (dx*dx) +(dy*dy);
  if (rt<(rad*rad)) {
    return true;
  } else {
    return false;
  }
}

Come prepared to talk about your custom pong game. Do a drawing(s) and have some code started.