// Experimental Interaction Assignment 03: Action and Reaction and better programming. // Requirements: Two different classes of objects that "react" to each other. // Virus in the Blood! by Jakob Fischer Jørgensen // An ebola virus has entered one of our blood vessels, which is very bad news. // We can only watch and be very sad, as the bad virus cells eats all the good stuff in our blood. // As the virus cells eats the good cells, the virus cells grow bigger and meaner. // As a sidenote, you can see which cell number in the array gets eaten in the output window. // The Virus array with a boolean to handle spawning Virus[] vi = new Virus[0]; boolean virus1 = true; // The Cells array with three booleans to handle spawning Cells[] ce = new Cells[0]; boolean spawn1 = true; boolean spawn2 = true; boolean spawn3 = true; // Variable for the background image PImage b; void setup() { // THE GREAT SETUP size(1024,576); // Sketch x and y size frameRate(60); // Sketch framerate b = loadImage("blood.jpg"); // Load background image } // SETUP OVER void draw() { // THE GREAT DRAW background(b); // Set background to our image b cursor(CROSS); // Replace the normal cursor with a cross // Check for cell against cell collision and check for boundary collision collision(); boundary(); // Check for virus against virus, virus against boundary, and virus against cell collision virusBoundary(); virusKillCell(); virusCollision(); // Grow, display and move each cell in the Cells array with for-loop // Dont grow, display or move anything with a null value for (int i = 0; i < ce.length; i++) { if (ce[i] != null) { ce[i].grow(); ce[i].display(); ce[i].move(); } } // Integer for number of cells to spawn each spawn cycle // Float for speed and direction of cells int numberOfCells = 40; float maxVelocity = 0.25; // Spawn cells after 1, 5 and 9 seconds, if corresponding spawn boolean is true // Set boolean to false when spawning is completed if ( millis() > 1000 && spawn1 == true) { spawn1 = false; for (int i = 0; i < numberOfCells; i++) { Cells newCells = new Cells(random(5,width-5),random(5,height-5),3,3, color(random(0,0),random(5,110),random(5,110)),random(-maxVelocity,maxVelocity),random(-maxVelocity,maxVelocity)); ce = (Cells[]) append(ce,newCells); } } if ( millis() > 5000 && spawn2 == true) { spawn2 = false; for (int i = 0; i < numberOfCells; i++) { Cells newCells = new Cells(random(5,width-5),random(5,height-5),3,3, color(random(0,0),random(5,110),random(5,110)),random(-maxVelocity,maxVelocity),random(-maxVelocity,maxVelocity)); ce = (Cells[]) append(ce,newCells); } } if ( millis() > 9000 && spawn3 == true) { spawn3 = false; for (int i = 0; i < numberOfCells; i++) { Cells newCells = new Cells(random(5,width-5),random(5,height-5),3,3, color(random(0,0),random(5,110),random(5,110)),random(-maxVelocity,maxVelocity),random(-maxVelocity,maxVelocity)); ce = (Cells[]) append(ce,newCells); } } // Integer for number of virus cells to spawn // Float for max speed and direction of virus cells int numberOfVirus = 4; float virusMaxVelocity = 0.50; // Grow, display and move each virus in the Virus array with for-loop for (int i = 0; i < vi.length; i++) { vi[i].grow(); vi[i].display(); vi[i].move(); } // Spawn the virus cells after 1 second if ( millis() > 1000 && virus1 == true) { virus1 = false; for (int i = 0; i < numberOfVirus; i++) { Virus newVirus = new Virus(random(5,width-5),random(5,height-5),5,5, color(random(150,255),random(0,0),random(0,0)),random(-virusMaxVelocity,virusMaxVelocity),random(-virusMaxVelocity,virusMaxVelocity)); vi = (Virus[]) append(vi,newVirus); } } } // DRAW OVER // THE GREAT COLLISION CHECK // Double nested for-loop to check cells in the array against eachother // We check the distance between the center of the cells and get the // outer distance by subtracting the growth of both divided by two // from the center distance. If this is less than zero, we have collision // If we have collision, we invert the growth of both cells to make them shrink // If growth is a negative number, we have to invert it in order to subract it void collision() { for (int i = 0; i < ce.length; i++) { for (int j = i; j < ce.length; j++) { if ((ce[i] != null) && (ce[j] != null)) { float centerDistance = dist (ce[i].xpos, ce[i].ypos, ce[j].xpos, ce[j].ypos); float iradius = ce[i].xgrowth/2; if (iradius < 0) { iradius *= -1; } float jradius = ce[j].xgrowth/2; if (jradius < 0) { jradius *= -1; } float outerDistance = centerDistance - iradius - jradius; if (outerDistance < 0) { ce[i].xgrowth = - ce[i].xgrowth; ce[i].ygrowth = - ce[i].ygrowth; ce[j].xgrowth = - ce[j].xgrowth; ce[j].ygrowth = - ce[j].ygrowth; ce[i].directionX *= -1; ce[i].directionY *= -1; ce[j].directionX *= -1; ce[j].directionY *= -1; } } } } } // Collision check for Virus against Cell // If virus hits cell, the cell is eaten and destroyed void virusKillCell() { for (int j = 0; j < vi.length; j++) { for (int i = 0; i < ce.length; i++) { if (ce[i] != null) { float centerDistance = dist (ce[i].xpos, ce[i].ypos, vi[j].xpos, vi[j].ypos); float cellradius = ce[i].xgrowth/2; if (cellradius < 0) { cellradius *= -1; } float virusradius = vi[j].xgrowth/2; if (virusradius < 0) { virusradius *= -1; } float outerDistance = centerDistance - cellradius - virusradius; if (outerDistance < 0) { // Remove dead cell NOT FREAKING RANDOM CELL //ce = (Cells[]) shorten(ce); ce[i] = null; vi[j].xgrowth = vi[j].xgrowth +3; vi[j].ygrowth = vi[j].ygrowth +3; vi[j].gcolor = color(random(150,255),random(0,100),random(0,0)); println(i); } } } } } // Collision Check for Virus vs Virus // If we have collision, we do the same as we did in cell against cell void virusCollision() { for (int i = 0; i < vi.length; i++) { for (int j = i; j < vi.length; j++) { if ((vi[i] != null) && (vi[j] != null)) { float centerDistance = dist (vi[i].xpos, vi[i].ypos, vi[j].xpos, vi[j].ypos); float iradius = vi[i].xgrowth/2; if (iradius < 0) { iradius *= -1; } float jradius = vi[j].xgrowth/2; if (jradius < 0) { jradius *= -1; } float outerDistance = centerDistance - iradius - jradius; if (outerDistance < 0) { vi[i].directionX *= -1; vi[i].directionY *= -1; vi[j].directionX *= -1; vi[j].directionY *= -1; } } } } } // Boundary collision check for the cells void boundary() { for (int i = 0; i < ce.length; i++) { if (ce[i] != null) { // Right side of sketch if (ce[i].xpos > width-ce[i].xgrowth / 2) { if (ce[i].directionX > 0) { ce[i].directionX *= -1; } } // Left side of sketch if (ce[i].xpos < ce[i].xgrowth / 2) { if (ce[i].directionX < 0) { ce[i].directionX *= -1; } } // Bottom of sketch if (ce[i].ypos > height-ce[i].ygrowth / 2) { if (ce[i].directionY > 0) { ce[i].directionY *= -1; } } // Top of sketch if (ce[i].ypos < ce[i].ygrowth / 2) { if (ce[i].directionY < 0) { ce[i].directionY *= -1; } } } } } // Boundary collision check for the Virus void virusBoundary() { for (int i = 0; i < vi.length; i++) { // Right side of sketch if (vi[i].xpos > width-vi[i].xgrowth / 2) { if (vi[i].directionX > 0) { vi[i].directionX *= -1; } } // Left side of sketch if (vi[i].xpos < vi[i].xgrowth / 2) { if (vi[i].directionX < 0) { vi[i].directionX *= -1; } } // Bottom of sketch if (vi[i].ypos > height-vi[i].ygrowth / 2) { if (vi[i].directionY > 0) { vi[i].directionY *= -1; } } // Top of sketch if (vi[i].ypos < vi[i].ygrowth / 2) { if (vi[i].directionY < 0) { vi[i].directionY *= -1; } } } } // Notes on for-loops: // Controls a sequence of repetitions. A "for" structure has three parts: init, test, and update. // Each part must be separated by a semi-colon ";". The loop continues until the test evaluates to false. // When a for structure is executed, the following sequence of events occurs: // 1. The init statement is executed // 2. The test is evaluated to be true or false // 3. If the test is true, jump to step 4. If the test is False, jump to step 6 // 4. Execute the statements within the block // 5. Execute the update statement and jump to step 2 // 6. Exit the loop.