// Vehicles on images template // 872a Model-Based Design // // This series of steps is the generic recipe // // 1) Initialize the world and all agents (usually randomly) // // 2) Do the following in an infinite loop: // // 3) Update the world with its own update rules (find out light intensity). // // 4) Draw the world // // 5) Loop through each agent and for each agent // // A) Sense the world // // B) Apply rules to update internal state based on the // current state and the results of sensing the world // // C) Draw this agent in a particular way based on its // internal state // // GLOBAL CONSTANTS // Size of window final int X_SIZE = 400; final int Y_SIZE = 400; // Background image // Must be a jpg or gif. Must live in the "data" folder inside // this sketch. Must be the same dimensions as the window. //String imageName = "image_clouds.jpg"; //BImage bgImage; // Number of vehicles on the image final int NUM_VEHICLES = 50; final int VEHICLE_WIDTH = 2; final int VEHICLE_LENGTH = 20; final color VEHICLE_COLOR_R = int(20); final color VEHICLE_COLOR_G = int(235); final color VEHICLE_COLOR_B = int(80); //final color VEHICLE_COLOR = (255,0,0); // Increasing this increases the speed they travel // also makes it harder for them to turn sharply final float SPEED_MULT = 3; // Vehicle state information stored in this array // of objects of class Vehicle // We have not yet discussed objects and classes. (But we will.) Vehicle[] vehicles = new Vehicle[NUM_VEHICLES]; // Leave trails as they move? final boolean LEAVE_TRAILS = true; // Amounts to change the underlying image color when leaving a trail final color TRAIL_COLOR = #44CCE0; // The final color of the trail final float CHANGE_PER_TRAIL = 0.1; // the amount toward that color for each pass ///////////////////////////////////////////////// // CA - Variables int [][]grid = new int[100][100]; int m_x; int m_y; /////////////////////////////////////////////// // Framerate in frames-per-second final int FRAME_RATE = 60; // --------------- S E T U P ------------------------------- // Initialize the starting conditions // Randomly assign values to all cells void setup() { size(X_SIZE, Y_SIZE); background(255); // bgImage = loadImage(imageName); makeVehicles(); //framerate(FRAME_RATE); ///////////////////////////////////// for (int i=0;i<1120;i++) { grid[int(random(100))][int(random(100))]=1; } ////////////////////////////////////// } // --------------- L O O P ------------------------------- void loop() { //drawImage(); // displays the image that the vehicles can use to calculate their state background(25,0,10); update_cellular_state_and_draw_cells(); calculateNextVehicleStates(); updateVehicleStates(); drawVehicles(); calc_next_cellular_state(); } // ----------------------- C L A S S V E H I C L E -------------- // Vehicle is a class. We will discuss what that is in class on Friday. // A class is a template for making objects. An object is a container for // variables and functions. That is not enough explanation. Do not worry about it. // But nonetheless know that each vehicle has all of the following attributes and // can have any of the following calls made on it. class Vehicle { float x, y, direction; // Location and direction (direction is in radians) float nextX, nextY, nextDirection; // Location and direction to update to float lSensorX, lSensorY, rSensorX, rSensorY; // Left and right sensor locations float lSensorVal, rSensorVal; // Left and right sensor values float width, length; // Width and length of the vehicle (set by default to VEHICLE_WIDTH and VEHICLE_LENGTH) int type; // What type of vehicle is this? // Right now we are only using one type (0), but you might want to define more. color trailColor = TRAIL_COLOR; // The color of the trail. Likely different for every vehicle type. // color vehicleColor = VEHICLE_COLOR; // The color of the vehicle. color vehicleColor_R = VEHICLE_COLOR_R; color vehicleColor_G = VEHICLE_COLOR_G; color vehicleColor_B = VEHICLE_COLOR_B; boolean onEdge; // Have we hit an edge? // ------------------ V E H I C L E --------------------------------- // Constructor function. This is called each time a new vehicle object is // created. Randomly assigns state values. Vehicle(int aType) { type = aType; x = random(X_SIZE); y = random(Y_SIZE); onEdge = false; direction = random(0, 360.0); width = VEHICLE_WIDTH; length = VEHICLE_LENGTH; } // ------------------ V E H I C L E . U P D A T E S T A T E --------------------------------- // Update the vehicle's internal state with the new values void updateState() { x = nextX; y = nextY; direction = nextDirection; updateSensorPositions(); // Update where the sensors are /* // Leave the trail sticking out of the middle of the back of the vehicle if (LEAVE_TRAILS) { float dx2 = -(width/2) * sin(HALF_PI - direction); float dy2 = (width/2) * cos(HALF_PI - direction); int trailX = int(x - dx2); int trailY = int(y + dy2); int index = trailY*X_SIZE + trailX; if (index < 0 || index >= X_SIZE * Y_SIZE) { return; } color c = bgImage.pixels[index]; int dRed = int( (red(trailColor) - red(c)) * CHANGE_PER_TRAIL); int dGreen = int( (green(trailColor) - green(c)) * CHANGE_PER_TRAIL); int dBlue = int( (blue(trailColor) - blue(c)) * CHANGE_PER_TRAIL); bgImage.pixels[index] = color(red(c)+dRed,green(c)+dGreen,blue(c)+dBlue); } */ } // ------------------ V E H I C L E . U P D A T E S E N S O R P O S I T I O N S --------------------------------- // Update where the vehicle's sensors are void updateSensorPositions() { float dx = -length-20 * sin(direction); float dy = length+20 * cos(direction); float dx2 = -width-20 * sin(HALF_PI - direction); float dy2 = width+20 * cos(HALF_PI - direction); rSensorX = x + dx; rSensorY = y + dy; lSensorX = rSensorX - dx2; lSensorY = rSensorY + dy2; } // ------------------ V E H I C L E . R E A D S E N S O R S --------------------------------- // Get values from the sensors (right now senses brightness only) // You could change that to have them sense whatever you want. void readSensors() { if (lSensorY < 0 || lSensorY > Y_SIZE || lSensorX < 0 || lSensorX > X_SIZE) { lSensorVal = 0; onEdge = true; } else { lSensorVal = SPEED_MULT * brightness(get((int)lSensorX, (int)lSensorY)) / 255.0; } if (rSensorY < 0 || rSensorY > Y_SIZE|| rSensorX < 0 || rSensorX > X_SIZE) { rSensorVal = 0; onEdge = true; } else { rSensorVal = SPEED_MULT * brightness(get((int)rSensorX, (int)rSensorY)) / 255.0; } } // ------------------ V E H I C L E . C A L C U L A T E N E X T S T A T E --------------------------------- // Determine what the nest state should be depending on the sensor values void calculateNextState() { readSensors(); // If you've hit an edge, reposition randomly if (onEdge) { nextX = random(X_SIZE); nextY = random(Y_SIZE); nextDirection = random(TWO_PI); onEdge = false; return; } // Here's where you'd cross sensor wires. vL and vR are velocity of left and right // wheels, and lSensorVal and rSensorVal are the left and right sensor values. // A lot of behavior can be changed by messing with these two lines. float vR = rSensorVal/2; float vL = lSensorVal/2; float dRot = atan2((vR - vL), width); float avg = (vR + vL) / 2.0; float dy = cos(direction + (dRot / 2.0)) * avg; float dx = -sin(direction + (dRot / 2.0)) * avg; nextX = x + dx*6; nextY = y + dy*6; nextDirection = direction + dRot/5; if (nextDirection > TWO_PI) { nextDirection -= TWO_PI; } } // ------------------ V E H I C L E . D R A W --------------------------------- // Draw the vehicle void draw() { int ix = int(x); int iy = int(y); noStroke(); fill(vehicleColor_R,vehicleColor_G,vehicleColor_B); push(); translate(ix, iy); rotate(direction); //rect(0, 0, 10, 30); quad(10, 10, 15, 20, 10, 40, 5, 20); pop(); //set cells at the same position as vehicle to zero if (ix > 360) { ix = 360; }else if (ix < 40) { ix = 40; }else if (iy > 360) { iy = 360; }else if (iy < 40) { iy = 40; }else { //erase black cells by making an area around the vehicle = 0 in the cellular array int q = 0; grid[ix/4][iy/4]=q; for(int g=5;g<9;g++){ grid[ix/4+g][iy/4]=q; grid[ix/4-g][iy/4]=q; grid[ix/4][iy/4+g]=q; grid[ix/4][iy/4-g]=q; grid[ix/4+g][iy/4+g]=q; grid[ix/4-g][iy/4-g]=q; grid[ix/4+g][iy/4-g]=q; grid[ix/4-g][iy/4+g]=q; } } /* noStroke(); ellipseMode(CENTER_DIAMETER); fill(0, 0, 220); ellipse(lSensorX, lSensorY, 3, 3); ellipse(rSensorX, rSensorY, 3, 3); */ } } /////END VEHICLE CLASS//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // --------------- M A K E V E H I C L E S ----- called in the Setup ------------------------------- // Initialize all the vehicle data randomly void makeVehicles() { for (int i = 0; i < NUM_VEHICLES; i++) { vehicles[i] = new Vehicle(0); } } // --------------- C A L C U L A T E N E X T V E H I C L E S T A T E S -------------- // Loop through and calculate the next state for each vehicle void calculateNextVehicleStates() { for (int i = 0; i < NUM_VEHICLES; i++) { vehicles[i].calculateNextState(); } } // --------------- U P D A T E V E H I C L E S T A T E S -------------- // Loop through and give each vehicle its next state void updateVehicleStates() { for (int i = 0; i < NUM_VEHICLES; i++) { vehicles[i].updateState(); } } // -------------- D R A W I M A G E ------------------------------------ // Draw the background image (continuously effaced with trails) void drawImage() { //original code //System.arraycopy(BImage.pixels , 0, pixels, 0, X_SIZE*Y_SIZE); //works #1 //bgImage = loadImage(imageName); //System.arraycopy(bgImage.pixels , 0, pixels, 0, X_SIZE*Y_SIZE); //works #2 //bgImage = loadImage(imageName); //image(bgImage, 0, 0); } // --------------- D R A W V E H I C L E S ------------------------------ // Draw each vehicle void drawVehicles() { for (int i = 0; i < NUM_VEHICLES; i++) { vehicles[i].draw(); } } //////////////////--------------U P D A T E C E L L U L A R S T A T E S A N D D R A W C E L L S -----------------------------------///////////////////// void update_cellular_state_and_draw_cells() { //--------Update Cellular States--------// //based on a 100 by 100 unit grid //each unit checked to see if it = 1 for(int x=0;x<100;x++) { for(int y=0;y<100;y++) { if (grid[x][y]==1) { //--------Draw Cells--------// color c = color(int(random(75,204)), int(random(5,25)), int(random(155,204))); set(x*4,y*4,c); for(int i=0;i<4;i++) { set(x*4+i,y*4,c); set(x*4-i,y*4,c); set(x*4,y*4+i,c); set(x*4,y*4-i,c); set(x*4+i,y*4+i,c); set(x*4-i,y*4-i,c); set(x*4+i,y*4-i,c); set(x*4-i,y*4+i,c); } /* float cell_color = random(150); noStroke(); fill(255,0,cell_color,random(80)); //keeps things within 200, 200 //if x = 100, the rect is at 200 rect(x*4,y*4,8,8); */ } } } } //////////////////--------------C A L C U L A T E N E X T C E L L U L A R S T A T E S -----------------------------------///////////////////// void calc_next_cellular_state() { //------Calculate Next Cellular States---------// int neighbour = 0; //keeps the simulation within the boundaries for(int x=1;x<99;x++) { for(int y=1;y<99;y++) { //assign a value to be incremented to variable 'neighbour' neighbour = 0; if (grid[x-1][y]==1) { neighbour++; } if (grid[x-1][y-1]==1) { neighbour++; } if (grid[x][y-1]==1) { neighbour++; } if (grid[x+1][y-1]==1) { neighbour++; } if (grid[x+1][y]==1) { neighbour++; } if (grid[x-1][y+1]==1) { neighbour++; } if (grid[x][y+1]==1) { neighbour++; } if (grid[x+1][y+1]==1) { neighbour++; } if (neighbour==3) { grid[x][y]=1; } else if ((neighbour==2)&&(grid[x][y]==1)) { grid[x][y]=1; } else { grid[x][y]=0; } if (mousePressed == true) { m_x = mouseX; m_y = mouseY; //keep mouse cursor from going outside the bounds of the grid array if (m_x > 360) { m_x = 360; }else if (m_x < 40) { m_x = 40; }else if (m_y > 360) { m_y = 360; }else if (m_y < 40) { m_y = 40; }else { //Draw cells with mouse pressed int q = 1; grid[m_x/4][m_y/4]=q; for(int g=0;g<3;g++){ grid[m_x/4+g][m_y/4]=q; grid[m_x/4-g][m_y/4]=q; grid[m_x/4][m_y/4+g]=q; grid[m_x/4][m_y/4-g]=q; grid[m_x/4+g][m_y/4+g]=q; grid[m_x/4-g][m_y/4-g]=q; grid[m_x/4+g][m_y/4-g]=q; grid[m_x/4-g][m_y/4+g]=q; } } } } } }