Week 07: Programming practice
Topics:
-
Practice with the concepts introduced so far in the course
-
Implementing more complex programs
-
Box intersection testing
Resources:
-
Lecture 10/23/2020 :sectnums:
Draw vs. Loops
Recall the following program from lab 05
int numCircles = 10;
float radius = 200;
void setup() {
size(500,500);
float delta = 2*pi/numCircles;
for (float angle = 0; angle < 2*PI; angle += delta) {
float x = 250 + radius * cos(angle);
float y = 250 + radius * sin(angle);
ellipse(x, y, 50, 50);
}
}
Let’s modify this program to draw the same image using draw()
instead of a loop
int numCircles = 100;
float radius = 200;
float delta = 2*PI/numCircles;
// approach: turn loop variable into accumulator variable
float angle = 0;
void setup() {
size(500,500);
}
void draw() {
float x = 250 + radius * cos(angle);
float y = 250 + radius * sin(angle);
ellipse(x, y, 50, 50);
angle += delta;
}
What are the differences between the two approaches?
-
With a loop, the code executes a finite number of steps (10) and we only see the result after it’s complete
-
With
draw()
, the code executes forever (unless we add anif
statement to stop further drawing). Note that we do not callbackground
to clear the screen.
Now modify the above program to animate one circle so it moves in a circle.
float radius = 200;
float delta = 0.1; // rate of change
float angle = 0;
void setup() {
size(500,500);
}
void draw() {
background(200);
float x = 250 + radius * cos(angle);
float y = 250 + radius * sin(angle);
ellipse(x, y, 50, 50);
angle += delta;
}
Array pallet
Write a program that creates 200 random rectangles.
-
The position and sizes of the rectangles should be random
-
The colors of the rectangle should be chosen randomly from a pallet of colors
-
For example, the image below was created with: #01315e, #92266c, #ff7979, #ffc174, #fff972
-
-
For fun, check out these sites for pallet ideas
void drawRectangles() {
color[] colors = {#01315e, #92266c, #ff7979, #ffc174, #fff972};
for (int i = 0; i < 200; i++) {
int idx = floor(random(0, colors.length));
fill(colors[idx]);
float x = random(0, width);
float y = random(0, height);
float w = random(0, width);
float h = random(0, height);
rect(x,y,w,h);
}
}
void setup() {
size(500,500);
drawRectangles();
}
Keyboard controls
Write a program that supports the following controls for a rectangle character:
-
Pressing 'd' moves right
-
Pressing 'a' moves left
-
Pressing 'w' moves up
-
Pressing 's' moves down
float xPos = 0;
float yPos = 0;
void setup() {
size(500,500);
}
void draw() {
background(200);
if (keyPressed) {
if (key == 'a') {
xPos = xPos - 10;
}
else if (key == 'd') {
xPos = xPos + 10;
}
else if (key == 'w') {
yPos = yPos - 10;
}
else if (key =='s') {
yPos = yPos + 10;
}
}
// Put in edge conditions
// wrap or clamp
rect(xPos, yPos, 100, 100);
}
How could we restrict the character’s movement to stay inside the canvas?
-
Clamp
// clamp
if (xPos > width-100) {
xPos = width-100;
}
else if (xPos < 0) {
xPos = 0;
}
if (yPos > height-100) {
yPos = height-100;
}
else if (yPos < 0) {
yPos = 0;
}
-
Wrap
if (xPos > width) {
xPos = 0;
}
else if (xPos < 0) {
xPos = width;
}
if (yPos > height) {
yPos = 0;
}
else if (yPos < 0) {
yPos = height;
}
Hover selection
Recall the text box from Lab 06. Let’s modify it to create square buttons that supports a mouse hover highlight.
// TODO: Implement insideTextBox
// Input: message (String) the text inside the box; Use this to get the box width/height
// Input: x (float) the X position of the text
// Input: y (float) the Y position of the text
// Returns boolean: true if the point mouseX,mouseY is inside the box; false otherwise
boolean insideTextBox(String message, float x, float y) {
float tw = textWidth(message);
float th = textAscent() + textDescent();
float topLeftX = x - tw * 0.5;
float topLeftY = y - th * 0.75;
if (mouseX >= topLeftX && mouseX <= topLeftX+tw &&
mouseY >= topLeftY && mouseY <= topLeftY+th) {
return true;
}
return false;
}
void drawTextBox(String message, float x, float y) {
float tw = textWidth(message);
float th = textAscent() + textDescent();
// TODO: Call insideTextBox to add highlight behavior
fill(255);
rect(x, y - th * 0.25, tw, th);
fill(0);
text(message, x, y);
}
void setup() {
size(500,500);
fill(0);
textSize(64);
textAlign(CENTER);
rectMode(CENTER);
}
void draw() {
background(200);
drawTextBox("Yes", 150, 250);
drawTextBox("No", 350, 250);
}
void mousePressed() {
if (box1.inside(mouseX, mouseY)) {
println("CLICK BOX1");
}
else if (box2.inside(mouseX, mouseY)) {
println("CLICK BOX2");
}
else {
println("CLICK NOTHING");
}
}
Collisions
Write a program that says "BAM!!" whenever two boxes collide. We will use classes for this program.
// Bryn Mawr 2020
// The main program
Box box1 = new Box(0,0,100,130, #8232E0);
Box box2 = new Box(300,400, 130, 100, #54832A);
void setup() {
size(500,500);
textSize(128);
textAlign(CENTER);
}
void draw() {
background(200);
box1.update();
box2.update();
box1.draw();
box2.draw();
if (box1.intersects(box2)) {
fill(0);
push();
translate(250,250);
rotate(-PI/6);
text("BAM!", 0, 0);
pop();
}
}
The Box class. Note that the boxes in this program use CORNER mode, not CENTER! Our Box class already has member variables for the position, size, and color. We’ve also implemented the constructor and accessor functions for you.
Now, let’s implement:
-
update
-
intersects
-
inside
class Box {
// Uses corner mode!
float mX = 0;
float mY = 0;
float mWidth = 100;
float mHeight = 100;
float mVelX = 0;
float mVelY = 0;
color mColor = #000000;
Box(float x, float y, float w, float h, color c) {
mX = x;
mY = y;
mWidth = w;
mHeight = h;
mVelX = random(-10,10);
mVelY = random(-10,10);
mColor = c;
}
// "setters"
// mutator functions
void setX(float x) {
mX = x;
}
// accessor functions
// "getters"
float x() {
return mX;
}
float y() {
return mY;
}
float width() {
return mWidth;
}
float height() {
return mHeight;
}
boolean inside(float x, float y) {
// This is a function stub.
// (x,y) are the coordinates for a point
// This function should return true if the point is inside this box; false otherwise
if (x >= mX && x <= mX + mWidth &&
y >= mY && y <= mY + mHeight) {
return true;
}
return false;
}
boolean intersects(Box other) {
// This is a function stub.
// This function should return true if this Box intersects 'other'
// To stay DRY, this function should call 'inside'
// Approach: get coordinates for each corner of other
// if any of the points of inside "me", then return true
// otherwise, return false
float x = other.x();
float y = other.y();
float w = other.width();
float h = other.height();
boolean topLeftTest = inside(x, y);
boolean topRightTest = inside(x+w,y);
boolean bottomLeftTest = inside(x, y+h);
boolean bottomRightTest = inside(x+w,y+h);
return topLeftTest || topRightTest ||
bottomLeftTest || bottomRightTest;
}
void draw() {
// Uses corner mode!
fill(mColor);
rect(mX, mY, mWidth, mHeight);
}
void update() {
// Function stub
// This function should implement a box that bounces inside the canvas
mX += mVelX;
mY += mVelY;
if (mX < 0) {
mVelX = -mVelX;
}
else if (mX > width-mWidth) {
mVelX = -mVelX;
}
if (mY < 0) {
mVelY = -mVelY;
}
else if (mY > height-mHeight) {
mVelY = -mVelY;
}
}
}