Skip to content

Instantly share code, notes, and snippets.

@slacktracer
Created November 13, 2021 20:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save slacktracer/3ccb61b902746ae85e084551fe51edf6 to your computer and use it in GitHub Desktop.
Save slacktracer/3ccb61b902746ae85e084551fe51edf6 to your computer and use it in GitHub Desktop.
agar.evo
/* !ideas!
add an inherited trait to splitting
?connect processes like moving speed and resting to comsumption of mass?
add abilty to quickly run canvas off screen without drawing
spectate focus jumps around on low raidus cells
also can crash on low raidus cells
maybe give every cell a unique id for tracking and sorting
think of other traits for cells to pass on
add in a way to control how many 1/dist there are as a cell trait.
add in regions to the game space so that cells only have to think about objects nearby
make an array that lists the cells in order of radius for drawing order
give each cell a team ID
cells will not dividing into or chase the same team ID
let that ID evolve so that 5% of the time the ID will shift to a new ID
use cell name as the team ID
AI visualization for focused cell?
cell division trait: reuse for determining how often a cell will divide
range, lower size limit?
have food pellet grow until hitting a cap of 5 like in the game
*/
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
document.body.appendChild(canvas);
window.onresize = function(event) {
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
};
//game bounds
var container = new function() {
this.foodID = 0;
this.cycle = 0; //cycle keeps track of the interations of the game loop
this.pause = false;
this.spectate = true;
this.visualize = true;
this.info = false;
this.cellFocus = 0;
this.nextFocus = function() {
container.cellFocus++;
if (container.cellFocus > cell.length - 1) container.cellFocus = 0;
};
this.CameraX = 0;
this.CameraY = 0;
this.width = 10000; // size of the map //10000
this.height = 8000; // size of the map //6000
this.friction = 0.97; //closer to 1 means higher speeds and less turning
this.speed = 0.1; //controls thrust per cycle from cells
this.divideSpeed = 20; //speed that cell mopve at after a division at 30 it lets them move about 1000 befor ethey slow down (at speed = 0.09 and friciton =0.97)
this.scale = 0.01; //the zoom
this.scaleGoal = 0.2; //what the scale will smoothly move towards
this.totalFood = (this.width * this.height) * 0.0000100; //0.0000150
this.totalVirus = (this.width * this.height) * 0.0000002; //0.0000003
this.totalCells = (this.width * this.height) * 0.0000005; //0.0000010
this.nameMutationRate = 0.1;
};
//container.scaleGraphPaper();
//small scale testing setup comment this out for full scale
/*
container.width = 3600;
container.height = 2600;
container.scaleGoal = 0.34;
container.spectate = false;
container.totalFood = 500;
container.totalVirus = 6;
container.totalCells = 8
*/
/*
//huge scale testing setup comment this out for full scale
container.width = 40000;
container.height = 20000;
container.scaleGoal = 0.1;
container.spectate = false;
container.totalFood = 2000;
container.totalVirus = 20;
container.totalCells = 20;
*/
var gui = new dat.GUI();
//gui.close();
gui.add(container, 'info');
gui.add(container, 'pause');
scontroller = gui.add(container, 'spectate');
scontroller.onFinishChange(function(value) {
container.scaleGoal = 0.14;
});
gui.add(container, 'scaleGoal', 0.1, 1);
//gui.add(container, 'nextFocus');
var guiSettings = gui.addFolder('environment');
guiSettings.add(container, 'speed', 0.01, 1).step(0.01);
guiSettings.add(container, 'friction', 0.9, .999).step(0.001);
guiSettings.add(container, 'width', 100, 20000).step(100);
guiSettings.add(container, 'height', 100, 20000).step(100);
var fcontroller = guiSettings.add(container, 'totalFood', 0, 3000).step(1);
fcontroller.onFinishChange(function(value) {
if (food.length > container.totalFood) food.splice(value);
});
var vcontroller = guiSettings.add(container, 'totalVirus', 0, 100).step(1);
vcontroller.onFinishChange(function(value) {
if (virus.length > container.totalVirus) virus.splice(value);
});
var ccontroller = guiSettings.add(container, 'totalCells', 1, 200).step(1);
ccontroller.onFinishChange(function(value) {
//if (cell.length>container.totalCells) cell.length = value;
if (cell.length > container.totalCells) cell.splice(value);
});
//repeating check to spawn food up the max value
function spawner() {
if (food.length < container.totalFood) {
pushFood(Math.random() * container.width, Math.random() * container.height);
}
if (cell.length < container.totalCells) {
newCellRandom();
}
if (virus.length < container.totalVirus) {
pushVirus();
}
}
function randomName() {
var text = "";
var possible = "abcdefghijklmnopqrstuvwxyz";
//capitalized first letter
text += possible.charAt(Math.floor(Math.random() * possible.length));
text = text.toUpperCase();
//add a random number of other letters
for (var k = 0; k < 3 + Math.round(Math.random() * 10); k++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
text[0] = text.charAt(0).toUpperCase()
return text;
}
//replace a char in a string function also a chance to just add a letter or remove a letter at the replacement site
String.prototype.mutateName = function(index) {
var possible = "abcdefghijklmnopqrstuvwxyz";
return this.substr(0, index + Math.round(2 * (Math.random() - 0.5))) + possible.charAt(Math.floor(Math.random() * possible.length)) + this.substr(index + 1);
}
var cell = [];
function pushCell(x, y, Vx, Vy, r, name, color, division, inertia, seekFood, seekCell, fleeCell, fleeVirus) {
cell.push({
alive: true,
Vx: Vx, //Velocity in x direction on spawn
Vy: Vy, //Velocity in Y direction on spawn
zone: {
x: 0,
y: 0
},
dir: 0, //direction cell is moving
rDraw: 0, //makes cell radius changes look smooth
stroke: "", //cell outline color is always a bit darker then fill color
//traits that evolve / are passed on with division
x: x, //Math.random() * container.width,
y: y, //Math.random() * container.height,
r: r, //30, //30
name: name,
color: color, ///rainbow in is color library file
textColor: "",
division: division, //100 if cell raidus goes above this division occurs
inertia: inertia, //0.000002 higher means less turning, lower is more jerky
seekFood: seekFood, //1 1/dist^3
seekCell: seekCell, //30 1/dist^3
fleeCell: fleeCell, //8000 1/dist^4
fleeVirus: fleeVirus, //5 1/dist^4
});
//set cell stroke to be a bit darker than fill
cell[cell.length - 1].stroke = ColorLuminance(cell[cell.length - 1].color, -0.1);
//set text color to be a color that readable compared to the body color
cell[cell.length - 1].textColor = invertCssColor(cell[cell.length - 1].color);
}
function newCellRandom() {
pushCell(Math.random() * container.width, //x
Math.random() * container.height, //y
0,
0,
30, //r
randomNameAustin(), //name
rainbow(32, Math.floor(Math.random() * 32)), //color
Math.random() * 500, //division 200
Math.random() * 100000, //inertia 100000/10000000 = 0.1
//50-50 chance of having negative traits
(0.5 - Math.random()) * 20000, //seekFood
(0.5 - Math.random()) * 20000, //seekCell
(0.5 - Math.random()) * 20000, //fleeCell
(0.5 - Math.random()) * 20000 //fleeVirus
/*
//all traits have the "best" number sign
Math.random() * 10000, //seekFood
Math.random() * 10000, //seekCell
Math.random() * -10000, //fleeCell
Math.random() * -10000 //fleeVirus
*/
);
}
for (var i = 0; i < container.totalCells; i++) {
newCellRandom()
}
//this.speed = 0.08 * (1 + 150 / this.r + 4000 / this.r / this.r)
//if (this.r > 50) this.r = 0.99995 * this.r - 0.00000005 * this.r * this.r
function cellDivision(i, dir) {
//original cell knock back
//cell[i].Vx = -Math.cos(dir);
//cell[i].Vy = -Math.sin(dir);
//pushCell(x,y,Vx,Vy,r,name,color,division,inertia,seekFood,seekCell,fleeCell,fleeVirus)
pushCell(cell[i].x + cell[i].r * Math.cos(dir),
cell[i].y + cell[i].r * Math.sin(dir),
container.divideSpeed * Math.cos(dir),
container.divideSpeed * Math.sin(dir),
cell[i].r, cell[i].name, colorMutate(cell[i].color), cell[i].division, cell[i].inertia,
cell[i].seekFood, cell[i].seekCell, cell[i].fleeCell, cell[i].fleeVirus
);
//mutations values shift by up to +-10%
cell[i].division += cell[i].division * (0.5 - Math.random()) * 0.20;
cell[i].inertia += cell[i].inertia * (0.5 - Math.random()) * 0.20;
cell[i].seekFood += cell[i].seekFood * (0.5 - Math.random()) * 0.20;
cell[i].seekCell += cell[i].seekCell * (0.5 - Math.random()) * 0.20;
cell[i].fleeCell += cell[i].fleeCell * (0.5 - Math.random()) * 0.20;
cell[i].fleeVirus += cell[i].fleeVirus * (0.5 - Math.random()) * 0.20;
//10% chance to mutate name
if (Math.random() < container.nameMutationRate) {
cell[i].name = cell[i].name.mutateName(Math.floor(Math.random() * cell[i].name.length));
}
//cell[i].color = cell[i].color.mutateColor();
//cell[i].stroke = ColorLuminance(cell[i].color, -0.1)
}
function cellMove() {
var cellLength = cell.length;
for (var i = 0; i < cellLength; i++) {
//determine zone
cell[i].zone.x = Math.floor(cell[i].x / 1000);
cell[i].zone.y = Math.floor(cell[i].y / 1000);
//AI
//inertia range: good around (0.0001) no negatives (evolving range 1 to 0.00001)
var inertia = cell[i].inertia / 10000000;
var vector = {
x: inertia * Math.cos(cell[i].dir),
y: inertia * Math.sin(cell[i].dir)
};
var length = food.length; //move towards food
for (var j = 0; j < length; j++) {
var dx = food[j].x - (cell[i].x);
var dy = food[j].y - (cell[i].y);
var dist = Math.sqrt(dx * dx + dy * dy) - cell[i].r;
dx = cell[i].seekFood * dx / dist / (dist * dist * cell[i].r);
dy = cell[i].seekFood * dy / dist / (dist * dist * cell[i].r);
vector.x += dx;
vector.y += dy;
}
length = virus.length; //avoid viruses
for (j = 0; j < length; j++) {
if (virus[j].r < cell[i].r) {
var dy = virus[j].y - (cell[i].y);
var dx = virus[j].x - (cell[i].x);
var dist = Math.sqrt(dx * dx + dy * dy) - cell[i].r;
dx = cell[i].fleeVirus * dx / dist / (dist * dist * dist * dist) * 1000;
dy = cell[i].fleeVirus * dy / dist / (dist * dist * dist * dist) * 1000;
vector.x += dx;
vector.y += dy;
}
}
length = cell.length; //chase and run from cells
for (j = 0; j < length; j++) {
//if (i != j) {
//START AI
if (cell[i].name != cell[j].name) {
var dx = cell[j].x - cell[i].x;
var dy = cell[j].y - cell[i].y;
var dist = Math.sqrt(dx * dx + dy * dy) - cell[i].r;
//seekCell
if (cell[i].r > cell[j].r * 1.12) { //chase smaller cells
dx = dx / dist / (dist * dist * dist);
dy = dy / dist / (dist * dist * dist);
sizeWeight = cell[j].r * cell[j].r; //larger cells are more valuable and eaiser to catch
vector.x += cell[i].seekCell * dx * sizeWeight;
vector.y += cell[i].seekCell * dy * sizeWeight;
//check for division target
if (cell[i].seekCell > 0 && cell[j].fleeCell < 0 && //if you chase and they run
cell[i].r * 0.65 > cell[j].r * 1.12 && // if the cell is big enough to eat
cell[j].r * 1.5 > cell[i].r * 0.65 && //if the cell is large enough to be worth eatting
dist < 250 && dist > 150 && // if the cell isn't too close or too far
cell[i].r * 0.65 > 40) { //if you are big enough to split and not starve
//There is a cost to division so less than 0.707
cell[i].r *= 0.65; //radius*1/2^(0.5) because of volume.
var dirX = (cell[j].x + 10 * cell[j].Vx) - cell[i].x;
var dirY = (cell[j].y + 10 * cell[j].Vy) - cell[i].y;
cellDivision(i, Math.atan2(dirY, dirX));
}
//fleeCell
} else if (cell[i].r < cell[j].r) { //run from bigger cells
dx = dx / dist / (dist * dist * dist * dist) * 1000;
dy = dy / dist / (dist * dist * dist * dist) * 1000;
vector.x += cell[i].fleeCell * dx;
vector.y += cell[i].fleeCell * dy;
}
//END AI
}
//eat smaller cells
if (cell[i].r > cell[j].r * 1.1) {
var x = cell[i].x - cell[j].x;
var y = cell[i].y - cell[j].y;
var d = Math.sqrt(x * x + y * y);
if (d < cell[i].r) {
//Volume+volume = volume PIr^2+PIr^2 =PIr^r root(r^2+r^2)=new r
cell[i].r = Math.sqrt(cell[i].r * cell[i].r + cell[j].r * cell[j].r)
cell[j].alive = false;
}
}
}
//direction
cell[i].dir = Math.atan2(vector.y, vector.x);
//move
var speed = container.speed * (2 + 50 / cell[i].r) // + 2000 / cell[i].r / cell[i].r)
cell[i].Vx = container.friction * cell[i].Vx + speed * Math.cos(cell[i].dir);
cell[i].Vy = container.friction * cell[i].Vy + speed * Math.sin(cell[i].dir);
cell[i].x += cell[i].Vx;
cell[i].y += cell[i].Vy;
//walls
if (cell[i].x < 0) {
cell[i].x = 0;
cell[i].Vx = 0;
} else if (cell[i].x > container.width) {
cell[i].x = container.width;
cell[i].Vx = 0;
}
if (cell[i].y < 0) {
cell[i].y = 0;
cell[i].Vy = 0;
} else if (cell[i].y > container.height) {
cell[i].y = container.height;
cell[i].Vy = 0;
}
//mass loss
cell[i].r *= 0.99999;
//starve?
if (cell[i].r < 20) { //dont' switch r to r draw here or script will make too many new cells
cell[i].alive = false;
for (var k = 0; k < 3; k++) { //spawn some food where cell dies
pushFood(cell[i].x + 25 - Math.random() * 50, cell[i].y + 25 - Math.random() * 50);
};
}
/*
//divide?
else if (cell[i].seekCell < 0 && cell[i].r > cell[i].division) {
//There is a cost to division so less than 0.707
cell[i].r *= 0.65; //radius*1/2^(0.5) because of volume.
cellDivision(i, -cell[i].dir);
}
*/
//touching virus
j = virus.length
while (j--) {
if (cell[i].r > virus[j].r) {
var x = virus[j].x - cell[i].x
var y = virus[j].y - cell[i].y
var d = Math.sqrt(x * x + y * y);
if (d < cell[i].r) {
var spawnCells = 0;
//for big cells divide into 10 cells with larger raidus
if (cell[i].r > 95) { // 94 = root(10 x 30^2) = root(spawnCells x (new cellRadius)^2)
if (cell[i].r > 300) {
if (cell[i].r > 400) cell[i].r = 400; //cell radius can't be too big
//relocate virus on hitting large cells
virus[j].x = Math.random() * container.width;
virus[j].y = Math.random() * container.height;
virus[j].r = 80 + Math.random() * 25;
}
spawnCells = 10;
cell[i].r /= Math.sqrt(spawnCells);
//relocate virus for large cell collisions
} else { // for smaller cells dividing into up to 10 cells
spawnCells = Math.round(Math.sqrt(cell[i].r * cell[i].r / (30 * 30)));
cell[i].r = 30;
}
for (var k = 0; k < spawnCells; k++) { //spawn mutated versions of mother cell
cellDivision(i, Math.random() * 6.28);
}
}
}
}
}
var k = cell.length;
while (k--) {
//die (needs to come at the end of the while loop)
if (!cell[k].alive) {
cell.splice(k, 1);
}
}
}
var virus = [];
function pushVirus() {
virus.push({
x: Math.random() * container.width,
y: Math.random() * container.height,
r: 80 + Math.random() * 25,
});
}
//spawn viruses at start
for (var i = 0; i < container.totalVirus; i++) {
pushVirus();
}
var food = [];
//build a 10x10 array to track zones
/* var zone = [];
for (var i = 0; i < 10; i++) {
zone.push([]);
}
for (var j = 0; j < 10; j++) {
for (var i = 0; i < 10; i++) {
zone[i].push([]);
}
} */
//new food cells are pushed into a zone
//find food by each food's id and remove them from the array when eaten
//https://www.w3schools.com/jsref/jsref_indexof_array.asp
//use index of to find the index needed to delete
function pushFood(x, y) {
food.push({
id: container.foodID, //IDs are used to that food can be removed from the zone tracker after it is eaten
x: x,
y: y,
color: rainbow(32, Math.floor(Math.random() * 32)),
r: 12,
rShift: Math.random() * 2 * Math.PI,
angle: Math.random() * 2 * Math.PI
});
//add food to food zone tracker
/* var i = food.length - 1;
var zX = Math.floor(food[i].x / 1000);
var zY = Math.floor(food[i].y / 1000);
//add 3 array eleemnt at a time
zone[zX][zY].push(food[i].id,food[i].x,food[i].y);
container.foodID += 3; */
}
//spawn food at start
for (var z = 0; z < container.totalFood; z++) {
pushFood(Math.random() * container.width, Math.random() * container.height);
}
//check if player is near food
function touchingFood() {
var length = cell.length;
for (var j = 0; j < length; j++) {
var i = food.length;
while (i--) {
var dX = food[i].x - cell[j].x;
var dY = food[i].y - cell[j].y;
var dist = Math.sqrt(dX * dX + dY * dY);
if (dist < cell[j].r - 2 * food[i].r) {
cell[j].r = Math.sqrt(cell[j].r * cell[j].r + food[i].r * food[i].r);
//remove food from zone array
/* var zoneX = Math.floor(food[i].x / 1000);
var zoneY = Math.floor(food[i].y / 1000);
var index = zone[zoneX][zoneY].indexOf(food[i].id)
zone[zoneX][zoneY].splice(index,3); */
//remove from food array
food.splice(i, 1);
//player.waves += ((Math.random() > 0.5) ? 1 : -1);
} else if (dist < cell[j].r + food[i].r * 2) {
var y = cell[j].y - food[i].y;
var x = cell[j].x - food[i].x;
var angle = Math.atan2(y, x);
var speed = 1 + Math.sqrt(cell[j].Vx * cell[j].Vx + cell[j].Vy * cell[j].Vy);
food[i].x += speed * Math.cos(angle); // + cell[j].Vx;
food[i].y += speed * Math.sin(angle); // + cell[j].Vy;
}
}
}
}
function draw() {
//clear screen
ctx.clearRect(0, 0, canvas.width, canvas.height);
//scale and translate
//exponential function that controls how scale depends on cell raidus
if (container.spectate) {
container.scaleGoal = 0.83 * Math.exp(-0.001941 * cell[container.cellFocus].r);
}
if (container.scaleGoal < 0.1) container.scaleGoal = 0.1; //max zoom
container.scale += (container.scaleGoal - container.scale) * 0.01; //smooth zooming
container.CameraX += (cell[container.cellFocus].x - container.CameraX) * 0.03; //smooth translation X
container.CameraY += (cell[container.cellFocus].y - container.CameraY) * 0.03; //smooth translation Y
//transforms and rotates the canvas camera
ctx.save();
ctx.scale(container.scale, container.scale);
if (container.spectate) {
ctx.translate(window.innerWidth * 0.5 / container.scale - container.CameraX, window.innerHeight * 0.5 / container.scale - container.CameraY);
} else {
ctx.translate(50, 50);
}
//draw graph paper background
var size = 50;
var length = Math.ceil(container.width / size) + 1;
ctx.lineWidth = 0.5;
ctx.strokeStyle = '#707070';
ctx.beginPath();
for (var i = 0; i < length; i++) {
ctx.moveTo(i * size, 0);
ctx.lineTo(i * size, container.height);
}
var length = Math.ceil(container.height / size) + 1;
for (var i = 0; i < length; i++) {
ctx.moveTo(0, i * size);
ctx.lineTo(container.width, i * size);
}
ctx.stroke();
//draw food
length = food.length;
var root3p2 = Math.sqrt(3) / 2
for (var i = 0; i < length; i++) {
ctx.fillStyle = food[i].color;
if (container.scale > 0.4) { //if zoomed in draw hexagons
ctx.save();
food[i].angle += 0.007; //food rotation speed
food[i].r = 12 + 1 * Math.sin(container.cycle * 0.08 + food[i].rShift);
ctx.translate(food[i].x, food[i].y);
ctx.rotate(food[i].angle);
ctx.translate(-food[i].x, -food[i].y);
ctx.beginPath();
ctx.lineTo(food[i].x + 0.5 * food[i].r, food[i].y + root3p2 * food[i].r);
ctx.lineTo(food[i].x + food[i].r, food[i].y);
ctx.lineTo(food[i].x + 0.5 * food[i].r, food[i].y - root3p2 * food[i].r);
ctx.lineTo(food[i].x - 0.5 * food[i].r, food[i].y - root3p2 * food[i].r);
ctx.lineTo(food[i].x - food[i].r, food[i].y);
ctx.lineTo(food[i].x - 0.5 * food[i].r, food[i].y + root3p2 * food[i].r);
ctx.closePath();
ctx.fill();
ctx.restore();
} else { // if zoomed out just draw circles
ctx.beginPath();
ctx.arc(food[i].x, food[i].y, food[i].r, 0, 2 * Math.PI);
ctx.fill();
}
}
//draw cells
ctx.globalAlpha = 0.9
ctx.textAlign = "center";
length = cell.length;
for (var i = length - 1; i > -1; i--) {
cell[i].rDraw += (cell[i].r - cell[i].rDraw) * 0.07; //controls cell raidus zoom
ctx.lineWidth = 12;
ctx.fillStyle = cell[i].color;
ctx.beginPath();
ctx.arc(cell[i].x, cell[i].y, cell[i].rDraw, 0, 2 * Math.PI);
ctx.fill();
ctx.strokeStyle = cell[i].stroke;
ctx.stroke();
//cell names
ctx.lineWidth = 2;
//ctx.font = "bold " + Math.floor(24 + cell[i].rDraw / 8) + "px Arial";
ctx.font = "bold " + Math.floor(6 + cell[i].rDraw / 5) + "px Arial";
//ctx.fillStyle = 'white';
//ctx.fillStyle = invertCssColor(cell[i].color);
ctx.fillStyle = cell[i].textColor;
ctx.fillText(cell[i].name, cell[i].x, cell[i].y + 5);
}
//draw viruses
length = virus.length;
for (var i = 0; i < length; i++) {
ctx.fillStyle = 'lime';
ctx.lineWidth = 7;
ctx.strokeStyle = '#00e600';
ctx.beginPath();
if (container.scale > 0.4) { //if zoomed in draw spikes
var amp = 2.5;
var sineCount = 40;
//for loop is sinecount*4
//angle = 360/(sineCount*4) * Math.PI / 180 * j;
for (var j = 0; j < 160; j++) {
var angle = 0.03927 * j; //0.0448798951 * j;
var x = Math.round(virus[i].x + (virus[i].r + amp * Math.sin(sineCount * angle)) * Math.cos(angle));
var y = Math.round(virus[i].y + (virus[i].r + amp * Math.sin(sineCount * angle)) * Math.sin(angle));
ctx.lineTo(x, y);
}
} else {
ctx.arc(virus[i].x, virus[i].y, virus[i].r, 0, 2 * Math.PI);
}
ctx.closePath();
ctx.fill();
ctx.stroke();
}
ctx.globalAlpha = 1;
//info for all on screen
if (container.info) {
var length = cell.length;
ctx.textAlign = "left";
ctx.font = "15px Arial";
for (var i = 0; i < length; i++) {
ctx.save();
ctx.translate(cell[i].x, cell[i].y - cell[i].r - 3);
ctx.scale(1 / container.scale, 1 / container.scale);
var x = -60
ctx.fillStyle = "rgba(0, 0, 0, 0.5)";
ctx.fillRect(x - 5, -5, 130, -110);
ctx.fillStyle = 'white';
ctx.fillText("seekFood = " + Math.round(cell[i].seekFood), x, -100);
ctx.fillText("seekCell = " + Math.round(cell[i].seekCell), x, -85);
ctx.fillText("fleeCell = " + Math.round(cell[i].fleeCell), x, -70);
ctx.fillText("fleeVirus = " + Math.round(cell[i].fleeVirus), x, -55);
ctx.fillText("inertia = " + Math.round(cell[i].inertia), x, -40);
ctx.fillText("division = " + Math.round(cell[i].division), x, -25);
ctx.fillText("radius = " + Math.round(cell[i].r), x, -10);
ctx.restore();
}
}
ctx.restore(); //undo translate and scale effects
//player info
/* if (container.spectate) {
ctx.fillStyle = "rgba(0, 0, 0, 0.5)";
//ctx.fillRect(8, window.innerHeight - 5, 120, -60);
ctx.fillRect(8, window.innerHeight - 5, 120, -110);
ctx.fillStyle = 'white';
ctx.textAlign = "left";
ctx.font = "15px Arial";
ctx.fillText("seekFood = " + Math.round(cell[container.cellFocus].seekFood), 11, window.innerHeight - 100);
ctx.fillText("seekCell = " + Math.round(cell[container.cellFocus].seekCell), 11, window.innerHeight - 85);
ctx.fillText("fleeCell = " + Math.round(cell[container.cellFocus].fleeCell), 11, window.innerHeight - 70);
ctx.fillText("fleeVirus = " + Math.round(cell[container.cellFocus].fleeVirus), 11, window.innerHeight - 55);
ctx.fillText("inertia = " + Math.round(cell[container.cellFocus].inertia), 11, window.innerHeight - 40);
ctx.fillText("division = " + Math.round(cell[container.cellFocus].division), 11, window.innerHeight - 25);
ctx.fillText("radius = " + Math.round(cell[container.cellFocus].r), 11, window.innerHeight - 10);
//leader board
ctx.fillStyle = "rgba(0, 0, 0, 0.5)";
ctx.fillRect(window.innerWidth - 5, 25, -200, 320);
ctx.fillStyle = 'white';
ctx.textAlign = "center";
ctx.font = "bold 26px Arial";
ctx.fillText("Leaderboard", window.innerWidth - 105, 55);
ctx.font = "bold 19px Arial";
var leaderLength = 10;
if (cell.length < 10) leaderLength = cell.length;
for (var i = 0; i < leaderLength; i++) {
ctx.fillText(i + 1 + ". " + cell[i].name, window.innerWidth - 105, 88 + i * 27);
}
} */
}
function cycle() {
container.cycle++;
draw();
if (!container.pause) {
touchingFood();
cellMove();
spawner();
}
requestAnimationFrame(cycle);
}
requestAnimationFrame(cycle);
var myVar = setInterval(function() {
sortCells();
}, 6000);
function sortCells() {
// sort by value
cell.sort(function(a, b) {
if (a.r > b.r) return -1; //flip the signs on the 1s to reverse order
if (a.r < b.r) return 1;
return 0;
});
}
function colorMutate(color) {
var index = Math.ceil(Math.random() * 6)
var char = color.charAt(index);
if (Math.random() > 0.5) {
char = shiftCharUp(char);
char = shiftCharUp(char);
} else if (Math.random() > 0.5) {
char = shiftCharDown(char);
char = shiftCharDown(char);
}
return color.substr(0, index) + char + color.substr(index + 1);
}
function shiftCharUp(char) {
switch (char) {
case "0":
char = '1'
break;
case "1":
char = '2'
break;
case "2":
char = '3'
break;
case "3":
char = '4'
break;
case "4":
char = '5'
break;
case "5":
char = '6'
break;
case "6":
char = '7'
break;
case "7":
char = '8'
break;
case "8":
char = '9'
break;
case "9":
char = 'a'
break;
case "a":
char = 'b'
break;
case "b":
char = 'c'
break;
case "c":
char = 'd'
break;
case "d":
char = 'e'
break;
default:
char = 'f'
}
return char;
}
function shiftCharDown(char) {
switch (char) {
case "2":
char = '1'
break;
case "3":
char = '2'
break;
case "4":
char = '3'
break;
case "5":
char = '4'
break;
case "6":
char = '5'
break;
case "7":
char = '6'
break;
case "8":
char = '7'
break;
case "9":
char = '8'
break;
case "a":
char = '9'
break;
case "b":
char = 'a'
break;
case "c":
char = 'b'
break;
case "d":
char = 'c'
break;
case "e":
char = 'd'
break;
case "f":
char = 'e'
break;
default:
char = '0'
}
return char;
}
function randomNameAustin(){
var name= ['Arron','Adam','Adrian','Alan','Alex','Albert','Alec','Alvin','Armando','Anderson','Andres','Andrew','Anthony','Anton','Antonio','Arnold','Alejandro','Ben','Boe','Blake','Byron','Bjorn','Bart','Bin','Boof','Bartholemeu','Birtha','Alexa','Erin','Charles','Charlie','Chalk','Chalupa','Candice','Chatauqua','Channing','Cody','Colonel','Drew','Dendrite','Dawn','Dorothy','Dibble','Dolby','Drake','Effigy','Ephemeral','Endive','Eloquent','Fat','Full','Fun','Fandrew','Guy','Gory','Gland','Gargantuant','Glop','Gope','Hilt','Hunter','Huntington','Igloo','Ink','Interior','Jack','Jalopy','Jaunt','Jubilance','Kool','Kwan','Knox','Krook','Lewis','Lawn','Lorpe','Link','Latch','Man','Mourn','Map','Maude','Max','Nando','Null','Nix','Ophelia','Operation','Prawn','Paul','Patricia'];
var adj= ['Arcadian',
'Baleful',
'Bellicose',
'Bilious',
'Boorish',
'Calamitous',
'Caustic',
'Cerulean',
'Comely',
'Concomitant',
'Contumacious',
'Corpulent',
'Crapulous',
'Defamatory',
'Didactic',
'Dilatory',
'Dowdy',
'Efficacious',
'Effulgent',
'Egregious',
'Endemic',
'Equanimous',
'Execrable',
'Fastidious',
'Feckless',
'Fecund',
'Friable',
'Fulsome',
'Garrulous',
'Guileless',
'Gustatory',
'Heuristic',
'Histrionic',
'Hubristic',
'Incendiary',
'Insidious',
'Insolent',
'Intransigent',
'Inveterate',
'Invidious',
'Irksome',
'Jejune',
'Jocular',
'Judicious',
'Lachrymose',
'Limpid',
'Loquacious',
'Luminous',
'Mannered',
'Mendacious',
'Meretricious',
'Minatory',
'Mordant',
'Munificent',
'Nefarious',
'Noxious',
'Obtuse',
'Parsimonious',
'Pendulous',
'Pernicious',
'Pervasive',
'Petulant',
'Platitudinous',
'Precipitate',
'Propitious',
'Puckish',
'Querulous',
'Quiescent',
'Rebarbative',
'Recalcitrant',
'Redolent',
'Rhadamanthine',
'Risible',
'Ruminative',
'Sagacious',
'Salubrious',
'Sartorial',
'Sclerotic',
'Serpentine',
'Spasmodic',
'Strident',
'Taciturn',
'Tenacious',
'Tremulous',
'Trenchant',
'Turbulent',
'Turgid',
'Ubiquitous',
'Uxorious',
'Verdant',
'Voluble',
'Voracious',
'Wheedling',
'Withering',
'Zealous',
];
var adjselec = adj[Math.floor(Math.random() * adj.length)];
var nameselec = name[Math.floor(Math.random() * name.length)];
return adjselec +' ' + nameselec;
}
/*
function AI() {
//moves towards the sum of all distance wieghted food pointing vectors
var inertia = 0.000002 // a larger coefficient makes the bot less likely to change direction
var vector = {
x: inertia * Math.cos(player.dir),
y: inertia * Math.sin(player.dir)
};
if (container.visual) {
ctx.strokeStyle = 'rgba(0, 255, 0, 0.3)';//'green';
ctx.lineWidth = 4;
ctx.beginPath();
ctx.moveTo(0.5 * window.innerWidth, 0.5 * window.innerHeight);
ctx.lineTo(300000000 * vector.x + 0.5 * window.innerWidth, 300000000 * vector.y + 0.5 * window.innerHeight);
ctx.stroke();
ctx.lineWidth = 1;
ctx.strokeStyle = 'black';
}
var length = food.length;
for (var i = 0; i < length; i++) {
var dy = food[i].y - (player.y);
var dx = food[i].x - (player.x);
var dist = Math.sqrt(dx * dx + dy * dy) - player.r;;
dx = dx / dist / (dist * dist * dist) // x/dist is a directionless unit vector
dy = dy / dist / (dist * dist * dist) // 1/(dist*dist*dist) weights the closer vectors higher
vector.x += dx;
vector.y += dy;
//vector visualization
if (dist < 800 && container.visual) {
ctx.beginPath();
ctx.moveTo(0.5 * window.innerWidth, 0.5 * window.innerHeight);
ctx.lineTo(300000000 * dx + 0.5 * window.innerWidth, 300000000 * dy + 0.5 * window.innerHeight);
ctx.stroke();
}
}
length = virus.length;
for (var i = 0; i < length; i++) {
if (virus[i].r < player.r) {
var dy = virus[i].y - (player.y);
var dx = virus[i].x - (player.x);
var dist = Math.sqrt(dx * dx + dy * dy) - player.r;
dx = 10 * dx / dist / (dist * dist * dist * dist) // x/dist is a directionless unit vector
dy = 10 * dy / dist / (dist * dist * dist * dist) // 1/(dist*dist*dist*dist) wieghts the closer vectors
vector.x -= dx;
vector.y -= dy;
if (dist < 800 && container.visual) {
ctx.strokeStyle = 'red';
ctx.beginPath();
ctx.moveTo(0.5 * window.innerWidth, 0.5 * window.innerHeight);
ctx.lineTo(-300000000 * dx + 0.5 * window.innerWidth, -300000000 * dy + 0.5 * window.innerHeight);
ctx.stroke();
}
}
}
//find the angle of the vector
player.dir = Math.atan2(vector.y, vector.x);
player.move();
}*/
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.5/dat.gui.min.js"></script>
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/464612/agarAIcolorfunctions.js"></script>
body {
background-color: #f0faff;
overflow:hidden;
}
canvas {
position: absolute;
left: 0;
top: 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment