//============================================================================= //=============ambient_light=======annie spinster========2006================== //============================================================================= //----------------------------------------------------------------------------- //Processing code: //----------------------------------------------------------------------------- //opengl is the graphics accelerator import processing.opengl.*; //the serial library allows communication with an external device import processing.serial.*; //declare a Serial object Serial port; //all the energy points in the system float totalEnergy = 4000; //no class of creature has any points at the start float plantEnergy = 0; float preyEnergy = 0; float predEnergy = 0; float scavEnergy = 0; float insEnergy=0; //prey appear when plantEnergy==preyTrigger etc. int preyTrigger = 200; int predTrigger = 600; //keep track of insect and egg populations int eggPop=0; int insPop=0; //set maximum population levels for each class int maxPlant = 400; int maxPrey = 50; int maxPred = 9; int maxScav = 6; int maxIns = 50; //bug fix: see setup int electro = 0; //more variables... float energyStore, diagonal, insX, insY; int bgb,bgh,bgs,scavPop,predPop, preyPop, val, chaira, chairb, chairc, chaird, chaire, chairf; //changeCount, moved, all there and regen are used for insect regeneration, wipeout happens when //all plants are infected boolean changeCount=false; boolean moved = false; boolean allThere, regen, wipeOut; //make some arrays to hold each instance of each class Plant[] plant = new Plant[maxPlant]; Prey[] prey = new Prey[maxPrey]; Pred[] pred = new Pred[maxPred]; Scav[] scav = new Scav[maxScav]; Ins[] ins = new Ins[maxIns]; InsEgg[] insEgg = new InsEgg[maxIns]; Para[] para = new Para[6]; //============================================ void setup(){ //bugfix: before I put this "if" in it listed the serial array 1 1/2 times and so could not find the right port if(electro==0){ //list all available ports and set the second in the list as the one connected to the wiring board println(Serial.list()); port = new Serial(this, Serial.list()[1], 9600); electro++; } //the insects have not regenerated yet and the world is not doomed regen=false; wipeOut=false; //full screen size(screen.width,screen.height, OPENGL); //changing framerate can alter the whole dynamic of the system // as some events depend on frameCount and some on the computer's clock framerate(20); //I found HSB colour mode easier to work with for changing the background colorMode(HSB, 360, 100, 100); smooth(); background(0); //background hue starts out red bgh=0; setInsPos(); //all the energy points are in energyStore energyStore = totalEnergy; //the screen diagonal is used as the starting point for judging distances between creatures diagonal = dist(0,0,width,height); //there are no scavs, preds or prey scavPop = 0; predPop = 0; preyPop = 0; //there is one plant and it knows its own name plant[0] = new Plant(); plant[0].itsName = 0; } //================================================ void draw(){ //if the port can be read by Processing if(0=33)&&(val<=48))){ chairb=1; } if((val<=8)||((val>=17)&&(val<=24))||((val>=33)&&(val<=40))||((val>=49)&&(val<=56))){ chairc=1; } if((val<=4)||((val>=9)&&(val<=12))||((val>=17)&&(val<=20))||((val>=25)&&(val<=28))||((val>=33)&&(val<=36))||((val>=41)&&(val<=44))||((val>=49)&&(val<=52))||((val>=57)&&(val<=60))){ chaird=1; } if((val==1)||(val==2)||((val%4)==1)||((val%4)==2)){ chaire=1; } if((val==1)||((val%2)==1)){ chairf=1; } } } //each occupied chair creates a parasitic spore cloud //if the chair is unoccupied the cloud goes away //each instance knows its name if(chaira==1){ if(para[0]==null){ para[0]=new Para(); para[0].itsName=0; } } else{ para[0]=null; } if(chairb==1){ if(para[1]==null){ para[1]=new Para(); para[1].itsName=1; } } else{ para[1]=null; } if( chairc==1){ if(para[2]==null){ para[2]=new Para(); para[2].itsName=2; } } else{ para[2]=null; } if(chaird==1){ if(para[3]==null){ para[3]=new Para(); para[3].itsName=3; } } else{ para[3]=null; } if(chaire==1){ if(para[4]==null){ para[4]=new Para(); para[4].itsName=4; } } else{ para[4]=null; } if(chairf==1){ if(para[5]==null){ para[5]=new Para(); para[5].itsName=5; } } else{ para[5]=null; } //background brightness varies depending on the value of energyStore, but is always above 25% int nbgb=int(25+((energyStore*75)/totalEnergy)); if(nbgb>bgb){ bgb++; } else if(nbgbpreysuc)&&(plantsuc>predsuc)&&(plantsuc>scavsuc)){ if((bgh>27)&&(bgh<207)){ bgh--; } else if((bgh<27)||(bgh>=207)){ bgh++; if(bgh>=360){ bgh-=360; } } } //or if prey are the most sucessful move background hue towards bluey purple else if((preysuc>plantsuc)&&(preysuc>predsuc)&&(preysuc>scavsuc)){ if((bgh>275)||(bgh<95)){ bgh--; if(bgh<=0){ bgh+=360; } } else if((bgh<275)&&(bgh>=95)){ bgh++; } } //etc... else if((predsuc>plantsuc)&&(predsuc>preysuc)&&(predsuc>scavsuc)){ if((bgh>110)&&(bgh<290)){ bgh--; } else if((bgh<110)||(bgh>=290)){ bgh++; if(bgh>=360){ bgh-=360; } } } else if((scavsuc>plantsuc)&&(scavsuc>preysuc)&&(scavsuc>predsuc)){ if((bgh>5)&&(bgh<185)){ bgh--; } else if((bgh<5)||(bgh>=185)){ bgh++; if(bgh>=360){ bgh-=360; } } } //once background hue, saturation and brightness have been calculated the background can be filled background(bgh,bgs,bgb); //if there are no plants, or all remaining plants are dying of starvation, make a new plant if(plantEnergy==0){ for(int i=0; i0)&&(allThere==true)&&(regen==false)){ //insRegen is the egg-laying event. regen is used to make sure they only do it once insRegen(); regen=true; } //if the eggs have hatched, or there are no eggs, changeCount is set to false if((eggPop==0)&&(changeCount==true)){ changeCount = false; } if((moved==false)&&(eggPop==0)){ setInsPos(); moved=true; } else if((moved==true)&&(insPop==0)){ moved=false; } //when the eggs have been laid, counter is reset, and changeCount becomes true if((insPop==0)&&(changeCount==false)){ for(int i=0; i=preyTrigger)&&(preyEnergy==0)){ for(int i = 0; i=predTrigger)&&(predEnergy==0)){ for(int i = 0; i0){ //if it is in a symbiotic relationship and there are more than 3 available energy points if((sym==true)&&(prey[symprey]!=null)&&(energyStore>3)){ //it takes 2 points from energyStore, gives one to its symprey and keeps one prey[symprey].energy++; preyEnergy++; energy++; plantEnergy ++; energyStore-=2; } //all plants then take a point from the energyStore. If sym==true, it has now taken two points for itself //and one for its symprey energy++; plantEnergy ++; energyStore--; } //if there is no available energy... else{ //if it is in a symbiotic relationship and its symprey has at least 2 points if((sym==true)&&(prey[symprey]!=null)&&(prey[symprey].energy>=2)){ //it takes a point from its symprey prey[symprey].energy--; preyEnergy--; energy++; plantEnergy++; } //if its not in a symbiotic relationship it loses a point back to the energyStore else if(sym==false){ energy-=1; plantEnergy-=1; energyStore+=1; } } //if it is in a symbiotic relationship and has at least 4 points, //or if it has at least 6 points and the world is not doomed, it has a baby if((((sym==true)&&(energy>=4))||(energy>=6))&&(wipeOut==false)){ plant[itsName].birth(); } //if it is old or has run out of energy it begins to die. It is no longer in a symbiotic relationship if((itsAge>=lifeSpan)||(energy<=0)){ dying = true; sym=false; } } //if it is in a symbiotic relationship its position on screen is the same as that of its symprey if((symprey!=(maxPrey+1))&&(sym==true)&&(prey[symprey]!=null)){ xpos=prey[symprey].xpos; ypos=prey[symprey].ypos; } //flock controls the general movement of plants else{ flock(); //these ifs stop it going off-screen or too near the bottom if(xpos<0){ xpos += 3; ypos += random(-2,2); } else if (xpos>width){ xpos -= 3; ypos += random(-2,2); } else if (ypos<0){ ypos += 3; xpos += random(-2,2); } else if (ypos>((2*height)/3)){ ypos -= 3; xpos += random(-2,2); } } } //infected plants get darker and start pulsing if((infected==true)&&(dying==false)){ itsBright-=2; if(itsBright<40){ itsBright=int(random(45,55)); } } //draw a circle and colour it in fill(itsHue, itsSat, itsBright, itsAlpha); stroke(itsHue, itsSat, (itsBright-20),itsAlpha); ellipse (xpos, ypos, itsWidth, itsWidth); } //-------------------------------------------------------------------------------------- //plant void birth(){ //find a gap in the plants array, make a new plant in that position and tell it its name for(int i = 0; i<(maxPlant-1); i++){ if (plant[i] == null){ plant[i] = new Plant(); plant[i].itsName = i; //if the parent is infected the baby will be too if(infected==true){ plant[i].infected=true; } float birthPlace = random(1); //plants have a 97.5% chance of being born next to their parent //(xpos and ypos have already been set as random in the plant constructor) if(birthPlace>0.025){ plant[i].xpos = xpos+(itsAge/2); plant[i].ypos = ypos; } //the energy cost of reproduction: the parent gives a point to the baby //and loses two more points to energyStore plant[i].energy ++; energy -= 3; plantEnergy -=2; energyStore+= 2; break; } } } //--------------------------------------------------------------------------------- //plant void die(){ //if it is in symbiosis then the relationship is dissolved and the symprey is //returned to its independent state if(sym==true){ prey[symprey].itsHue = prey[symprey].origHue; prey[symprey].sym=false; prey[symprey].symplant=(maxPlant+1); sym=false; } //it falls slowly down the screen becoming more and more transparent ypos += (1 +random(2)); if(itsAlpha>2){ itsAlpha--; } //if it falls through a parasitic cloud it becomes infected for(int i =0;i<6;i++){ if(para[i]!=null){ if((ypos>para[i].ypos)&&((xpos<(para[i].xpos+(para[i].itsWidth/2)))&&(xpos>(para[i].xpos-(para[i].itsWidth/2))))){ if(infected==false){ infected=true; } } } } //when it reaches the bottom it gives any remaining energy back to energyStore and deletes itself if(ypos>=height){ energyStore += energy; plantEnergy -= energy; plant[itsName] = null; } } //------------------------------------------------------------------------ //plant void flock(){ int minJiggle,maxJiggle; //plants jiggle more if they're infected if(infected==true){ minJiggle=-2; maxJiggle=2; } else{ minJiggle=-1; maxJiggle=1; } float drift = random(1); if(drift>0.66){ //plants have a tendency to drift away from the viewers: if more chairs are occupied //on the right than the left then plants will tend to drift left etc if(((chaira+chairb+chairc)>(chaird+chaire+chairf))&&(xpos<(width-(width/5)))){ xpos++; } else if(((chaira+chairb+chairc)<(chaird+chaire+chairf))&&(xpos>(width/5))){ xpos--; } if(((chairc+chaird)>(chaira+chairf))&&(ypos>(height/10))){ ypos--; } else if(((chairc+chaird)<(chaira+chairf))&&(ypos<(7*height)/12)){ ypos++; } } //clumping is achieved by enabling isolated plants to drift towards //their nearest neigbour. Clumps are kept loose by making the ideal //distance between plants 4 times their age findNearestPlant(); flockDistance = itsAge*4; if(plant[nearestPlant]!=null){ if(plant[nearestPlant].xpos>(xpos+flockDistance)){ xpos++; } else if(plant[nearestPlant].xpos<(xpos-flockDistance)){ xpos--; } if(plant[nearestPlant].ypos>(ypos+flockDistance)){ ypos++; } else if(plant[nearestPlant].ypos<(ypos-flockDistance)){ ypos--; } //if they're in more or less the right place they just jiggle a bit else{ xpos+=random(minJiggle,maxJiggle); ypos+=random(minJiggle,maxJiggle); } } } //-------------------------------------------------------------------------------------- //plant int findNearestPlant(){ //set initial nearestDistance as the longest possible straight line on screen float nearestDistance =diagonal; for(int i = 0; i<(maxPlant); i++){ //the distance to each plant in turn (except dying plants and itself) is //compared to nearestDistance. If the distance is shorter than nearestDistance //then that plant becomes nearestPlant, and its distance is the new nearestDistance if((plant[i] != null)&&(i != itsName)&&(plant[i].dying==false)){ float distance = dist(xpos, ypos, plant[i].xpos, plant[i].ypos); if (distance < nearestDistance){ nearestPlant = i; nearestDistance = distance; } } } //when it's cycled through all the plants it knows which is the nearest and returns that return nearestPlant; } } //=========================================================== //prey, or herbivores... class Prey { int itsName, energy, lifeSpan,itsAge, itsWidth, maxWidth, randomX, randomY, seconds, nearestPlant,nearestPrey, nearestPred, flockDistance, hungry, itsHue, itsBright, itsSat, itsAlpha, symplant, origHue; float xpos, ypos, angle, xdiff, ydiff; boolean dying, running, dieClock, infected, sym; Prey(){ itsWidth = 0; //angle is used to determine which way the prey is facing. //it is set randomly at birth angle = random(-PI,PI); //they are born in a random spot in the top 2/3 of the screen //this is reset in the birth method so that only the first //prey on screen is born in a random spot xpos = random(width); ypos = random((2*height)/3); //randomX, randomY are used in "wander" randomX = int(xpos); randomY = int(ypos); itsAge = 0; seconds = second(); dying = false; //prey know whether they are running away or not running = false; infected = false; itsAlpha = 255; //they get hungry when they have 9 or fewer energy points hungry = 9; //they are bluey purple itsHue = int(random(250,300)); //they remember their original colour so they can revert //to this shade if a symbiotic relationship ends origHue = itsHue; itsSat = int(random(70,90)); itsBright = int(random(90,100)); //born with 10 energy points energy = 10; preyEnergy += energy; //symplant holds the name of a plant in symbiotic relationship with the prey //for now, this is set as outside the plant array ie a non-existant plant symplant =(maxPlant+1); //the 10 energy points it is born with are taken from 10 plants at random int i = energy; while(i>0){ int randomPlant = int(random(maxPlant-1)); if((plant[randomPlant] != null)&&(plant[randomPlant].energy>0)){ plant[randomPlant].energy--; plantEnergy--; i--; } } //they live for 30-50 seconds lifeSpan = 30+int(random(20)); //they grow up to 25-40 px in width maxWidth = int(random(25,40)); //dieClock determines whether they spin clockwise or anticlockwise //when they die or become infected. There is an equal chance for each option float rn = random(-1,1); if(rn<0){ dieClock=true; } else{ dieClock=false; } } //------------------------------------------------------------------- //prey //see plant.birth as they're almost identical void birth(){ for(int i = 0; i<(maxPrey-1); i++){ if (prey[i] == null){ prey[i] = new Prey(); prey[i].itsName = i; if(infected==true){ //they have a roughly 50% chance of infecting offspring float inherit = random(1); if(inherit>0.5){ prey[i].infected=true; } } //they are always born next to the parent prey[i].xpos = xpos+(itsAge/2); prey[i].ypos = ypos; //cost of reproduction: 6 points from the parent and 1 point from the //baby are returned to the energy store prey[i].energy --; energy -= 6; preyEnergy -=7; energyStore+=7; preyPop++; break; } } } //------------------------------------------------------------------- //prey void update (){ //if it's in symbiosis with a plant if(sym==true){ //it gets hungry when it has 12 points or less - ie a lot sooner hungry=12; //check to make sure symPlant is still there and is not dying //if it has gone or is dying the relationship ends and the prey returns to its original colour if((plant[symplant]==null)||(plant[symplant].dying==true)){ sym=false; itsHue=origHue; } } //each 25 frames(just over a second at 20 fps if the program is running at full speed) //a new random point on screen is chosen. this is where the prey will head towards when wandering if(frameCount%25==0){ randomX = int(random(width)); randomY = int(random((height*2)/3)); } if(dying == true){ die(); } else{ //birthday...see plant.update. NB prey do not age while they are //running away, otherwise they have a tendency to die before they are caught by preds. if((seconds != second())&&(running==false)){ itsAge ++; if(itsWidth=3)){ plant[symplant].energy--; plantEnergy--; energy++; preyEnergy++; } } //if it's not in a symbiotic relationship, it stays its original colour else{ itsHue=origHue; } //if it has at least 14 points it has a baby if(energy>=14){ birth(); } //if it gets old or runs out of energy it dies if((itsAge>=lifeSpan)||(energy<=0)){ dying = true; } } //infected prey are doomed to wander until they die if(infected==true){ wander(); } //if its not infected... else{ //runAway includes looking for predators and setting the //value of "running" runAway(); //if it's not running away... if(running==false){ //and it's not hungry or there's no food it wanders around if((energy>hungry)||(plantEnergy==0)){ wander(); } //if it's hungry and there's food it hunts else{ hunt(); } } } //this stops it going off screen or too near the bottom if(xpos<0){ xpos += 3; ypos += random(-2,2); } else if (xpos>width){ xpos -= 3; ypos += random(-2,2); } else if (ypos<0){ ypos += 3; xpos += random(-2,2); } else if (ypos>(2*height)/3){ ypos -= 3; xpos += random(-2,2); } } //this draws the prey on screen. I only have a hazy idea of how pushMatrix //and popMatrix work. The creatures are drawn as a set of overlapping shapes //in this case, a purple ellipse with a smaller black ellipse on top. //pushMatrix and popMatrix enable me to move both shapes together as a single object pushMatrix(); stroke(itsHue, itsSat, (itsBright-20), itsAlpha); translate(xpos,ypos); if(running==true){ rotate(135); } rotate(angle); ellipseMode(CENTER); fill(itsHue, itsSat, itsBright, itsAlpha); rotate(radians(90)); ellipse (0, 0, (itsWidth/2),itsWidth); stroke(0,0,0,itsAlpha); fill(0,0,0,itsAlpha); ellipse (0,((itsWidth/4)*-1),(itsWidth/4), (itsWidth/2)); popMatrix(); } //---------------------------------------------------------------------------------- //prey //see plant.die void die(){ if(sym==true){ plant[symplant].sym=false; plant[symplant].symprey=(maxPrey+1); sym=false; symplant=(maxPlant+1); } xpos += int(random(-1,+1)); ypos += (1 +random(2)); if(itsAlpha>2){ itsAlpha--; } for(int i =0;i<6;i++){ if(para[i]!=null){ if((ypos>para[i].ypos)&&((xpos<(para[i].xpos+(para[i].itsWidth/2)))&&(xpos>(para[i].xpos-(para[i].itsWidth/2))))){ if(infected==false){ infected=true; } } } } //if it's going clockwise it adds 2 degrees to its angle, if it's going anticlockwise it subtracts 2 degrees float deg = degrees(angle); if(dieClock==true){ deg+=2; if(deg>=360){ deg-=360; } } else{ deg-=2; if(deg<=0){ deg+=360; } } //reset angle angle = radians(deg); if(ypos>=height){ energyStore += energy; preyEnergy -=energy; prey[itsName] = null; preyPop--; } } //---------------------------------------------------------------------------------------------- //prey void hunt(){ float huntDist; int nextTo; int addX = 0; int addY = 0; findNearestPlant(); //if there are any plants... if(plant[nearestPlant]!=null){ //huntDist is the distance to the nearest plant huntDist = dist(xpos,ypos,plant[nearestPlant].xpos,plant[nearestPlant].ypos); //nextTo is what the distance must be before the plant is caught nextTo = int((itsWidth/2)+(plant[nearestPlant].itsAge/2)); //if the prey has reached the nearest plant... if(huntDist <= nextTo){ //prey become infected by eating infected plants if(plant[nearestPlant].infected==true){ infected=true; } //the prey takes the plant's energy and the plant ceases to exist energy += plant[nearestPlant].energy; plantEnergy -= plant[nearestPlant].energy; preyEnergy += plant[nearestPlant].energy; plant[nearestPlant] = null; } //if it hasn't reached the plant yet... else{ findNearestPrey(); //if there are any other prey around find the distance to the nearest one if(prey[nearestPrey]!=null){ float preyDist = dist(xpos, ypos, prey[nearestPrey].xpos, prey[nearestPrey].ypos); //if they are overlapping or very close together addX and addY are set to 3. This will //allow them to hunt faster as a group if(preyDist<=((itsAge/2)+(prey[nearestPrey].itsAge/2))){ addX = 3; addY = 3; } } //atan2 is used to calculate a new xpos and ypos each frame //along the shortest path to the nearest plant. float atany = plant[nearestPlant].ypos-ypos; float atanx = plant[nearestPlant].xpos-xpos; angle = atan2(atany, atanx); if(plant[nearestPlant].xpos>xpos){ xdiff=atanx; } else{ xdiff=xpos-plant[nearestPlant].xpos; } if(plant[nearestPlant].ypos>ypos){ ydiff=atany; } else{ ydiff=ypos-plant[nearestPlant].ypos; } //changing the value in the conditional brackets changes the hunting speed //xdiff and ydiff are continuously multiplied by 9/10 until the value is less than 5 while((xdiff>5)||(ydiff>5)){ xdiff=(xdiff*9)/10; ydiff=(ydiff*9)/10; } //make sure the prey moves towards and not away from the plant if(xpos>plant[nearestPlant].xpos){ xdiff=(xdiff*-1); addX=(addX*-1); } if(ypos>plant[nearestPlant].ypos){ ydiff=(ydiff*-1); addY=(addY*-1); } //the new position is calculated xpos+=(xdiff+addX); ypos+=(ydiff+addY); } } //if there are no plants just wander about else{ wander(); } } //----------------------------------------------------------------------------- //prey void runAway(){ findNearestPred(); //if there are any preds... if(pred[nearestPred]!=null){ //find the distance to the nearest pred float d=dist(xpos,ypos,pred[nearestPred].xpos,pred[nearestPred].ypos); //runDistance is how close the nearest pred has to be before the prey runs away float runDistance = (itsWidth/2)+(pred[nearestPred].itsAge/2)+20; //if they are close enough a new xpos and ypos are calculated using atan2 to find //the most direct path between them. This enables the prey to move directly away from the pred if(d<= runDistance){ running = true; float atany = pred[nearestPred].ypos-ypos; float atanx = pred[nearestPred].xpos-xpos; angle = atan2(atany, atanx); if(pred[nearestPred].xpos>xpos){ xdiff=atanx; } else{ xdiff=xpos-pred[nearestPred].xpos; } if(pred[nearestPred].ypos>ypos){ ydiff=atany; } else{ ydiff=ypos-pred[nearestPred].ypos; } //changing the 6 in brackets changes the running away speed while((xdiff>6)||(ydiff>6)){ xdiff=(xdiff*9)/10; ydiff=(ydiff*9)/10; } if(xpos=360){ deg-=360; } } else{ deg-=30; if(deg<=0){ deg+=360; } } angle = radians(deg); } //if not infected, atan2 is used to find a straight line path to the random point else{ angle = atan2(atany, atanx); } if(randomX>xpos){ xdiff=atanx; } else{ xdiff=xpos-randomX; } if(randomY>ypos){ ydiff=atany; } else{ ydiff=ypos-randomY; } //if the prey is in symbiosis it wanders faster if(sym==true){ while((xdiff>4)||(ydiff>4)){ xdiff=(xdiff*9)/10; ydiff=(ydiff*9)/10; } } else{ while((xdiff>1.5)||(ydiff>1.5)){ xdiff=(xdiff*9)/10; ydiff=(ydiff*9)/10; } } //makes sure the prey moves towards and not away from the random point if(xpos>randomX){ xdiff=(xdiff*-1); } if(ypos>randomY){ ydiff=(ydiff*-1); } //the new position is set xpos+=xdiff; ypos+=ydiff; } } //----------------------------------------------------------------------------------------- //prey //symbiosis is very similar to hunt void symbiosis(){ float huntDist; int nextTo; int addX = 0; int addY = 0; huntDist = dist(xpos,ypos,plant[nearestPlant].xpos,plant[nearestPlant].ypos); nextTo = int((itsWidth/2)+(plant[nearestPlant].itsAge/2)); //when the prey reaches the infected plant if(huntDist <= nextTo){ //sym is true for both parties sym=true; plant[nearestPlant].sym=true; //the plant has 10 seconds added to its lifespan plant[nearestPlant].lifeSpan+=10; //they introduce themselves to each other symplant=plant[nearestPlant].itsName; plant[nearestPlant].symprey=itsName; } //if it hasn't yet reached the plant it moves towards it along a straight line path else{ float atany = plant[nearestPlant].ypos-ypos; float atanx = plant[nearestPlant].xpos-xpos; angle = atan2(atany, atanx); if(plant[nearestPlant].xpos>xpos){ xdiff=atanx; } else{ xdiff=xpos-plant[nearestPlant].xpos; } if(plant[nearestPlant].ypos>ypos){ ydiff=atany; } else{ ydiff=ypos-plant[nearestPlant].ypos; } while((xdiff>5)||(ydiff>5)){ xdiff=(xdiff*9)/10; ydiff=(ydiff*9)/10; } if(xpos>plant[nearestPlant].xpos){ xdiff=(xdiff*-1); addX=(addX*-1); } if(ypos>plant[nearestPlant].ypos){ ydiff=(ydiff*-1); addY=(addY*-1); } xpos+=(xdiff+addX); ypos+=(ydiff+addY); } } //----------------------------------------------------------------------------------------- //prey //this is almost the same as plant.findNearestPlant except that //if the prey is in symbiosis it will ignore infected plants int findNearestPlant(){ float nearestDistance =diagonal; if(sym==false){ for(int i = 0; i<(maxPlant); i++){ if((plant[i]!=null)&&(plant[i].dying==false)&&(plant[i].sym==false)){ float distance = dist(xpos, ypos, plant[i].xpos, plant[i].ypos); if (distance < nearestDistance){ nearestPlant = i; nearestDistance = distance; } } } return nearestPlant; } else{ for(int i = 0; i<(maxPlant); i++){ if((plant[i] != null)&&(plant[i].dying==false)&&(plant[i].infected==false)&&(plant[i].sym==false)){ float distance = dist(xpos, ypos, plant[i].xpos, plant[i].ypos); if (distance < nearestDistance){ nearestPlant = i; nearestDistance = distance; } } } return nearestPlant; } } //------------------------------------------------------------------------------- //prey //see plant.findNearestPlant int findNearestPrey(){ float nearestDistance =diagonal; for(int i = 0; i<(maxPrey); i++){ if ((prey[i] != null)&&(i != itsName)&&(prey[i].dying==false)){ float distance = dist(xpos, ypos, prey[i].xpos, prey[i].ypos); if (distance < nearestDistance){ nearestPrey = i; nearestDistance = distance; } } } return nearestPrey; } //---------------------------------------------------------------------------------- //prey //see plant.findNearestPlant int findNearestPred(){ float nearestDistance =diagonal; for(int i = 0; i<(maxPred); i++){ if ((pred[i] != null)&&(pred[i].dying==false)){ float distance = dist(xpos, ypos, pred[i].xpos, pred[i].ypos); if (distance < nearestDistance){ nearestPred = i; nearestDistance = distance; } } } return nearestPred; } } //=========================================================== //all the classes are quite similarly constructed - see class Plant class Pred { int itsName, energy, lifeSpan, itsAge, itsWidth, maxWidth, seconds, nearestPlant, nearestPrey, nearestPred, flockDistance, hungry, itsHue, itsBright, itsSat, itsAlpha, randomX, randomY; float xpos, ypos, angle, xdiff, ydiff; boolean dying, dieClock, infected; Pred(){ itsWidth=0; angle = random(-PI,PI); xpos = random(width); ypos = random((2*height)/3); randomX=int(random(width)); randomY=int(random((2*height)/3)); itsAge = 0; seconds = second(); dying = false; infected = false; itsAlpha = 255; hungry = 14; itsHue = int(random(80,140)); itsSat = int(random(80,100)); itsBright = int(random(30,70)); energy = 0; //preds take 15 energy points from random prey int i = 0; while(i<15){ int randomPrey = int(random(maxPrey-1)); if((prey[randomPrey] != null)&&(prey[randomPrey].energy>0)){ prey[randomPrey].energy--; energy++; preyEnergy--; predEnergy++; i++; } } lifeSpan = 50+int(random(10)); maxWidth = int(random(40,lifeSpan)); float rn = random(-1,1); if(rn<0){ dieClock=true; } else{ dieClock=false; } } //------------------------------------------------------------------------- //pred //see plant.birth void birth(){ for(int i = 0; i<(maxPred-1); i++){ if (pred[i] == null){ pred[i] = new Pred(); pred[i].itsName = i; //there is a 50% chance of an infected parent passing on the parasite if(infected==true){ float inherit = random(1); if(inherit>0.5){ pred[i].infected=true; } } pred[i].xpos = xpos+(itsAge/2); pred[i].ypos = ypos; //cost of reproduction: parent loses 8 points, baby loses 2 pred[i].energy -=2; energy -= 8; predEnergy -=10; energyStore+=10; predPop++; break; } } } //---------------------------------------------------------------------------------- //pred //see plant.update and prey.update void update (){ if(dying == true){ die(); } else{ if(seconds != second()){ itsAge ++; if(itsWidth=25)&&(preyEnergy>15)){ birth(); } } else{ if((energy>=20)&&(preyEnergy>15)){ birth(); } } if((itsAge>=lifeSpan)||(energy<=0)){ dying = true; } } hunt(); if(xpos<0){ xpos += 1; ypos += random(-2,2); } else if (xpos>width){ xpos -= 1; ypos += random(-2,2); } else if (ypos<0){ ypos += 1; xpos += random(-2,2); } else if (ypos>(2*height)/3){ ypos -= 1; xpos += random(-2,2); } } //infected preds become drained of colour if((infected==true)&&(dying==false)){ itsSat--; } //what it looks like - see prey.update pushMatrix(); stroke(itsHue, itsSat,(itsBright-20),itsAlpha); translate(xpos,ypos); rotate(angle); ellipseMode(CENTER); fill(itsHue,itsSat,itsBright,itsAlpha); rotate(radians(270)); ellipse (0, 0,itsWidth ,(itsWidth/2)); fill(0,0,0,itsAlpha); ellipse(0,(itsWidth/8),(itsWidth/2),(itsWidth/4)); fill(itsHue,itsSat,(itsBright-20),itsAlpha); triangle(((itsWidth/8)*-1),(itsWidth/4),(itsWidth/8),(itsWidth/4),0,((itsWidth*2)/3)); translate(((itsWidth/6)*-1),((itsWidth/18)*-1)); rotate(radians(20)); triangle(((itsWidth/8)*-1),(itsWidth/4),(itsWidth/8),(itsWidth/4),0,(itsWidth/2)); translate((itsWidth/3),((itsWidth/8)*-1)); rotate(radians(315)); triangle(((itsWidth/8)*-1),(itsWidth/4),(itsWidth/8),(itsWidth/4),0,(itsWidth/2)); popMatrix(); } //------------------------------------------------------------------------ //pred //see prey.die and plant.die void die(){ xpos += int(random(-1,+1)); ypos += (2 +int(random(3))); if(itsAlpha>2){ itsAlpha-=2; } for(int i =0;i<6;i++){ if(para[i]!=null){ if((ypos>para[i].ypos)&&((xpos<(para[i].xpos+(para[i].itsWidth/2)))&&(xpos>(para[i].xpos-(para[i].itsWidth/2))))){ if(infected==false){ infected=true; } } } } float deg = degrees(angle); if(dieClock==true){ deg+=4; if(deg>=360){ deg-=360; } } else{ deg-=4; if(deg<=0){ deg+=360; } } angle = radians(deg); if(ypos>=height){ energyStore += energy; predEnergy -=energy; pred[itsName] = null; predPop--; } } //---------------------------------------------------------------------------- //pred //see prey.hunt void hunt(){ float huntDist; int nextTo; findNearestPrey(); if(prey[nearestPrey]!=null){ huntDist =dist(xpos,ypos,prey[nearestPrey].xpos,prey[nearestPrey].ypos); nextTo = int((itsAge/2)+(prey[nearestPrey].itsWidth/2)); if(energy<=hungry){ if(huntDist <= nextTo){ if(prey[nearestPrey].infected==true){ //when they become infected, preds lose 20 seconds from their lifespan //and suffer some loss of appetite infected=true; hungry+=4; lifeSpan-=20; } energy += prey[nearestPrey].energy; preyEnergy -= prey[nearestPrey].energy; predEnergy += prey[nearestPrey].energy; prey[nearestPrey] = null; preyPop--; } else{ float atany = prey[nearestPrey].ypos-ypos; float atanx = prey[nearestPrey].xpos-xpos; angle = atan2(atany, atanx); if(prey[nearestPrey].xpos>xpos){ xdiff=atanx; } else{ xdiff=xpos-prey[nearestPrey].xpos; } if(prey[nearestPrey].ypos>ypos){ ydiff=atany; } else{ ydiff=ypos-prey[nearestPrey].ypos; } //infected preds hunt a bit faster if(infected==true){ while((xdiff>8)||(ydiff>8)){ xdiff=(xdiff*9)/10; ydiff=(ydiff*9)/10; } } else{ while((xdiff>6)||(ydiff>6)){ xdiff=(xdiff*9)/10; ydiff=(ydiff*9)/10; } } if(xpos>prey[nearestPrey].xpos){ xdiff=(xdiff*-1); } if(ypos>prey[nearestPrey].ypos){ ydiff=(ydiff*-1); } xpos+=(xdiff+random(-2,2)); ypos+=(ydiff+random(-2,2)); } } else{ wander(); } } else{ wander(); } } //-------------------------------------------------------------------------- //pred //see plant.wander void wander(){ int intX=int(xpos); int intY=int(ypos); if((intX==randomX)&&(intY==randomY)){ randomX=int(random(width)); randomY=int(random(height)); } float atany = randomY-ypos; float atanx = randomX-xpos; angle = atan2(atany, atanx); if(randomX>xpos){ xdiff=atanx; } else{ xdiff=xpos-randomX; } if(randomY>ypos){ ydiff=atany; } else{ ydiff=ypos-randomY; } while((xdiff>2)||(ydiff>2)){ xdiff=(xdiff*9)/10; ydiff=(ydiff*9)/10; } if(xpos>randomX){ xdiff=(xdiff*-1); } if(ypos>randomY){ ydiff=(ydiff*-1); } xpos+=xdiff; ypos+=ydiff; //infected preds can infect plants by wandering across them if(infected==true){ findNearestPlant(); if(plant[nearestPlant]!=null){ if((xpos<(plant[nearestPlant].xpos+5))&&(xpos>(plant[nearestPlant].xpos-5))&&(ypos<(plant[nearestPlant].ypos+5))&&(ypos>(plant[nearestPlant].ypos-5))){ plant[nearestPlant].infected=true; } } } } //----------------------------------------------------------------------------- //pred //see plant.findNearestPlant int findNearestPrey(){ float nearestDistance =diagonal; for(int i = 0; i<(maxPrey); i++){ if ((prey[i] != null)&&(prey[i].dying==false)&&(prey[i].sym==false)){ float distance = dist(xpos, ypos, prey[i].xpos, prey[i].ypos); if (distance < nearestDistance){ nearestPrey = i; nearestDistance = distance; } } } return nearestPrey; } //--------------------------------------------------------------------------------- //pred //see plant.findNearestPlant int findNearestPlant(){ float nearestDistance =diagonal; for(int i = 0; i<(maxPlant); i++){ if((plant[i] != null)&&(plant[i].dying==false)){ float distance = dist(xpos, ypos, plant[i].xpos, plant[i].ypos); if (distance < nearestDistance){ nearestPlant = i; nearestDistance = distance; } } } return nearestPlant; } } //================================================================== class Scav{ int itsName, itsAlpha, itsHue, itsSat, itsBright, energy, itsAge, lifeSpan, nearestPlant, nearestPrey, nearestPred, nearestScav, addSpeed, seconds, randomX, randomY; float xpos, ypos, lastX, lastY, startArc, stopArc, turn, angle, xdiff, ydiff, itsWidth, maxWidth, body, startShake; boolean morphed, exploding, dying, right, climbing, up, dieClock, infected; Scav(){ //body width changes if the scav explodes body=0.25; angle = random(-PI,PI); //larval scavs know whether they are travelling left or right right=true; //turn is used to make the larval legs go round turn = 0; //climbing and up are used when one larva climbs over another climbing = false; up=true; infected = false; seconds=second(); xpos = random(width); maxWidth =random(15,20); itsWidth = 1; //larval scavs appear along the bottom ypos= height-itsWidth; itsAlpha = 255; //they are red itsHue = int(random(-20,10)); randomX=int(random(width)); randomY=int(random((2*height)/3)); if(itsHue<0){ itsHue+=360; } itsSat = int(random(90,100)); itsBright = int(random(40,70)); morphed = false; exploding = false; energy = 0; float rn = random(-1,1); if(rn<0){ dieClock=true; } else{ dieClock=false; } itsAge = 0; lifeSpan = (40+int(random(20))); dying = false; scavPop++; } //-------------------------------------------------------- //scav //see plant.update and prey.update void update(){ //infected scavs get darker and pulse if((infected==true)&&(dying==false)){ itsBright-=2; if(itsBright<10){ itsBright=int(random(30,50)); } } //if it's still a larva... if(morphed==false){ if(itsWidth<=maxWidth){ itsWidth=(itsWidth*1.025); } //climb includes looking for other scavs to climb over climb(); //if its' travelling right then the legs will be drawn one way round, // if it's going left then they'll be drawn the other way round. if(right==true){ startArc=PI; stopArc=TWO_PI; //if it's reached the right edge of the screen it turns round if(xpos>=(width-15)){ right=false; } } else{ startArc=PI/2; stopArc=PI+(PI/2); //if it's reached the left edge of the screen it turns round if(xpos<=15){ right=true; } } hunt(); //bugfix: I couldn't work out how to stop the larval scavs getting stuck //together sometimes, so I put this in - if a scav is in the same place it was //in the previous frame then it changes direction, so if they get stuck together //they move apart again if(seconds!=second()){ if((lastX==xpos)&&(lastY==ypos)){ if(right==true){ right=false; } else{ right=true; } } seconds=second(); } lastX=xpos; lastY=ypos; //this is what they look like - see prey.update fill(itsHue,itsSat,itsBright); pushMatrix(); ellipseMode(CENTER); stroke(itsHue,itsSat,(itsBright-20)); translate(xpos,ypos); ellipse(0,0,itsWidth,itsWidth); noFill(); strokeWeight(3); rotate(turn); //draw a leg... arc(((itsWidth/2.2)*-1),((itsWidth/2.2)*-1),(itsWidth/4),(itsWidth/4),startArc, stopArc); //draw 7 more for(int i=0; i<7; i++){ rotate(PI/4); arc(((itsWidth/2.2)*-1),((itsWidth/2.2)*-1),(itsWidth/4),(itsWidth/4),startArc,stopArc); } popMatrix(); strokeWeight(1); //change the xpos and rotate the legs a bit ready for the next frame if(right==true){ xpos++; turn+=radians(3); } else{ xpos--; turn+=radians(-3); } //when it gets 500 energy points it turns into an adult if(energy>=500){ morphed=true; } } //if it's an adult... else{ if(dying==true){ die(); } else{ //scavs explode from overeating, or if they're pretty much the last thing alive if(exploding==true){ explode(); } //if it's not exploding... else{ //check to see whether it should be exploding if((energy>=1000)||((plantEnergy==0)&&(preyEnergy==0)&&(predEnergy==0)&&(scavEnergy==energy))){ exploding=true; startShake = frameCount+(framerate*2); } //if it is still not exploding... else{ //adults move faster than larvae addSpeed = int(random(5,7)); //adults lose 30 energy points each second if(seconds!=second()){ if(energy>=30){ energy-=30; scavEnergy-=30; energyStore+=30; } //if it doesn't have 30 points it loses whatever it's got left else{ scavEnergy-=energy; energyStore+=energy; energy=0; } itsAge++; seconds=second(); } if(energy>950){ birth(); } if((itsAge>=lifeSpan)||((energy<=10)&&(morphed==true))){ dying=true; } hunt(); } if(xpos<0){ xpos += int(random(1,3)); ypos += int(random(-2,2)); } else if (xpos>width){ xpos -= int(random(1,3)); ypos += int(random(-2,2)); } else if (ypos<0){ ypos += int(random(1,3)); xpos += int(random(-2,2)); } else if (ypos>height){ ypos -= int(random(1,3)); xpos += int(random(-2,2)); } } } if(exploding==false){ //this bit makes it cast a shadow pushMatrix(); translate(xpos,ypos); rotate(angle); rotate(radians(90)); scale(0.8); noStroke(); fill(itsHue, 0, 0,(itsAlpha/2)); triangle(itsWidth,(itsWidth*4),0,0,(itsWidth/10),(itsWidth*3)); triangle((itsWidth*-1),(itsWidth*4),0,0,((itsWidth/10)*-1),(itsWidth*3)); ellipse(0,(itsWidth*2.5),(itsWidth*body),(itsWidth*5)); ellipse(0,itsWidth/2,itsWidth/2, itsWidth/2); popMatrix(); } pushMatrix(); translate((xpos-5),(ypos)); rotate(angle); rotate(radians(90)); scale(0.75); fill(itsHue, itsSat, itsBright, itsAlpha); stroke(itsHue, 0,0,itsAlpha); triangle(itsWidth,(itsWidth*4),0,0,(itsWidth/10),(itsWidth*3)); triangle((itsWidth*-1),(itsWidth*4),0,0,((itsWidth/10)*-1),(itsWidth*3)); fill(itsHue,0,0,itsAlpha); ellipse(0,(itsWidth*2.5),(itsWidth*body),(itsWidth*5)); ellipse(0,itsWidth/2,itsWidth/2, itsWidth/2); popMatrix(); } } //--------------------------------------------------------------------- //scav //see plant.findNearestPlant int findNearestPlant(){ float nearestDistance =diagonal; for(int i = 0; i<(maxPlant); i++){ if((plant[i]!=null)&&(plant[i].sym==false)&&(((morphed==true)&&(plant[i].dying==false))||(morphed==false))){ float distance = dist(xpos, ypos, plant[i].xpos, plant[i].ypos); if (distance < nearestDistance){ nearestPlant = i; nearestDistance = distance; } } } return nearestPlant; } //------------------------------------------------------------------------------------------ //scav //see plant.findNearestPlant int findNearestPrey(){ float nearestDistance =diagonal; for(int i = 0; i<(maxPrey); i++){ if((prey[i]!=null)&&(prey[i].sym==false)&&(((morphed==true)&&(prey[i].dying==false))||((morphed==false)&&(prey[i].ypos>(2*height)/3)))){ float distance = dist(xpos, ypos, prey[i].xpos, prey[i].ypos); if (distance < nearestDistance){ nearestPrey = i; nearestDistance = distance; } } } return nearestPrey; } //--------------------------------------------------------------------------------------------- //scav //see plant.findNearestPlant int findNearestPred(){ float nearestDistance =diagonal; for(int i = 0; i<(maxPred); i++){ if((pred[i] != null)&&(((morphed==true)&&(pred[i].dying==false))||((morphed==false)&&(pred[i].ypos>(2*height)/3)))){ float distance = dist(xpos, ypos, pred[i].xpos, pred[i].ypos); if (distance < nearestDistance){ nearestPred = i; nearestDistance = distance; } } } return nearestPred; } //---------------------------------------------------------------------------------------------------- //scav //see plant.findNearestPlant int findNearestScav(){ float nearestDistance =diagonal; for(int i = 0; i<(maxScav); i++){ if(i!=itsName){ if(scav[i] != null){ float distance = dist(xpos, ypos, scav[i].xpos, scav[i].ypos); if (distance < nearestDistance){ nearestScav = i; nearestDistance = distance; } } } } return nearestScav; } //--------------------------------------------------------------------------------------------------- //scav //see prey.hunt. Because scavs eat anything they need to find the //nearest of each class before they decide where the nearest food is void hunt(){ float plantDist = diagonal; float preyDist = diagonal; float predDist = diagonal; float scavDist = diagonal; findNearestPlant(); if(plant[nearestPlant]!=null){ plantDist = dist(xpos, ypos, plant[nearestPlant].xpos, plant[nearestPlant].ypos); } findNearestPrey(); if(prey[nearestPrey]!=null){ preyDist = dist(xpos, ypos, prey[nearestPrey].xpos, prey[nearestPrey].ypos); } findNearestPred(); if(pred[nearestPred]!=null){ predDist = dist(xpos, ypos, pred[nearestPred].xpos, pred[nearestPred].ypos); } if(scavPop>1){ findNearestScav(); if(scav[nearestScav]!=null){ scavDist = dist(xpos, ypos, scav[nearestScav].xpos,scav[nearestScav].ypos); } } //if the nearest food is a plant... if((plant[nearestPlant]!=null)&&((plantDistxpos){ xdiff=atanx; } else{ xdiff=xpos-plant[nearestPlant].xpos; } if(plant[nearestPlant].ypos>ypos){ ydiff=atany; } else{ ydiff=ypos-plant[nearestPlant].ypos; } while((xdiff>7)||(ydiff>7)){ xdiff=(xdiff*9)/10; ydiff=(ydiff*9)/10; } if(xpos>plant[nearestPlant].xpos){ xdiff=(xdiff*-1); } if(ypos>plant[nearestPlant].ypos){ ydiff=(ydiff*-1); } xpos+=(xdiff+random(-2,2)); ypos+=(ydiff+random(-2,2)); } } //this stops hunting scavs from sticking together - if they're directly on top //of each other one or both will shift a bit. if((scav[nearestScav]!=null)&&(scav[nearestScav].itsName!=itsName)){ if((xpos>(scav[nearestScav].xpos-10))&&(xpos<(scav[nearestScav].xpos+10))&&(ypos>(scav[nearestScav].ypos-10))&&(ypos<(scav[nearestScav].ypos+10))){ if(xposxpos){ xdiff=atanx; } else{ xdiff=xpos-prey[nearestPrey].xpos; } if(prey[nearestPrey].ypos>ypos){ ydiff=atany; } else{ ydiff=ypos-prey[nearestPrey].ypos; } while((xdiff>7)||(ydiff>7)){ xdiff=(xdiff*9)/10; ydiff=(ydiff*9)/10; } if(xpos>prey[nearestPrey].xpos){ xdiff=(xdiff*-1); } if(ypos>prey[nearestPrey].ypos){ ydiff=(ydiff*-1); } xpos+=(xdiff+random(-2,2)); ypos+=(ydiff+random(-2,2)); } } if((scav[nearestScav]!=null)&&(scav[nearestScav].itsName!=itsName)){ if((xpos>(scav[nearestScav].xpos-10))&&(xpos<(scav[nearestScav].xpos+10))&&(ypos>(scav[nearestScav].ypos-10))&&(ypos<(scav[nearestScav].ypos+10))){ if(xposxpos){ xdiff=atanx; } else{ xdiff=xpos-pred[nearestPred].xpos; } if(pred[nearestPred].ypos>ypos){ ydiff=atany; } else{ ydiff=ypos-pred[nearestPred].ypos; } while((xdiff>7)||(ydiff>7)){ xdiff=(xdiff*9)/10; ydiff=(ydiff*9)/10; } if(xpos>pred[nearestPred].xpos){ xdiff=(xdiff*-1); } if(ypos>pred[nearestPred].ypos){ ydiff=(ydiff*-1); } xpos+=xdiff; ypos+=ydiff; } } if((scav[nearestScav]!=null)&&(scav[nearestScav].itsName!=itsName)){ if((xpos>(scav[nearestScav].xpos-10))&&(xpos<(scav[nearestScav].xpos+10))&&(ypos>(scav[nearestScav].ypos-10))&&(ypos<(scav[nearestScav].ypos+10))){ if(xposxpos){ xdiff=atanx; } else{ xdiff=xpos-scav[nearestScav].xpos; } if(scav[nearestScav].ypos>ypos){ ydiff=atany; } else{ ydiff=ypos-scav[nearestScav].ypos; } while((xdiff>7)||(ydiff>7)){ xdiff=(xdiff*9)/10; ydiff=(ydiff*9)/10; } if(xpos>scav[nearestScav].xpos){ xdiff=(xdiff*-1); } if(ypos>scav[nearestScav].ypos){ ydiff=(ydiff*-1); } xpos+=xdiff; ypos+=ydiff; } } } //if there's not even any other scavs to eat then just wander about else{ wander(); } } } //---------------------------------------------------------------------------------------------- //scav void explode(){ //exploding scavs bodies swell up and become transparent if(body<4){ body+=0.1; itsAlpha-=3; } //when the body swells to a certain size the swelling slows a bit and the scav starts shaking //it will shake for approx 3 seconds: framerate*3 else{ float stopShake = startShake+(framerate*3); if(body<5){ body+=0.05; itsAlpha-=3; //it shakes a bit randomly float num = random(-1,1); if(num<0){ xpos+=4; } else{ xpos-=4; } } //when it reaches maximum width it suddenly becomes a small black circle //which falls rapidly to the bottom else{ itsWidth=2; itsAlpha=255; ypos+=12; //when it reaches the bottom it dies if(ypos>=height){ energyStore += energy; scavEnergy -=energy; scav[itsName] = null; scavPop--; } } } } //--------------------------------------------------------------------------------------------- //scav //see plant.birth. Baby scavs are always born uninfected void birth(){ for(int i = 0; i<(maxScav-1); i++){ if (scav[i] == null){ scav[i] = new Scav(); scav[i].itsName = i; //it costs the scav 600 points to reproduce energy -= 600; scavEnergy -=600; energyStore+=600; break; } } } //---------------------------------------------------------------------------------------- //scav //see plant.die etc void die(){ xpos += int(random(-1,+1)); ypos += (2 +int(random(3))); if(itsAlpha>2){ itsAlpha-=2; } for(int i =0;i<6;i++){ if(para[i]!=null){ if((ypos>para[i].ypos)&&((xpos<(para[i].xpos+(para[i].itsWidth/2)))&&(xpos>(para[i].xpos-(para[i].itsWidth/2))))){ if(infected==false){ infected=true; } } } } float deg = degrees(angle); if(dieClock==true){ deg+=2; if(deg>=360){ deg-=360; } } else{ deg-=2; if(deg<=0){ deg+=360; } } angle = radians(deg); if(ypos>=height){ energyStore += energy; scavEnergy -=energy; scav[itsName] = null; scavPop--; } } //---------------------------------------------------------------------------------------- //scav void climb(){ //theheight stores the usual ypos of the scav before it begins climbing float theheight = height-((itsWidth*3)/4); if(scavPop>1){ findNearestScav(); if(scav[nearestScav]!=null){ //if there is another scav then find the distance to the nearest one float nowDist=dist(xpos,ypos,scav[nearestScav].xpos,scav[nearestScav].ypos); //if the nearest scav is less than 25 px away and is not climbing then climb if((nowDist<25)&&(scav[nearestScav].climbing==false)&&(scav[nearestScav].itsName>itsName)){ climbing=true; //while climbing, the scavs left/right movement is cancelled out so that it moves straight up or down if(right==true){ xpos--; } else{ xpos++; } //if it's climbing up... if(up==true){ ypos--; //when it reaches 45 px above the bottom it starts climbing down. if(ypos<(height-45)){ up=false; } } //if it's climbing down... else{ ypos++; //when it reaches its original ypos it stops climbing and "up" is reset ready for its next climb if(ypos>=theheight){ ypos=theheight; climbing=false; up=true; } } } //the rest of this is double checking to make sure the climbing scav returns to its original ypos //and knows it is no longer climbing. I put it in to help stop the scavs from sticking together or getting stuck in mid-air // I'm not sure how much of this code is really necessary! else{ if(ypos=theheight){ ypos=theheight; climbing=false; up=true; } } else if(ypos>theheight){ ypos--; climbing=false; up=true; } } } } else{ if(ypos=theheight){ ypos=theheight; climbing=false; up=true; } } else if(ypos>theheight){ ypos--; climbing=false; up=true; } } } //---------------------------------------------------- //scavs //see prey.wander void wander(){ int intX=int(xpos); int intY=int(ypos); if((intX==randomX)&&(intY==randomY)){ randomX=int(random(width)); randomY=int(random(height)); } float atany = randomY-ypos; float atanx = randomX-xpos; angle = atan2(atany, atanx); if(randomX>xpos){ xdiff=atanx; } else{ xdiff=xpos-randomX; } if(randomY>ypos){ ydiff=atany; } else{ ydiff=ypos-randomY; } while((xdiff>2)||(ydiff>2)){ xdiff=(xdiff*9)/10; ydiff=(ydiff*9)/10; } if(xpos>randomX){ xdiff=(xdiff*-1); } if(ypos>randomY){ ydiff=(ydiff*-1); } xpos+=xdiff; ypos+=ydiff; } } //=============================================== //insect eggs don't know much class InsEgg{ float xpos, ypos; int itsName, counter, itsAge, itsAlpha, seconds; InsEgg(){ //insX and insY are global variables which determine the point where each generation //of insects lay eggs. eggs are clustered around this point in a loose oblong blob xpos = insX+(random(-6,6)); ypos = insY+(random(-6,30)); itsAge=0; //they are completely invisible to start with itsAlpha=0; seconds=second(); //counter tells the eggs when to hatch counter = frameCount+1123; } //------------------------------------------------ void update(){ //if the time has come to hatch if(frameCount>=counter){ //each egg creates a new insect in its own position then nulls itself for(int i = 0; i=counter){ lay(); } //if they are not dying or laying... else{ //allThere is a global variable which changes to true when all insects //have reached the laying site (insX and insY) allThere=false; hunt(); } //this is a patch-up for a bug which caused the insects to freeze from time to time //it tells them that if they haven't moved since the previous frame then they must jiggle a bit if((xpos==lastX)&&(ypos==lastY)){ xpos+=(random(-3,3)); ypos+=(random(-3,3)); } //draw a little circle but don't colour it in stroke(itsHue,itsSat,(itsBright-20),itsAlpha); noFill(); ellipse(xpos,ypos,3,3); //reset lastX, lastY lastX=xpos; lastY=ypos; } //------------------------------------------------------- //insects //see plant.die void die(){ ypos += (1 +random(2)); if(itsAlpha>2){ itsAlpha--; } for(int i =0;i<6;i++){ if(para[i]!=null){ if((ypos>para[i].ypos)&&((xpos<(para[i].xpos+(para[i].itsWidth/2)))&&(xpos>(para[i].xpos-(para[i].itsWidth/2))))){ if(infected==false){ infected=true; } } } } if(ypos>=height){ ins[itsName] = null; insPop--; } } //------------------------------------------------------- //insects //this is a variation on the hunt method, it's a bit messy... void lay(){ //if it is more than 7 px from the laying site it moves towards it in a straight line if(dist(xpos,ypos,insX,insY)>7){ float atany = insY-ypos; float atanx = insX-xpos; if(insX>xpos){ xdiff=atanx; } else{ xdiff=xpos-insX; } if(insY>ypos){ ydiff=atany; } else{ ydiff=ypos-insY; } while((xdiff>6)||(ydiff>6)){ xdiff=(xdiff*9)/10; ydiff=(ydiff*9)/10; } if(xpos>insX){ xdiff=(xdiff*-1); } if(ypos>insY){ ydiff=(ydiff*-1); } xpos+=(xdiff+random(-2,2)); ypos+=(ydiff+random(-2,2)); //while the insect has not reached the laying site allThere cannot be true allThere=false; } //when it reaches the laying site else{ there=true; dying=true; } } //------------------------------------------------------ //insects //see prey.hunt etc void hunt(){ float huntDist; int nextTo; //the insect's favourite food is scavs if(scavPop>0){ findNearestScav(); } //make sure the scav exists, is not dying, is an adult, is not the last creature it bit, and that it has at least 200 points if((scav[nearestScav]!=null)&&(scav[nearestScav].dying==false)&&(scav[nearestScav].morphed==true)&&(lastBitten!=scav[nearestScav])&&(scav[nearestScav].energy>=200)){ huntDist = dist(xpos,ypos,scav[nearestScav].xpos,scav[nearestScav].ypos); nextTo = int(scav[nearestScav].itsWidth/2); if(huntDist <= nextTo){ if(infected==false){ //infected insects can move faster if(scav[nearestScav].infected==true){ infected=true; speed=6; } } //if the insect is infected it infects the creature it bites else{ if(scav[nearestScav].infected==false){ scav[nearestScav].infected=true; } } //it takes one energy point from the creature it bites energy += 1; scav[nearestScav].energy -= 1; scavEnergy-=1; insEnergy +=1; //the name of the creature is stored as lastBitten, but I'm not sure this works lastBitten = scav[nearestScav]; } //if it's not next to the nearest scav it moves towards it else{ float atany = scav[nearestScav].ypos-ypos; float atanx = scav[nearestScav].xpos-xpos; if(scav[nearestScav].xpos>xpos){ xdiff=atanx; } else{ xdiff=xpos-scav[nearestScav].xpos; } if(scav[nearestScav].ypos>ypos){ ydiff=atany; } else{ ydiff=ypos-scav[nearestScav].ypos; } while((xdiff>speed)||(ydiff>speed)){ xdiff=(xdiff*9)/10; ydiff=(ydiff*9)/10; } if(xpos>scav[nearestScav].xpos){ xdiff=(xdiff*-1); } if(ypos>scav[nearestScav].ypos){ ydiff=(ydiff*-1); } xpos+=(xdiff+random(-3,3)); ypos+=(ydiff+random(-3,3)); } } //if there's not a scav it can bite it will go for a pred //see above else{ if(predPop>0){ findNearestPred(); } if((pred[nearestPred]!=null)&&(pred[nearestPred].dying==false)&&(lastBitten!=pred[nearestPred])&&(pred[nearestPred].energy>=5)){ huntDist =dist(xpos,ypos,pred[nearestPred].xpos,pred[nearestPred].ypos); nextTo = int(pred[nearestPred].itsWidth/2); if(huntDist <= nextTo){ if(infected==false){ if(pred[nearestPred].infected==true){ infected=true; speed=6; } } else{ if(pred[nearestPred].infected==false){ pred[nearestPred].infected=true; pred[nearestPred].hungry+=4; pred[nearestPred].lifeSpan-=20; } } energy += 1; pred[nearestPred].energy -= 1; predEnergy-=1; insEnergy +=1; lastBitten = pred[nearestPred]; } else{ float atany = pred[nearestPred].ypos-ypos; float atanx = pred[nearestPred].xpos-xpos; if(pred[nearestPred].xpos>xpos){ xdiff=atanx; } else{ xdiff=xpos-pred[nearestPred].xpos; } if(pred[nearestPred].ypos>ypos){ ydiff=atany; } else{ ydiff=ypos-pred[nearestPred].ypos; } while((xdiff>speed)||(ydiff>speed)){ xdiff=(xdiff*9)/10; ydiff=(ydiff*9)/10; } if(xpos>pred[nearestPred].xpos){ xdiff=(xdiff*-1); } if(ypos>pred[nearestPred].ypos){ ydiff=(ydiff*-1); } xpos+=(xdiff+random(-3,3)); ypos+=(ydiff+random(-3,3)); } } //if it can't bite a scav or a pred it will go for a prey else{ if(preyPop>0){ findNearestPrey(); } if((prey[nearestPrey]!=null)&&(prey[nearestPrey].dying==false)&&(prey[nearestPrey].sym==false)&&(lastBitten!=prey[nearestPrey])&&(prey[nearestPrey].energy>=4)){ huntDist =dist(xpos,ypos,prey[nearestPrey].xpos,prey[nearestPrey].ypos); nextTo = int(prey[nearestPrey].itsWidth/2); if(huntDist <= nextTo){ if(infected==false){ if(prey[nearestPrey].infected==true){ infected=true; speed=6; } } else{ if(prey[nearestPrey].infected==false){ prey[nearestPrey].infected=true; } } energy += 1; prey[nearestPrey].energy -= 1; preyEnergy-=1; insEnergy +=1; lastBitten = prey[nearestPrey]; } else{ float atany = prey[nearestPrey].ypos-ypos; float atanx = prey[nearestPrey].xpos-xpos; if(prey[nearestPrey].xpos>xpos){ xdiff=atanx; } else{ xdiff=xpos-prey[nearestPrey].xpos; } if(prey[nearestPrey].ypos>ypos){ ydiff=atany; } else{ ydiff=ypos-prey[nearestPrey].ypos; } while((xdiff>speed)||(ydiff>speed)){ xdiff=(xdiff*9)/10; ydiff=(ydiff*9)/10; } if(xpos>prey[nearestPrey].xpos){ xdiff=(xdiff*-1); } if(ypos>prey[nearestPrey].ypos){ ydiff=(ydiff*-1); } xpos+=(xdiff+random(-3,3)); ypos+=(ydiff+random(-3,3)); } } //if there's nothing else it can bite it will go for a plant - see above else{ findNearestPlant(); if((plant[nearestPlant]!=null)&&(plant[nearestPlant].dying==false)&&(lastBitten!=plant[nearestPlant])&&(plant[nearestPlant].energy>=2)){ huntDist = dist(xpos,ypos,plant[nearestPlant].xpos,plant[nearestPlant].ypos); nextTo = int(plant[nearestPlant].itsWidth/2); if(huntDist <= nextTo){ if(infected==false){ if(plant[nearestPlant].infected==true){ infected=true; speed=6; } } else{ if(plant[nearestPlant].infected==false){ plant[nearestPlant].infected=true; } } energy += 1; plant[nearestPlant].energy -= 1; plantEnergy-=1; insEnergy +=1; lastBitten = plant[nearestPlant]; } else{ float atany = plant[nearestPlant].ypos-ypos; float atanx = plant[nearestPlant].xpos-xpos; if(plant[nearestPlant].xpos>xpos){ xdiff=atanx; } else{ xdiff=xpos-plant[nearestPlant].xpos; } if(plant[nearestPlant].ypos>ypos){ ydiff=atany; } else{ ydiff=ypos-plant[nearestPlant].ypos; } while((xdiff>speed)||(ydiff>speed)){ xdiff=(xdiff*9)/10; ydiff=(ydiff*9)/10; } if(xpos>plant[nearestPlant].xpos){ xdiff=(xdiff*-1); } if(ypos>plant[nearestPlant].ypos){ ydiff=(ydiff*-1); } xpos+=(xdiff+random(-3,3)); ypos+=(ydiff+random(-3,3)); } } } } } } //---------------------------------------------------------- //insects //see plant.findNearestPlant int findNearestScav(){ float nearestDistance =diagonal; for(int i = 0; i<(maxScav); i++){ if((scav[i] != null)&&(scav[i].morphed==true)){ float distance = dist(xpos, ypos, scav[i].xpos, scav[i].ypos); if (distance < nearestDistance){ nearestScav = i; nearestDistance = distance; } } } return nearestScav; } //--------------------------------------------------------- //insects //see plant.findNearestPlant int findNearestPred(){ float nearestDistance =diagonal; for(int i = 0; i<(maxPred); i++){ if ((pred[i] != null)&&(pred[i].dying==false)){ float distance = dist(xpos, ypos, pred[i].xpos, pred[i].ypos); if (distance < nearestDistance){ nearestPred = i; nearestDistance = distance; } } } return nearestPred; } //------------------------------------------------------- //insects //see plant.findNearestPlant int findNearestPrey(){ float nearestDistance =diagonal; for(int i = 0; i<(maxPrey); i++){ if ((prey[i] != null)&&(prey[i].dying==false)){ float distance = dist(xpos, ypos, prey[i].xpos, prey[i].ypos); if (distance < nearestDistance){ nearestPrey = i; nearestDistance = distance; } } } return nearestPrey; } //------------------------------------------------------------ //insects //see plant.findNearestPlant int findNearestPlant(){ float nearestDistance =diagonal; for(int i = 0; i<(maxPlant); i++){ if((plant[i] != null)&&(plant[i].dying==false)){ float distance = dist(xpos, ypos, plant[i].xpos, plant[i].ypos); if (distance < nearestDistance){ nearestPlant = i; nearestDistance = distance; } } } return nearestPlant; } } //================================================================ //this is a bit redundant as a separate method now - it was a lot bigger //originally. Once per generation of insects the laying site is reset as //a random point near the top edge of the screen void setInsPos(){ insY = 6; insX = random(6,(width-6)); } //=================================================================== //this is when the actual egg production happens void insRegen(){ int i=0; //this keeps running as long as there is space in the array for new eggs //and as long as insEnergy(the total energy of all the insects) is at least 10 while((i=10)){ //make an egg and put 10 points in energyStore if(insEgg[i]==null){ insEgg[i]=new InsEgg(); insEgg[i].itsName=i; eggPop++; insEnergy-=10; energyStore+=10; } i++; } //when the array is full up or there's less than 10 points left //any remaining energy is returned to energyStore energyStore+=insEnergy; insEnergy=0; //all the insects die for(int j=0; j(height-(height/4)))&&(ypos<((height-(height/4))+100))){ ypos+=int(random(-2,2)); } else if(ypos>((height-(height/4))+100)){ ypos-=int(random(3)); } else{ ypos+=int(random(3)); } xpos+=int(random(-3,3)); if((itsWidth>30)&&(itsWidth<100)){ itsWidth+=int(random(-4,4)); } else if(itsWidth<=30){ itsWidth+=int(random(4)); } else{ itsWidth-=int(random(4)); } itsHeight+=int(random(-1,1)); //the second ellipse is positioned quite randomly on top of the first secondy = int(random((ypos-(itsHeight/2)),(ypos-((itsHeight*3)/4)))); noStroke(); //paras are a slightly darker shade of the background hue and are a bit transparent int s=bgs-20; int b=bgb-20; fill(bgh, s,b,80); //two wobbly blobs ellipse(xpos, ypos, itsWidth,itsHeight); ellipse(xpos, secondy,((itsWidth*2)/3), (itsHeight/2)); } } //=============================================================================================== //----------------------------------------------------------------------------------------------- //end of Processing code //----------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------- //Wiring code: //----------------------------------------------------------------------------------------------- /* //the starting point for the Wiring part of ambient_light was "switch_serial //by BARRAGAN //created 13 May 2004 //revised 28 Aug 2005 //I needed the program to send the exact combination of 6 digital inputs received - this involves //giving each possible combination of chairs a unique number. After I wrote this I found a much easier //way of doing it using bitwise values (ie pina=1, pinb=2, pinc=4, pind=8...) and then just adding //them up... //============================================================================================================= //the pins on the wiring board are assigned to the switchpin variables. int switchpina = 0; int switchpinb = 1; int switchpinc = 2; int switchpind = 3; int switchpine = 4; int switchpinf = 5; int pina = 0; int pinb = 0; int pinc = 0; int pind = 0; int pine = 0; int pinf = 0; //========================================================================================================== void setup() { //each pin's mode is set as input pinMode(switchpina, INPUT); pinMode(switchpinb, INPUT); pinMode(switchpinc, INPUT); pinMode(switchpind, INPUT); pinMode(switchpine, INPUT); pinMode(switchpinf, INPUT); // start serial communication at 9600bps Serial.begin(9600); } //========================================================================================================== void loop() { //pins are all reset to 0 pina=0; pinb=0; pinc=0; pind=0; pine=0; pinf=0; //if the switch is on the variable is changed to 1 if(digitalRead(switchpina) == LOW){ pina=1; } if(digitalRead(switchpinb) == LOW){ pinb=1; } if(digitalRead(switchpinc) == LOW){ pinc=1; } if(digitalRead(switchpind) == LOW){ pind=1; } if(digitalRead(switchpine) == LOW){ pine=1; } if(digitalRead(switchpinf) == LOW){ pinf=1; } //so now, having worked out which switches are on and which are off //I go through every possible combination and assign it a unique number if(pina==1){ if(pinb==1){ if(pinc==1){ if(pind==1){ if(pine==1){ if(pinf==1){ Serial.write(1); } else{ Serial.write(2); } } else{ if(pinf==1){ Serial.write(3); } else{ Serial.write(4); } } } else{ if(pine==1){ if(pinf==1){ Serial.write(5); } else{ Serial.write(6); } } else{ if(pinf==1){ Serial.write(7); } else{ Serial.write(8); } } } } else{ if(pind==1){ if(pine==1){ if(pinf==1){ Serial.write(9); } else{ Serial.write(10); } } else{ if(pinf==1){ Serial.write(11); } else{ Serial.write(12); } } } else{ if(pine==1){ if(pinf==1){ Serial.write(13); } else{ Serial.write(14); } } else{ if(pinf==1){ Serial.write(15); } else{ Serial.write(16); } } } } } else{ if(pinc==1){ if(pind==1){ if(pine==1){ if(pinf==1){ Serial.write(17); } else{ Serial.write(18); } } else{ if(pinf==1){ Serial.write(19); } else{ Serial.write(20); } } } else{ if(pine==1){ if(pinf==1){ Serial.write(21); } else{ Serial.write(22); } } else{ if(pinf==1){ Serial.write(23); } else{ Serial.write(24); } } } } else{ if(pind==1){ if(pine==1){ if(pinf==1){ Serial.write(25); } else{ Serial.write(26); } } else{ if(pinf==1){ Serial.write(27); } else{ Serial.write(28); } } } else{ if(pine==1){ if(pinf==1){ Serial.write(29); } else{ Serial.write(30); } } else{ if(pinf==1){ Serial.write(31); } else{ Serial.write(32); } } } } } } else{ if(pinb==1){ if(pinc==1){ if(pind==1){ if(pine==1){ if(pinf==1){ Serial.write(33); } else{ Serial.write(34); } } else{ if(pinf==1){ Serial.write(35); } else{ Serial.write(36); } } } else{ if(pine==1){ if(pinf==1){ Serial.write(37); } else{ Serial.write(38); } } else{ if(pinf==1){ Serial.write(39); } else{ Serial.write(40); } } } } else{ if(pind==1){ if(pine==1){ if(pinf==1){ Serial.write(41); } else{ Serial.write(42); } } else{ if(pinf==1){ Serial.write(43); } else{ Serial.write(44); } } } else{ if(pine==1){ if(pinf==1){ Serial.write(45); } else{ Serial.write(46); } } else{ if(pinf==1){ Serial.write(47); } else{ Serial.write(48); } } } } } else{ if(pinc==1){ if(pind==1){ if(pine==1){ if(pinf==1){ Serial.write(49); } else{ Serial.write(50); } } else{ if(pinf==1){ Serial.write(51); } else{ Serial.write(52); } } } else{ if(pine==1){ if(pinf==1){ Serial.write(53); } else{ Serial.write(54); } } else{ if(pinf==1){ Serial.write(55); } else{ Serial.write(56); } } } } else{ if(pind==1){ if(pine==1){ if(pinf==1){ Serial.write(57); } else{ Serial.write(58); } } else{ if(pinf==1){ Serial.write(59); } else{ Serial.write(60); } } } else{ if(pine==1){ if(pinf==1){ Serial.write(61); } else{ Serial.write(62); } } else{ if(pinf==1){ Serial.write(63); } else{ Serial.write(0); } } } } } } // wait 100ms delay(100); } */ //======================================================================================================= //----------------------------------------------------------------------------------------------------- //end of Wiring code //-------------------------------------------------------------------------------------------------------- //=======================================================================================================