basic evolution finished
This commit is contained in:
200
dist/bundle.js
vendored
Normal file
200
dist/bundle.js
vendored
Normal file
File diff suppressed because one or more lines are too long
14
dist/css/style.css
vendored
Normal file
14
dist/css/style.css
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
body{
|
||||
background: #121D29;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
canvas {
|
||||
display: block;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
12
dist/html/index.html
vendored
Normal file
12
dist/html/index.html
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charste="UTF-8">
|
||||
<title>Evolution Simulator</title>
|
||||
<link rel="stylesheet" href="../css/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<canvas id='canvas'></canvas>
|
||||
<script src="../bundle.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
1935
package-lock.json
generated
1935
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -2,10 +2,10 @@
|
||||
"name": "EvolutionSimulatorV2",
|
||||
"version": "1.0.0",
|
||||
"description": "Version 2 of the evolution simulator",
|
||||
"main": "index.js",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"build": "webpack --mode=production",
|
||||
"build": "webpack --mode=production",
|
||||
"build-dev": "webpack --mode=development",
|
||||
"build-watch": "webpack --watch --mode=development"
|
||||
},
|
||||
@@ -21,6 +21,8 @@
|
||||
},
|
||||
"homepage": "https://github.com/MaxRobinsonTheGreat/EvolutionSimulatorV2#readme",
|
||||
"devDependencies": {
|
||||
"webpack": "^4.43.0",
|
||||
"webpack-cli": "^3.3.12"
|
||||
}
|
||||
},
|
||||
"dependencies": {}
|
||||
}
|
||||
|
||||
94
src/Cell.js
Normal file
94
src/Cell.js
Normal file
@@ -0,0 +1,94 @@
|
||||
const CellTypes = require("./CellTypes");
|
||||
|
||||
// A cell exists in a grid system.
|
||||
class Cell{
|
||||
constructor(type, col, row, x, y){
|
||||
this.owner = null;
|
||||
this.setType(type);
|
||||
this.col = col;
|
||||
this.row = row;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
setType(type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
performFunction(env) {
|
||||
switch(this.type){
|
||||
case CellTypes.mouth:
|
||||
eatFood(this, env);
|
||||
break;
|
||||
case CellTypes.producer:
|
||||
growFood(this, env);
|
||||
break;
|
||||
case CellTypes.killer:
|
||||
killNeighbors(this, env);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
getColor() {
|
||||
return CellTypes.colors[this.type];
|
||||
}
|
||||
|
||||
isLiving() {
|
||||
return this.type != CellTypes.empty &&
|
||||
this.type != CellTypes.food &&
|
||||
this.type != CellTypes.wall;
|
||||
}
|
||||
}
|
||||
|
||||
function eatFood(self, env){
|
||||
eatNeighborFood(env.grid_map.cellAt(self.col+1, self.row), self, env);
|
||||
eatNeighborFood(env.grid_map.cellAt(self.col-1, self.row), self, env);
|
||||
eatNeighborFood(env.grid_map.cellAt(self.col, self.row+1), self, env);
|
||||
eatNeighborFood(env.grid_map.cellAt(self.col, self.row-1), self, env);
|
||||
}
|
||||
|
||||
function eatNeighborFood(n_cell, self, env){
|
||||
if (n_cell == null)
|
||||
return;
|
||||
if (n_cell.type == CellTypes.food){
|
||||
env.changeCell(n_cell.col, n_cell.row, CellTypes.empty, null);
|
||||
self.owner.food_collected++;
|
||||
}
|
||||
}
|
||||
|
||||
function growFood(self, env){
|
||||
if (self.owner.is_mover)
|
||||
return;
|
||||
for (var c=-1; c<=1; c++){
|
||||
for (var r=-1; r<=1; r++){
|
||||
if (r==0 && c==0)
|
||||
continue;
|
||||
var cell = env.grid_map.cellAt(self.col+c, self.row+r);
|
||||
if (cell != null && cell.type == CellTypes.empty && Math.random() * 100 <= 0.5){
|
||||
env.changeCell(self.col+c, self.row+r, CellTypes.food, null);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function killNeighbors(self, env) {
|
||||
killNeighbor(env.grid_map.cellAt(self.col+1, self.row));
|
||||
killNeighbor(env.grid_map.cellAt(self.col-1, self.row));
|
||||
killNeighbor(env.grid_map.cellAt(self.col, self.row+1));
|
||||
killNeighbor(env.grid_map.cellAt(self.col, self.row-1));
|
||||
}
|
||||
|
||||
function killNeighbor(n_cell) {
|
||||
if(n_cell == null) {
|
||||
return
|
||||
}
|
||||
if (n_cell.type != CellTypes.armor && n_cell.owner != null && n_cell.owner != self.owner && n_cell.owner.living){
|
||||
n_cell.owner.die();
|
||||
if (n_cell == CellTypes.killer){
|
||||
self.owner.die();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Cell;
|
||||
16
src/CellTypes.js
Normal file
16
src/CellTypes.js
Normal file
@@ -0,0 +1,16 @@
|
||||
const CellTypes = {
|
||||
empty: 0,
|
||||
food: 1,
|
||||
wall: 2,
|
||||
mouth: 3,
|
||||
producer: 4,
|
||||
mover: 5,
|
||||
killer: 6,
|
||||
armor: 7,
|
||||
colors: ['#121D29', 'green', 'black', 'orange', 'white', 'blue', 'red', 'purple'],
|
||||
getRandomLivingType: function(){
|
||||
return Math.floor(Math.random() * 5) + 3;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CellTypes;
|
||||
34
src/Engine.js
Normal file
34
src/Engine.js
Normal file
@@ -0,0 +1,34 @@
|
||||
const Environment = require('./Environment');
|
||||
|
||||
class Engine{
|
||||
constructor(){
|
||||
this.fps = 0;
|
||||
this.environment = new Environment(5);
|
||||
this.environment.OriginOfLife();
|
||||
this.last_update = Date.now();
|
||||
this.delta_time = 0;
|
||||
this.running = false;
|
||||
}
|
||||
|
||||
start(fps=60) {
|
||||
this.fps = fps;
|
||||
this.game_loop = setInterval(function(){this.update();}.bind(this), 1000/fps);
|
||||
this.runnning = true;
|
||||
}
|
||||
|
||||
stop() {
|
||||
clearInterval(this.game_loop);
|
||||
this.running = false;
|
||||
}
|
||||
|
||||
|
||||
update() {
|
||||
this.delta_time = Date.now() - this.last_update;
|
||||
this.last_update = Date.now();
|
||||
this.environment.update(this.delta_time);
|
||||
this.environment.render();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = Engine;
|
||||
72
src/Environment.js
Normal file
72
src/Environment.js
Normal file
@@ -0,0 +1,72 @@
|
||||
const Grid = require('./GridMap');
|
||||
const Renderer = require('./Rendering/Renderer');
|
||||
const GridMap = require('./GridMap');
|
||||
const Organism = require('./Organism');
|
||||
const CellTypes = require('./CellTypes');
|
||||
const Cell = require('./Cell');
|
||||
const EnvironmentController = require('./EnvironmentController');
|
||||
|
||||
class Environment{
|
||||
constructor(cell_size) {
|
||||
this.renderer = new Renderer('canvas', this, cell_size);
|
||||
this.controller = new EnvironmentController(this, this.renderer.canvas);
|
||||
this.grid_rows = Math.floor(this.renderer.height / cell_size);
|
||||
this.grid_cols = Math.floor(this.renderer.width / cell_size);
|
||||
this.grid_map = new GridMap(this.grid_cols, this.grid_rows, cell_size);
|
||||
this.renderer.renderFullGrid();
|
||||
this.organisms = [];
|
||||
}
|
||||
|
||||
|
||||
// {
|
||||
// running: 0,
|
||||
// paused: 1,
|
||||
// headless: 2
|
||||
// };
|
||||
|
||||
update(delta_time) {
|
||||
var to_remove = [];
|
||||
for (var i in this.organisms) {
|
||||
var org = this.organisms[i];
|
||||
if (!org.update()) {
|
||||
to_remove.push(i);
|
||||
}
|
||||
}
|
||||
this.removeOrganisms(to_remove);
|
||||
}
|
||||
|
||||
render() {
|
||||
// console.log(this.cells_to_render);
|
||||
this.renderer.renderCells();
|
||||
this.renderer.renderHighlights();
|
||||
}
|
||||
|
||||
removeOrganisms(org_indeces) {
|
||||
for (var i of org_indeces.reverse()){
|
||||
this.organisms.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
OriginOfLife() {
|
||||
var center = this.grid_map.getCenter();
|
||||
var org = new Organism(center[0], center[1], this);
|
||||
org.addCell(CellTypes.mouth, -1, -1);
|
||||
org.addCell(CellTypes.producer, 0, 0);
|
||||
org.addCell(CellTypes.mouth, 1, 1);
|
||||
this.addOrganism(org);
|
||||
}
|
||||
|
||||
addOrganism(organism) {
|
||||
organism.updateGrid();
|
||||
this.organisms.push(organism);
|
||||
}
|
||||
|
||||
changeCell(c, r, type, owner) {
|
||||
this.grid_map.setCellType(c, r, type);
|
||||
this.grid_map.setCellOwner(c, r, owner);
|
||||
this.renderer.addToRender(this.grid_map.cellAt(c, r));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Environment;
|
||||
|
||||
52
src/EnvironmentController.js
Normal file
52
src/EnvironmentController.js
Normal file
@@ -0,0 +1,52 @@
|
||||
|
||||
class EnvironmentController{
|
||||
constructor(env, canvas) {
|
||||
this.env = env;
|
||||
this.canvas = canvas;
|
||||
this.mouse_x;
|
||||
this.mouse_y;
|
||||
this.mouse_c;
|
||||
this.mouse_r;
|
||||
this.mouse_down = false;
|
||||
this.cur_cell = null;
|
||||
this.cur_org = null;
|
||||
this.defineEvents();
|
||||
}
|
||||
|
||||
defineEvents() {
|
||||
this.canvas.addEventListener('mousedown', e => {
|
||||
this.mouse_down=true;
|
||||
});
|
||||
|
||||
this.canvas.addEventListener('mouseup', e => {
|
||||
this.mouse_down=false;
|
||||
});
|
||||
|
||||
this.canvas.addEventListener('mousemove', e => {
|
||||
var prev_cell = this.cur_cell;
|
||||
var prev_org = this.cur_org;
|
||||
|
||||
this.mouse_x = e.offsetX;
|
||||
this.mouse_y = e.offsetY;
|
||||
var colRow = this.env.grid_map.xyToColRow(this.mouse_x, this.mouse_y);
|
||||
this.mouse_c = colRow[0];
|
||||
this.mouse_r = colRow[1];
|
||||
this.cur_cell = this.env.grid_map.cellAt(this.mouse_c, this.mouse_r);
|
||||
this.cur_org = this.cur_cell.owner;
|
||||
|
||||
if (this.cur_org != prev_org || this.cur_cell != prev_cell) {
|
||||
this.env.renderer.clearAllHighlights(true);
|
||||
if (this.cur_org != null) {
|
||||
this.env.renderer.highlightOrganism(this.cur_org);
|
||||
}
|
||||
else if (this.cur_cell != null) {
|
||||
this.env.renderer.highlightCell(this.cur_cell, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
module.exports = EnvironmentController;
|
||||
73
src/GridMap.js
Normal file
73
src/GridMap.js
Normal file
@@ -0,0 +1,73 @@
|
||||
const Cell = require('./Cell');
|
||||
const CellTypes = require('./CellTypes');
|
||||
|
||||
class GridMap {
|
||||
constructor(cols, rows, cell_size, filltype=CellTypes.empty) {
|
||||
this.grid = [];
|
||||
this.cols = cols;
|
||||
this.rows = rows;
|
||||
this.cell_size = cell_size;
|
||||
for(var c=0; c<cols; c++) {
|
||||
var row = [];
|
||||
for(var r=0; r<rows; r++) {
|
||||
var cell = new Cell(filltype, c, r, c*cell_size, r*cell_size);
|
||||
|
||||
row.push(cell);
|
||||
}
|
||||
this.grid.push(row);
|
||||
}
|
||||
}
|
||||
|
||||
fillGrid(type) {
|
||||
for (var col of grid) {
|
||||
for (var cell of col){
|
||||
cell.setType(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cellAt(col, row) {
|
||||
if (!this.isValidLoc(col, row)) {
|
||||
return null;
|
||||
}
|
||||
return this.grid[col][row];
|
||||
}
|
||||
|
||||
setCellType(col, row, type) {
|
||||
if (!this.isValidLoc(col, row)) {
|
||||
return;
|
||||
}
|
||||
this.grid[col][row].setType(type);
|
||||
}
|
||||
|
||||
setCellOwner(col, row, owner) {
|
||||
if (!this.isValidLoc(col, row)) {
|
||||
return;
|
||||
}
|
||||
this.grid[col][row].owner = owner;
|
||||
}
|
||||
|
||||
isValidLoc(col, row){
|
||||
return col<this.cols && row<this.rows && col>=0 && row>=0;
|
||||
}
|
||||
|
||||
getCenter(){
|
||||
return [Math.floor(this.cols/2), Math.floor(this.rows/2)]
|
||||
}
|
||||
|
||||
xyToColRow(x, y) {
|
||||
var c = Math.floor(x/this.cell_size);
|
||||
var r = Math.floor(y/this.cell_size);
|
||||
if (c >= this.cols)
|
||||
c = this.cols-1;
|
||||
else if (c < 0)
|
||||
c = 0;
|
||||
if (r >= this.rows)
|
||||
r = this.rows-1;
|
||||
else if (r < 0)
|
||||
r = 0;
|
||||
return [c, r];
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = GridMap;
|
||||
12
src/LocalCell.js
Normal file
12
src/LocalCell.js
Normal file
@@ -0,0 +1,12 @@
|
||||
const CellTypes = require("./CellTypes");
|
||||
|
||||
// A local cell is a lightweight container for a cell in an organism. It does not directly exist in the grid
|
||||
class LocalCell{
|
||||
constructor(type, loc_col, loc_row){
|
||||
this.type = type;
|
||||
this.loc_col = loc_col;
|
||||
this.loc_row = loc_row;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = LocalCell;
|
||||
249
src/Organism.js
Normal file
249
src/Organism.js
Normal file
@@ -0,0 +1,249 @@
|
||||
const CellTypes = require("./CellTypes");
|
||||
const Cell = require("./Cell");
|
||||
const GridMap = require("./GridMap");
|
||||
const LocalCell = require("./LocalCell");
|
||||
const { producer } = require("./CellTypes");
|
||||
|
||||
class Organism {
|
||||
constructor(col, row, env, parent=null) {
|
||||
this.c = col;
|
||||
this.r = row;
|
||||
this.env = env;
|
||||
this.lifetime = 0;
|
||||
this.food_collected = 0;
|
||||
this.living = true;
|
||||
this.cells = [];
|
||||
this.is_producer = false;
|
||||
this.is_mover = false;
|
||||
if (parent != null) {
|
||||
this.inherit(parent);
|
||||
}
|
||||
}
|
||||
|
||||
addCell(type, c, r) {
|
||||
for (var cell of this.cells) {
|
||||
if (cell.loc_col == c && cell.loc_row == r)
|
||||
return false;
|
||||
}
|
||||
this.checkProducerMover(type);
|
||||
this.cells.push(new LocalCell(type, c, r));
|
||||
return true;
|
||||
}
|
||||
|
||||
removeCell(c, r) {
|
||||
var check_change = false;
|
||||
for (var i=0; i<this.cells.length; i++) {
|
||||
var cell = this.cells[i];
|
||||
if (cell.loc_col == c && cell.loc_row == r){
|
||||
if (cell.type == this.producer || cell.type == this.mover) {
|
||||
check_change = true;
|
||||
}
|
||||
this.cells.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (check_change) {
|
||||
this.is_producer = false;
|
||||
this.is_producer = false;
|
||||
for (var cell of this.cells) {
|
||||
this.checkProducerMover(cell.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkProducerMover(type) {
|
||||
if (type == CellTypes.producer)
|
||||
this.is_producer = true;
|
||||
if (type == CellTypes.mover)
|
||||
this.is_mover = true;
|
||||
}
|
||||
|
||||
inherit(parent) {
|
||||
for (var c of parent.cells){
|
||||
//deep copy parent cells
|
||||
this.addCell(c.type, c.loc_col, c.loc_row);
|
||||
}
|
||||
}
|
||||
|
||||
// amount of food required before it can reproduce
|
||||
foodNeeded() {
|
||||
return this.cells.length;
|
||||
}
|
||||
|
||||
lifespan() {
|
||||
return this.cells.length * 150;
|
||||
}
|
||||
|
||||
reproduce() {
|
||||
//produce mutated child
|
||||
//check nearby locations (is there room and a direct path)
|
||||
var org = new Organism(0, 0, this.env, this);
|
||||
if (Math.random() * 100 <= 5) {
|
||||
org.mutate();
|
||||
}
|
||||
|
||||
var direction = this.getRandomDirection();
|
||||
var direction_c = direction[0];
|
||||
var direction_r = direction[1];
|
||||
var boost = Math.floor(Math.random() * 2) + 1;
|
||||
boost = 1;
|
||||
|
||||
var new_c = this.c + (direction_c*this.cells.length*2) + (direction_c*boost);
|
||||
var new_r = this.r + (direction_r*this.cells.length*2) + (direction_r*boost);
|
||||
if (org.isClear(new_c, new_r)){// && org.isStraightPath(new_c, new_r, this.c, this.r, this)){
|
||||
org.c = new_c;
|
||||
org.r = new_r;
|
||||
this.env.addOrganism(org);
|
||||
org.updateGrid();
|
||||
}
|
||||
|
||||
this.food_collected -= this.foodNeeded();
|
||||
|
||||
|
||||
}
|
||||
|
||||
mutate() {
|
||||
var choice = Math.floor(Math.random() * 3);
|
||||
if (choice == 0) {
|
||||
var type = CellTypes.getRandomLivingType();
|
||||
var branch = this.cells[Math.floor(Math.random() * this.cells.length)];
|
||||
var c = branch.loc_col+Math.floor(Math.random() * 2) - 1;
|
||||
var r = branch.loc_row+Math.floor(Math.random() * 2) - 1;
|
||||
return this.addCell(type, c, r);
|
||||
}
|
||||
else if (choice == 1){
|
||||
// change cell
|
||||
var cell = this.cells[Math.floor(Math.random() * this.cells.length)];
|
||||
cell.type = CellTypes.getRandomLivingType();
|
||||
this.checkProducerMover(cell.type);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
// remove cell
|
||||
if(this.cells.length > 1) {
|
||||
this.cells.splice(Math.floor(Math.random() * this.cells.length), 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
attemptMove(col, row) {
|
||||
var direction = this.getRandomDirection();
|
||||
var direction_c = direction[0];
|
||||
var direction_r = direction[1];
|
||||
var new_c = this.c + direction_c;
|
||||
var new_r = this.r + direction_r;
|
||||
if (this.isClear(new_c, new_r)) {
|
||||
for (var cell of this.cells) {
|
||||
var real_c = this.c + cell.loc_col;
|
||||
var real_r = this.r + cell.loc_row;
|
||||
this.env.changeCell(real_c, real_r, CellTypes.empty, null);
|
||||
}
|
||||
this.c = new_c;
|
||||
this.r = new_r;
|
||||
this.updateGrid();
|
||||
}
|
||||
}
|
||||
|
||||
getRandomDirection(){
|
||||
var directions = [[0,1],[0,-1],[1,0],[-1,0]]
|
||||
return directions[Math.floor(Math.random() * directions.length)];
|
||||
}
|
||||
|
||||
// assumes either c1==c2 or r1==r2, returns true if there is a clear path from point a to b
|
||||
isStraightPath(c1, r1, c2, r2, parent){
|
||||
// TODO FIX!!!
|
||||
if (c1 == c2) {
|
||||
if (r1 > r2){
|
||||
var temp = r2;
|
||||
r2 = r1;
|
||||
r1 = temp;
|
||||
}
|
||||
for (var i=r1; i!=r2; i++) {
|
||||
var cell = this.env.grid_map.cellAt(c1, i)
|
||||
if (!this.isPassableCell(cell, parent)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if (c1 > c2){
|
||||
var temp = c2;
|
||||
c2 = c1;
|
||||
c1 = temp;
|
||||
}
|
||||
for (var i=c1; i!=c2; i++) {
|
||||
var cell = this.env.grid_map.cellAt(i, r1);
|
||||
if (!this.isPassableCell(cell, parent)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
isPassableCell(cell, parent){
|
||||
return cell.type == CellTypes.empty || cell.owner == this || cell.owner == parent;
|
||||
}
|
||||
|
||||
isClear(col, row) {
|
||||
for(var loccell of this.cells) {
|
||||
var cell = this.getRealCell(loccell, col, row);
|
||||
if(cell == null || cell.type != CellTypes.empty && cell.owner != this) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
die() {
|
||||
for (var cell of this.cells) {
|
||||
var real_c = this.c + cell.loc_col;
|
||||
var real_r = this.r + cell.loc_row;
|
||||
this.env.changeCell(real_c, real_r, CellTypes.food, null);
|
||||
}
|
||||
this.living = false;
|
||||
}
|
||||
|
||||
updateGrid() {
|
||||
for (var cell of this.cells) {
|
||||
var real_c = this.c + cell.loc_col;
|
||||
var real_r = this.r + cell.loc_row;
|
||||
this.env.changeCell(real_c, real_r, cell.type, this);
|
||||
}
|
||||
}
|
||||
|
||||
update() {
|
||||
// this.food_collected++;
|
||||
this.lifetime++;
|
||||
if (this.lifetime > this.lifespan()) {
|
||||
this.die();
|
||||
return this.living;
|
||||
}
|
||||
for (var cell of this.cells) {
|
||||
this.getRealCell(cell).performFunction(this.env);
|
||||
}
|
||||
if (!this.living){
|
||||
return this.living
|
||||
}
|
||||
if (this.is_mover) {
|
||||
this.attemptMove();
|
||||
}
|
||||
if (this.food_collected >= this.foodNeeded()) {
|
||||
this.reproduce();
|
||||
}
|
||||
|
||||
return this.living;
|
||||
}
|
||||
|
||||
getRealCell(local_cell, c=this.c, r=this.r){
|
||||
var real_c = c + local_cell.loc_col;
|
||||
var real_r = r + local_cell.loc_row;
|
||||
return this.env.grid_map.cellAt(real_c, real_r);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = Organism;
|
||||
103
src/Rendering/Renderer.js
Normal file
103
src/Rendering/Renderer.js
Normal file
@@ -0,0 +1,103 @@
|
||||
|
||||
// Renderer controls access to a canvas. There is one renderer for each canvas
|
||||
class Renderer {
|
||||
constructor(canvas_id, env, cell_size) {
|
||||
this.cell_size = cell_size;
|
||||
this.env = env;
|
||||
this.canvas = document.getElementById(canvas_id);
|
||||
this.ctx = canvas.getContext("2d");
|
||||
this.canvas.width = window.innerWidth;
|
||||
this.canvas.height = window.innerHeight;
|
||||
this.height = canvas.height;
|
||||
this.width = canvas.width;
|
||||
this.cells_to_render = new Set();
|
||||
this.cells_to_highlight = new Set();
|
||||
this.highlighted_cells = new Set();
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.ctx.fillStyle = 'white';
|
||||
this.ctx.fillRect(0, 0, this.height, this.width);
|
||||
}
|
||||
|
||||
renderFullGrid() {
|
||||
var grid = this.env.grid_map.grid;
|
||||
for (var col of grid) {
|
||||
for (var cell of col){
|
||||
this.ctx.fillStyle = cell.getColor();
|
||||
this.ctx.fillRect(cell.x, cell.y, this.cell_size, this.cell_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
renderCells() {
|
||||
for (var cell of this.cells_to_render) {
|
||||
this.renderCell(cell);
|
||||
}
|
||||
this.cells_to_render.clear();
|
||||
}
|
||||
|
||||
renderCell(cell) {
|
||||
this.ctx.fillStyle = cell.getColor();
|
||||
this.ctx.fillRect(cell.x, cell.y, this.cell_size, this.cell_size);
|
||||
}
|
||||
|
||||
renderOrganism(org) {
|
||||
for(var org_cell of org.cells) {
|
||||
var cell = org.getRealCell(org_cell);
|
||||
this.renderCell(cell);
|
||||
}
|
||||
}
|
||||
|
||||
addToRender(cell) {
|
||||
if (this.highlighted_cells.has(cell)){
|
||||
this.cells_to_highlight.add(cell);
|
||||
}
|
||||
this.cells_to_render.add(cell);
|
||||
}
|
||||
|
||||
renderHighlights() {
|
||||
for (var cell of this.cells_to_highlight) {
|
||||
this.renderCellHighlight(cell);
|
||||
this.highlighted_cells.add(cell);
|
||||
}
|
||||
this.cells_to_highlight.clear();
|
||||
|
||||
}
|
||||
|
||||
highlightOrganism(org) {
|
||||
for(var org_cell of org.cells) {
|
||||
var cell = org.getRealCell(org_cell);
|
||||
this.cells_to_highlight.add(cell);
|
||||
}
|
||||
}
|
||||
|
||||
highlightCell(cell) {
|
||||
this.cells_to_highlight.add(cell);
|
||||
}
|
||||
|
||||
renderCellHighlight(cell, color="yellow") {
|
||||
this.renderCell(cell);
|
||||
this.ctx.fillStyle = color;
|
||||
this.ctx.globalAlpha = 0.5;
|
||||
this.ctx.fillRect(cell.x, cell.y, this.cell_size, this.cell_size);
|
||||
this.ctx.globalAlpha = 1;
|
||||
this.highlighted_cells.add(cell);
|
||||
}
|
||||
|
||||
clearAllHighlights(clear_to_highlight=false) {
|
||||
for (var cell of this.highlighted_cells) {
|
||||
this.renderCell(cell);
|
||||
}
|
||||
this.highlighted_cells.clear();
|
||||
if (clear_to_highlight) {
|
||||
this.cells_to_highlight.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// $("body").mousemove(function(e) {
|
||||
// console.log("hello");
|
||||
// });
|
||||
|
||||
module.exports = Renderer;
|
||||
@@ -0,0 +1,6 @@
|
||||
'user strict';
|
||||
|
||||
import Engine from './Engine';
|
||||
|
||||
var engine = new Engine();
|
||||
engine.start(45);
|
||||
@@ -3,7 +3,10 @@ const path = require('path');
|
||||
module.exports = {
|
||||
entry: './src/index.js',
|
||||
output: {
|
||||
filename: 'main.js',
|
||||
filename: 'bundle.js',
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
},
|
||||
externals: {
|
||||
jquery: 'jQuery'
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user