{
   "description" : "Port of the \"BoidRoids.js\" file contained in the Max distribution examples.\r\nUsed with permission of Cycling '74\r\n\r\nThought this might be a good example to put up here on writing classes.",
   "ancestor_list" : [],
   "author" : "xffff",
   "name" : "BoidRoids Class",
   "code" : "/*\r\nSuperCollider port of BoidRoids.js from the Max examples\r\nUsed with permission of Cycling '74 (thanks!)\r\n\r\nMike Murphy 2012\r\n*/\r\n\r\n// mode \\average = \"average x/y/vx/vy list\"\r\n// mode \\normal = \"series of x/y/vx/vy lists\"\r\n\r\nBoidRoids {\r\n\t// global varables and code\r\n\tvar\r\n\tagents,\r\n\t<avgvelocity_x = 0,\r\n\t<avgvelocity_y = 0,\r\n\t<centroid_x = 0,\r\n\t<centroid_y = 0,\r\n\t<>myagentcount = 0,\r\n\t<myseparation = 0.03,\r\n\t<myalignment = 0.05,\r\n\t<mycoherence = 0.02,\r\n\t<myinertia = 0.5,\r\n\t<myfriction = 0.5,\r\n\t<mysepthresh = 0.1,\r\n\t<mymaxvel = 0.05,\r\n\t<mygravity = 0,\r\n\t<mygravpoint_x = 0.5,\r\n\t<mygravpoint_y = 0.5,\r\n\t<>mode = \\normal,\r\n\tx = 0,\r\n\ty = 0,\r\n\tvx = 0,\r\n\tvy = 0;\r\n\r\n\t*new{ |numboids|\r\n\t\t^super.new.initagents(numboids);\r\n\t}\r\n\r\n\tinitagents{ |n|\r\n\t\t// clip agentcount to range 1.-1000.\r\n\t\tmyagentcount = n.clip(1,1000);\r\n\t\tagents = Array.new(n);\r\n\r\n\t\tfor(0,myagentcount-1,{ |i|\r\n\t\t\t// start with random position/velocity\r\n\t\t\tx = rrand(0.0,1.0);\r\n\t\t\ty = rrand(0.0,1.0);\r\n\t\t\tvx = (rrand(0.0,1.0)-0.5)*0.1;\r\n\t\t\tvy = (rrand(0.0,1.0)-0.5)*0.1;\r\n\t\t\t// create a new agent... agents[i][x,y,vx,vy]\r\n\t\t\tagents.add([x,y,vx,vy]);\r\n\t\t\t}\r\n\t\t);\r\n\t}\r\n\r\n\t// task function\r\n\tgetBoids {\r\n\t\t//var i;\r\n\t\tvar cx=0;\r\n\t\tvar cy=0;\r\n\t\tvar cvx=0;\r\n\t\tvar cvy=0;\r\n\r\n\t\tfor (0,myagentcount-1,{ |i|\r\n\t\t\tthis.agent_tick(i);\r\n\r\n\t\t\t// calculate current frame's average position/velocity\r\n\t\t\tcx = cx + agents[i][0];\r\n\t\t\tcy = cy + agents[i][1];\r\n\t\t\tcvx = cvx + agents[i][2];\r\n\t\t\tcvy = cvy + agents[i][3];\r\n\t\t\t}\r\n\t\t);\r\n\r\n\t\tcentroid_x = cx/myagentcount;\r\n\t\tcentroid_y = cy/myagentcount;\r\n\t\tavgvelocity_x = cvx/myagentcount;\r\n\t\tavgvelocity_y = cvy/myagentcount;\r\n\r\n\t\tif(mode==\\normal,{\r\n\t\t\t^agents;\r\n\t\t\t},{\r\n\t\t\t\tif(mode==\\average,{\r\n\t\t\t\t\t^[centroid_x,centroid_y,avgvelocity_x,avgvelocity_y];\r\n\t\t\t\t\t},{\r\n\t\t\t\t\t\tpostln(\"BoidRoids: mode can be either \\average, or \\normal\");\r\n\t\t\t\t\t}\r\n\t\t\t\t);\r\n\t\t\t}\r\n\t\t);\r\n\r\n\t}\r\n\r\n\t// one iteration of the simulation for a given agent\r\n\t// we pass this the index of an agent in the agents array\r\n\t// it has the attributes agent[x,y,vx,vy]...\r\n\tagent_tick { | agent |\r\n\t\tvar px,py;\r\n\r\n\t\t// save current velocity for inertia calc\r\n\t\t//px = vx;\r\n\t\t//py = vy;\r\n\t\tpx = agents[agent][2];\r\n\t\tpy = agents[agent][3];\r\n\r\n\t\t// apply rules\r\n\t\tthis.separate(agent);\r\n\t\tthis.align(agent);\r\n\t\tthis.cohere(agent);\r\n\t\tthis.gravitate(agent);\r\n\r\n\t\t// inertia\r\n\t\t//vx = (px*myinertia) + (vx*(1-myinertia));\r\n\t\t//vy = (py*myinertia) + (vy*(1-myinertia));\r\n\t\tagents[agent][2] = (px*myinertia) + (agents[agent][2]*(1-myinertia));\r\n\t\tagents[agent][3] = (px*myinertia) + (agents[agent][3]*(1-myinertia));\r\n\r\n\t\t// velocity limit\r\n\t\tagents[agent][2] = agents[agent][2].clip(mymaxvel.neg,mymaxvel);\r\n\t\tagents[agent][3] = agents[agent][3].clip(mymaxvel.neg,mymaxvel);\r\n\r\n\t\t// update position based on velocity and friction\r\n\t\t//x = x + (vx*(1-myfriction));\r\n\t\t//y = y + (vy*(1-myfriction));\r\n\t\tagents[agent][0] = agents[agent][0] + (agents[agent][2]*(1-myfriction));\r\n\t\tagents[agent][1] = agents[agent][1] + (agents[agent][3]*(1-myfriction));\r\n\r\n\t\tthis.twrap(agent); // torus space\r\n\t}\r\n\r\n\t// rules (a is the index of an agent in the agents array)\r\n\tseparate { |a|\r\n\t\tvar dx,dy,proxscale,mag;\r\n\r\n\t\t// run from positions of neighbors\r\n\t\tfor(0,myagentcount-1,{ |i|\r\n\t\t\tif(a != i,{\r\n\t\t\t\tdx = agents[i][0] - agents[a][0];\r\n\t\t\t\tdy = agents[i][1] - agents[a][1];\r\n\r\n\t\t\t\t//torus space\r\n\t\t\t\tif(dx>0.5,{\r\n\t\t\t\t\tdx = dx - 1;\r\n\t\t\t\t\t},{\r\n\t\t\t\t\t\tif(dx<0.5.neg,{\r\n\t\t\t\t\t\t\tdx = dx + 1;\r\n\t\t\t\t\t\t});\r\n\t\t\t\t});\r\n\t\t\t\tif(dy>0.5,{\r\n\t\t\t\t\tdy = dy - 1;\r\n\t\t\t\t\t},{\r\n\t\t\t\t\t\tif(dy<0.5.neg,{\r\n\t\t\t\t\t\t\tdy = dy + 1;\r\n\t\t\t\t\t\t});\r\n\t\t\t\t});\r\n\r\n\t\t\t\tif((abs(dx)>1e-4)&&(abs(dy)>1e-4),{\r\n\t\t\t\t\tmag = (dx*dx)+(dy*dy); // cheap mag, no sqrt\r\n\t\t\t\t\t},{\r\n\t\t\t\t\t\tmag = 0.01;\r\n\t\t\t\t});\r\n\r\n\t\t\t\tif(mag<mysepthresh,{\r\n\t\t\t\t\tif (mag<1e-4,{\r\n\t\t\t\t\t\tproxscale = 8;\r\n\t\t\t\t\t\t},{\r\n\t\t\t\t\t\t\tproxscale = (mysepthresh /\r\n\t\t\t\t\t\t\t\t(mysepthresh-(mysepthresh-mag))).clip(0,8);\r\n\t\t\t\t\t});\r\n\r\n\t\t\t\t\tagents[a][2] = agents[a][2] - (dx*myseparation*proxscale);\r\n\t\t\t\t\tagents[a][3] = agents[a][3] - (dy*myseparation*proxscale);\r\n\t\t\t\t\t}\r\n\t\t\t\t);\r\n\t\t\t\t}\r\n\t\t\t);\r\n\t\t\t}\r\n\t\t);\r\n\t}\r\n\r\n\talign { |a|\r\n\t\tvar dvx,dvy;\r\n\r\n\t\t// conform to velocities towards average velocity\r\n\t\tdvx = avgvelocity_x - agents[a][2];\r\n\t\tdvy = avgvelocity_y - agents[a][3];\r\n\r\n\t\tagents[a][2] = agents[a][2] + (dvx*myalignment);\r\n\t\tagents[a][3] = agents[a][3] + (dvy*myalignment);\r\n\t}\r\n\r\n\tcohere { |a|\r\n\t\tvar dx,dy;\r\n\r\n\t\t// move towards center of mass\r\n\t\tdx = centroid_x - agents[a][0];\r\n\t\tdy = centroid_y - agents[a][1];\r\n\r\n\t\tagents[a][2] = agents[a][2] + (dx*mycoherence);\r\n\t\tagents[a][3] = agents[a][3] + (dy*mycoherence);\r\n\t}\r\n\r\n\tgravitate { |a|\r\n\t\tvar dx,dy;\r\n\r\n\t\t// move towards center\r\n\t\tdx = mygravpoint_x - agents[a][0];\r\n\t\tdy = mygravpoint_y - agents[a][1];\r\n\r\n\t\tagents[a][2] = agents[a][2] + (dx*mygravity);\r\n\t\tagents[a][3] = agents[a][3] + (dy*mygravity);\r\n\t}\r\n\r\n\t// utility functions\r\n\ttwrap { |a|\r\n\t\tif(agents[a][0]<0,{\r\n\t\t\tagents[a][0] = agents[a][0] + 1;\r\n\t\t\t},{\r\n\t\t\t\tif(agents[a][0]>1,{\r\n\t\t\t\t\tagents[a][0] = agents[a][0] - 1;\r\n\t\t\t\t});\r\n\t\t});\r\n\r\n\t\tif(agents[a][1]<0,{\r\n\t\t\tagents[a][1] = agents[a][1] + 1;\r\n\t\t\t},{\r\n\t\t\t\tif(agents[a][1]>1,{\r\n\t\t\t\t\tagents[a][1] = agents[a][1] - 1;\r\n\t\t\t\t});\r\n\t\t});\r\n\t}\r\n\r\n\t// not in use atm\r\n\tbounce { |a|\r\n\t\tif ((agents[a][0]<0)||(agents[a][0]>1), {\r\n\t\t\tagents[a][2] = agents[a][2].neg;\r\n\t\t});\r\n\t\tif ((agents[a][1]<0)||(agents[a][1]>1), {\r\n\t\t\tagents[a][3] = agents[a][3].neg;\r\n\t\t});\r\n\r\n\t}\r\n\r\n\t// set var vunctions\r\n\tseparation { |v|\r\n\t\tmyseparation = v.clip(0,1)*0.1;\r\n\t}\r\n\r\n\talignment { |v|\r\n\t\tmyalignment = v.clip(0,1)*0.1;\r\n\t}\r\n\r\n\tcoherence { |v|\r\n\t\tmycoherence = v.clip(0,1)*0.1;\r\n\t}\r\n\r\n\tfriction { |v|\r\n\t\tmyfriction = v.clip(0,1);\r\n\t}\r\n\r\n\tinertia { |v|\r\n\t\tmyinertia = v.clip(0,1);\r\n\t}\r\n\r\n\tsepthresh { |v|\r\n\t\tmysepthresh = v.clip(0,0.5);\r\n\t}\r\n\r\n\tmaxvel { |v|\r\n\t\tmymaxvel = v.clip(0,1)*0.1;\r\n\t}\r\n\r\n\tgravity { |v|\r\n\t\tmygravity = v.clip(-1,1)*0.1;\r\n\t}\r\n\r\n\tgravpoint { |x,y|\r\n\t\tmygravpoint_x = x.clip(0,1);\r\n\t\tmygravpoint_y = y.clip(0,1);\r\n\t}\r\n}",
   "id" : "1-4RY",
   "is_private" : null,
   "labels" : [
      "class",
      "simulation",
      "swarm",
      "boids",
      "port"
   ]
}
