/* Title: Physics Playing Blocks
* Author: Adam Gill
* Description:
* The goal is to just play around! You can drag the blocks with your mouse and fling them too.
* Try to stack the blocks on top of eachother, or even try to bounce one on top of the other.
*
* To fix the block merging glitch, click and hold on one of the two blocks merging together and they should split.
* Alternatively, you can press R to reset the blocks.
* You can also re-randomize the colors by pressing C.
*/
float gravity;
float box1LocX, box1LocY, box2LocX, box2LocY, box3LocX, box3LocY;
float box1VelX, box1VelY, box2VelX, box2VelY, box3VelX, box3VelY;
int box1Size, box2Size, box3Size, halfBox1Size, halfBox2Size, halfBox3Size;
boolean isMouseOverBox1, isMouseOverBox2, isMouseOverBox3;
color box1Color, box2Color, box3Color;
void setup() {
// Set canvas size
size(400, 400);
// Set variables
gravity = 0.98f;
box1LocX = 195f;
box1LocY = 340f;
box2LocX = 205f;
box2LocY = 230f;
box3LocX = 195f;
box3LocY = 120f;
box1VelX = 0f;
box1VelY = 0f;
box2VelX = 0f;
box2VelY = 0f;
box3VelX = 0f;
box3VelY = 0f;
box1Size = 100;
box2Size = 100;
box3Size = 100;
halfBox1Size = box1Size / 2;
halfBox2Size = box2Size / 2;
halfBox3Size = box3Size / 2;
isMouseOverBox1 = false;
isMouseOverBox2 = false;
isMouseOverBox3 = false;
box1Color = color((int) random(0, 255), (int) random(0, 255), (int) random(0, 255));
box2Color = color((int) random(0, 255), (int) random(0, 255), (int) random(0, 255));
box3Color = color((int) random(0, 255), (int) random(0, 255), (int) random(0, 255));
}
void draw() {
// Draw Methods
drawBackground();
drawBlock(box1LocX, box1LocY, box1Size, box1Color);
drawBlock(box2LocX, box2LocY, box2Size, box2Color);
drawBlock(box3LocX, box3LocY, box3Size, box3Color);
// Call update methods for each box, detect collisions, and finally apply the velocities to all boxes for next frame.
updateBox1();
updateBox2();
updateBox3();
detectCollisions();
applyVelocityToBoxes();
if (keyCode == 82) {
box1LocX = 195f;
box1LocY = 340f;
box2LocX = 205f;
box2LocY = 230f;
box3LocX = 195f;
box3LocY = 120f;
box1VelX = 0f;
box1VelY = 0f;
box2VelX = 0f;
box2VelY = 0f;
box3VelX = 0f;
box3VelY = 0f;
isMouseOverBox1 = false;
isMouseOverBox2 = false;
isMouseOverBox3 = false;
keyCode = 0;
}
if (keyCode == 67) {
box1Color = color((int) random(0, 255), (int) random(0, 255), (int) random(0, 255));
box2Color = color((int) random(0, 255), (int) random(0, 255), (int) random(0, 255));
box3Color = color((int) random(0, 255), (int) random(0, 255), (int) random(0, 255));
keyCode = 0;
}
}
// Updates physics for box 1
void updateBox1() {
boolean applyGravity = true;
// Check if the mouse is in the box
if ((mouseX > box1LocX - halfBox1Size && mouseX < box1LocX + halfBox1Size) && (mouseY > box1LocY - halfBox1Size && mouseY < box1LocY + halfBox1Size)) {
isMouseOverBox1 = true;
} else {
isMouseOverBox1 = false;
}
// Vertical Collision Detection
if (box1LocY + halfBox1Size + box1VelY > height) {
applyGravity = false;
box1VelY *= -0.5;
box1LocY = height - halfBox1Size;
} else if (box1LocY - halfBox1Size + box1VelY < 0) {
applyGravity = false;
box1VelY *= -0.5;
box1LocY = halfBox1Size;
}
// Horizontal Collision Detection
if (box1LocX + halfBox1Size + box1VelX > width) {
box1LocX = height - halfBox1Size;
box1VelX *= -0.5;
} else if (box1LocX - halfBox1Size + box1VelX < 0) {
box1LocX = halfBox1Size;
box1VelX *= -0.5;
}
// Box Grabber Code
// Calculates a vector between box 1 and the mouse then calculates a vector to move the box
if (mousePressed && isMouseOverBox1) {
applyGravity = false;
float tempXDist = mouseX - box1LocX;
float tempYDist = mouseY - box1LocY;
float tempAngle = atan(tempYDist / tempXDist);
float tempMagnitude = sqrt(sq(tempXDist) + sq(tempYDist));
float resultMagnitude = tempMagnitude * 0.9;
if (tempXDist > 0 && tempYDist > 0) {
box1VelX = resultMagnitude * cos(tempAngle);
box1VelY = resultMagnitude * sin(tempAngle);
} else if (tempXDist < 0 && tempYDist > 0) {
box1VelX = -resultMagnitude * cos(tempAngle);
box1VelY = -resultMagnitude * sin(tempAngle);
} else if (tempXDist > 0 && tempYDist < 0) {
box1VelX = resultMagnitude * cos(tempAngle);
box1VelY = resultMagnitude * sin(tempAngle);
} else if (tempXDist < 0 && tempYDist < 0) {
box1VelX = -resultMagnitude * cos(tempAngle);
box1VelY = -resultMagnitude * sin(tempAngle);
} else {
box1VelX = 0;
box1VelY = 0;
}
}
// Apply gravity if enabled
// If not then collision is probably happening so apply friction
if (applyGravity) {
box1VelY += gravity;
} else {
box1VelX *= 0.6;
box1VelY *= 0.6;
}
}
// Updates physics for box 2
void updateBox2() {
boolean applyGravity = true;
// Check if the mouse is in the box
if ((mouseX > box2LocX - halfBox2Size && mouseX < box2LocX + halfBox2Size) && (mouseY > box2LocY - halfBox2Size && mouseY < box2LocY + halfBox2Size)) {
isMouseOverBox2 = true;
} else {
isMouseOverBox2 = false;
}
// Vertical Collision Detection
if (box2LocY + halfBox2Size + box2VelY > height) {
applyGravity = false;
box2VelY *= -0.5;
box2LocY = height - halfBox2Size;
} else if (box2LocY - halfBox2Size + box2VelY < 0) {
applyGravity = false;
box2VelY *= -0.5;
box2LocY = halfBox2Size;
}
// Horizontal Collision Detection
if (box2LocX + halfBox2Size + box2VelX > width) {
box2LocX = height - halfBox2Size;
box2VelX *= -0.5;
} else if (box2LocX - halfBox2Size + box2VelX < 0) {
box2LocX = halfBox2Size;
box2VelX *= -0.5;
}
// Box Grabber Code
// Calculates a vector between box 2 and the mouse then calculates a vector to move the box
if (mousePressed && isMouseOverBox2) {
applyGravity = false;
float tempXDist = mouseX - box2LocX;
float tempYDist = mouseY - box2LocY;
float tempAngle = atan(tempYDist / tempXDist);
float tempMagnitude = sqrt(sq(tempXDist) + sq(tempYDist));
float resultMagnitude = tempMagnitude * 0.9;
if (tempXDist > 0 && tempYDist > 0) {
box2VelX = resultMagnitude * cos(tempAngle);
box2VelY = resultMagnitude * sin(tempAngle);
} else if (tempXDist < 0 && tempYDist > 0) {
box2VelX = -resultMagnitude * cos(tempAngle);
box2VelY = -resultMagnitude * sin(tempAngle);
} else if (tempXDist > 0 && tempYDist < 0) {
box2VelX = resultMagnitude * cos(tempAngle);
box2VelY = resultMagnitude * sin(tempAngle);
} else if (tempXDist < 0 && tempYDist < 0) {
box2VelX = -resultMagnitude * cos(tempAngle);
box2VelY = -resultMagnitude * sin(tempAngle);
} else {
box2VelX = 0;
box2VelY = 0;
}
}
// Apply gravity if enabled
// If not then collision of a wall is probably happening so apply friction
if (applyGravity) {
box2VelY += gravity;
} else {
box2VelX *= 0.6;
box2VelY *= 0.6;
}
}
// Updates physics for box 3
void updateBox3() {
boolean applyGravity = true;
// Check if the mouse is in the box
if ((mouseX > box3LocX - halfBox3Size && mouseX < box3LocX + halfBox3Size) && (mouseY > box3LocY - halfBox3Size && mouseY < box3LocY + halfBox3Size)) {
isMouseOverBox3 = true;
} else {
isMouseOverBox3 = false;
}
// Vertical Collision Detection
if (box3LocY + halfBox3Size + box3VelY > height) {
applyGravity = false;
box3VelY *= -0.5;
box3LocY = height - halfBox3Size;
} else if (box3LocY - halfBox3Size + box3VelY < 0) {
applyGravity = false;
box3VelY *= -0.5;
box3LocY = halfBox3Size;
}
// Horizontal Collision Detection
if (box3LocX + halfBox3Size + box3VelX > width) {
box3LocX = height - halfBox3Size;
box3VelX *= -0.5;
} else if (box3LocX - halfBox3Size + box3VelX < 0) {
box3LocX = halfBox3Size;
box3VelX *= -0.5;
}
// Box Grabber Code
// Calculates a vector between box 3 and the mouse then calculates a vector to move the box
if (mousePressed && isMouseOverBox3) {
applyGravity = false;
float tempXDist = mouseX - box3LocX;
float tempYDist = mouseY - box3LocY;
float tempAngle = atan(tempYDist / tempXDist);
float tempMagnitude = sqrt(sq(tempXDist) + sq(tempYDist));
float resultMagnitude = tempMagnitude * 0.9;
if (tempXDist > 0 && tempYDist > 0) {
box3VelX = resultMagnitude * cos(tempAngle);
box3VelY = resultMagnitude * sin(tempAngle);
} else if (tempXDist < 0 && tempYDist > 0) {
box3VelX = -resultMagnitude * cos(tempAngle);
box3VelY = -resultMagnitude * sin(tempAngle);
} else if (tempXDist > 0 && tempYDist < 0) {
box3VelX = resultMagnitude * cos(tempAngle);
box3VelY = resultMagnitude * sin(tempAngle);
} else if (tempXDist < 0 && tempYDist < 0) {
box3VelX = -resultMagnitude * cos(tempAngle);
box3VelY = -resultMagnitude * sin(tempAngle);
} else {
box3VelX = 0;
box3VelY = 0;
}
}
// Apply gravity if enabled
// If not then collision is probably happening so apply friction
if (applyGravity) {
box3VelY += gravity;
} else {
box3VelX *= 0.6;
box3VelY *= 0.6;
}
}
void detectCollisions() {
// These MONSTER if statements detects collisions between the blocks
/* Checks for the following:
* |_Is the right side of box1 inside box2? OR...
* |_Is the left side of box1 inside box2?
* |_...either of those AND either of...
* |_Is the top of box1 inside box2? OR...
* |_Is the bottom of box1 inside box2?
* \_> if so then:
* |_take half of box1 velocity, store it in temp. variable 1
* |_do the same with box2 and temp. var. 2
* |_reflect, half, and add temp. var. 2 to box1 velocity
* \_do the same with box2 and temp. var. 1
*
* Repeat for box1 & 3
* Repeat for box2 & 3
*/
// Box 1 & 2 collision
if ((((box1LocX + halfBox1Size + box1VelX > box2LocX - halfBox2Size + box2VelX) && (box1LocX + halfBox1Size + box1VelX < box2LocX + halfBox2Size + box2VelX)) ||
((box1LocX - halfBox1Size + box1VelX > box2LocX - halfBox2Size + box2VelX) && (box1LocX - halfBox1Size + box1VelX < box2LocX + halfBox2Size + box2VelX))) &&
(((box1LocY + halfBox1Size + box1VelY > box2LocY - halfBox2Size + box2VelY) && (box1LocY + halfBox1Size + box1VelY < box2LocY + halfBox2Size + box2VelY)) ||
((box1LocY - halfBox1Size + box1VelY > box2LocY - halfBox2Size + box2VelY) && (box1LocY - halfBox1Size + box1VelY < box2LocY + halfBox2Size + box2VelY)))) {
// Calculate bounce for x
float velocityXTemp1 = box1VelX / 2;
float velocityXTemp2 = box2VelX / 2;
box1VelX = -(box1VelX / 2) + velocityXTemp2;
box2VelX = -(box2VelX / 2) + velocityXTemp1;
// Calculate bounce for y
float velocityYTemp1 = box1VelY / 2;
float velocityYTemp2 = box2VelY / 2;
box1VelY = -(box1VelY / 2) + velocityYTemp2;
box2VelY = -(box2VelY / 2) + velocityYTemp1;
}
// Box 1 & 3 collision
if ((((box1LocX + halfBox1Size + box1VelX > box3LocX - halfBox3Size + box3VelX) && (box1LocX + halfBox1Size + box1VelX < box3LocX + halfBox3Size + box3VelX)) ||
((box1LocX - halfBox1Size + box1VelX > box3LocX - halfBox3Size + box3VelX) && (box1LocX - halfBox1Size + box1VelX < box3LocX + halfBox3Size + box3VelX))) &&
(((box1LocY + halfBox1Size + box1VelY > box3LocY - halfBox3Size + box3VelY) && (box1LocY + halfBox1Size + box1VelY < box3LocY + halfBox3Size + box3VelY)) ||
((box1LocY - halfBox1Size + box1VelY > box3LocY - halfBox3Size + box3VelY) && (box1LocY - halfBox1Size + box1VelY < box3LocY + halfBox3Size + box3VelY)))) {
// Calculate bounce for x
float velocityXTemp1 = box1VelX / 2;
float velocityXTemp2 = box3VelX / 2;
box1VelX = -(box1VelX / 2) + velocityXTemp2;
box3VelX = -(box3VelX / 2) + velocityXTemp1;
// Calculate bounce for y
float velocityYTemp1 = box1VelY / 2;
float velocityYTemp2 = box3VelY / 2;
box1VelY = -(box1VelY / 2) + velocityYTemp2;
box3VelY = -(box3VelY / 2) + velocityYTemp1;
}
// Box 2 & 3 collision
if ((((box2LocX + halfBox2Size + box2VelX > box3LocX - halfBox3Size + box3VelX) && (box2LocX + halfBox2Size + box2VelX < box3LocX + halfBox3Size + box3VelX)) ||
((box2LocX - halfBox2Size + box2VelX > box3LocX - halfBox3Size + box3VelX) && (box2LocX - halfBox2Size + box2VelX < box3LocX + halfBox3Size + box3VelX))) &&
(((box2LocY + halfBox2Size + box2VelY > box3LocY - halfBox3Size + box3VelY) && (box2LocY + halfBox2Size + box2VelY < box3LocY + halfBox3Size + box3VelY)) ||
((box2LocY - halfBox2Size + box2VelY > box3LocY - halfBox3Size + box3VelY) && (box2LocY - halfBox2Size + box2VelY < box3LocY + halfBox3Size + box3VelY)))) {
// Calculate bounce for x
float velocityXTemp1 = box2VelX / 2;
float velocityXTemp2 = box3VelX / 2;
box2VelX = -(box2VelX / 2) + velocityXTemp2;
box3VelX = -(box3VelX / 2) + velocityXTemp1;
// Calculate bounce for y
float velocityYTemp1 = box2VelY / 2;
float velocityYTemp2 = box3VelY / 2;
box2VelY = -(box2VelY / 2) + velocityYTemp2;
box3VelY = -(box3VelY / 2) + velocityYTemp1;
}
}
void applyVelocityToBoxes() {
// Box 1
box1LocX += box1VelX;
box1LocY += box1VelY;
// Box 2
box2LocX += box2VelX;
box2LocY += box2VelY;
// Box 3
box3LocX += box3VelX;
box3LocY += box3VelY;
}
// Draws a block at a location with a determined size
void drawBlock(float locX, float locY, float size, color boxColor) {
float halfSize = size / 2f;
float quartSize = halfSize / 2f;
rectMode(CENTER);
noStroke();
fill(boxColor); // True Color
rect(locX, locY, size, size);
fill(255, 255, 255, 100); // Light 2
quad(locX - halfSize, locY - halfSize, locX + halfSize, locY - halfSize, locX + quartSize, locY - quartSize, locX - quartSize, locY - quartSize);
fill(255, 255, 255, 55); // Light 1
quad(locX - halfSize, locY + halfSize, locX - halfSize, locY - halfSize, locX - quartSize, locY - quartSize, locX - quartSize, locY + quartSize);
fill(0, 0, 0, 55); // Dark 1
quad(locX + halfSize, locY - halfSize, locX + halfSize, locY + halfSize, locX + quartSize, locY + quartSize, locX + quartSize, locY - quartSize);
fill(0, 0, 0, 100); // Dark 2
quad(locX + halfSize, locY + halfSize, locX - halfSize, locY + halfSize, locX - quartSize, locY + quartSize, locX + quartSize, locY + quartSize);
}
// Draws the background texture
void drawBackground() {
background(100);
noFill();
stroke(55);
for (int i = -2; i < (width / 10) + 2; i++) {
line((i * 10) + (10 * sin(frameCount / 25f)), 0, (i * 10) + (10 * cos(frameCount / 25f)), height);
}
for (int i = -2; i < (width / 10) + 2; i++) {
line(0, (i * 10) + (10 * cos(frameCount / 25f)), width, (i * 10) + (10 * sin(frameCount / 25f)));
}
}