/* 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))); } }