// Processing source code : Braitenberg's Vehicles // Based on program written by william ngan Vehicle[] robots; Source[] sources; boolean mouseDown; PImage ground; boolean bounded = true; // vehicles run into world boundary (if true), wrap around (if false) int numOfLights = 2; int numOfRobots = 3; float move_speed = PI/6; void setup() { size( 300, 300 ); framerate( 30 ); ellipseMode( CENTER ); rectMode( CENTER ); noStroke(); ground = new PImage( width, height ); robots = new Vehicle[10]; for (int i=0; i='1' && key<='5') { numOfLights = 5-('5'-key); updateGround(); } if (key==CODED) { if (keyCode==UP) { numOfRobots++; numOfRobots = min( numOfRobots, robots.length-1 ); } else if (keyCode==DOWN) { numOfRobots--; numOfRobots = max( numOfRobots, 1 ); } } } void updateGround() { float sum; int c; int px = 5; color cc; ground = new PImage(width, height); for (int i=0; i=1) break; } c = (int)min(sum*255, 255); for (int p=0; pwidth) ? x-width : x ); y = ( y<0 ) ? height+y : ((y>height) ? y-height : y ); } } void checkCollision() { float dx, dy, da; for (int i=0; iTWO_PI) angle -= TWO_PI; float temp = sin(angle)*HALF_PI+ainc; ellipse( x+cos(temp)*10*dir, y+sin(temp)*10*dir, 20, 20 ); } } class Sensor { float x, y; float maxReading; float sense; Sensor( float x, float y ) { this.x = x; this.y = y; maxReading = 1; } void setLocation( float x, float y ) { this.x = x; this.y = y; } /* float getSense(boolean plus) { float sum = red( ground.get( (int)x, (int)y ) )/255.0; sum = (plus) ? sum : 1-sum; sense = (specialSense) ? nonlinear( sum, maxReading ) : 1-sum; return sense; }*/ // This is an example of non-linear threshhold sensing. Returns 0 // until the normalized sensory value = 0.5, then returns a linear value // between 0.5 and 1. float getNonlinearSense() { float val = red( ground.get( (int)x, (int)y ) )/255.0; if (val < 0.5) return 0; else return val; } // Returns 0 when sensory value is maximum, 1 when it's minimum float getInverseSense() { float val = red( ground.get( (int)x, (int)y ) )/255.0; sense = 1 - val; return sense; } // Returns 1 when sensory value is maximum, 0 when it's minimum float getSense() { sense = red( ground.get( (int)x, (int)y ) )/255.0; return sense; } void drawMe() { fill(255); ellipse( x, y, 16, 16 ); fill(200*sense,0,0); ellipse( x, y, 7, 7 ); } } class Source { float x, y; float strength; // between 0 to 1 float max_radius; boolean dragging = true; int id; Source( float x, float y, float strength, float max_radius, int id ) { this.x = x; this.y = y; this.strength = strength; this.max_radius = max_radius; this.id = id; } void setLocation( float x, float y ) { this.x = x; this.y = y; } void drawMe() { if (id < numOfLights ) { checkCollision(); // dragging? if (mouseDown && mouseX>x-10 && mouseXy-10 && mouseY= max_radius) return ((plus) ? 0 : 1); // Strength of source falls of linearly in distance (up to max_radius) from source // d = strength*(d/max_radius); // Strength of source falls off as a function of the cosine of distance (up to max_radius) from source d = 1-nonlinear( d, max_radius ); return ((plus) ? 1-d : d ); } } // Returns a value between 0 and 1 (assume r & rmax >= 0) // Returns 0 if r is >= rmax // Returns 1 if r = 0 float nonlinear(float r, float rmax) { float f = (rmax - Math.min(r, rmax)) / rmax; return 0.5 - 0.5*cos(f*PI); } void mousePressed() { mouseDown = true; } void mouseReleased() { mouseDown = false; updateGround(); }