control tabs, organism editor, code refactor
This commit is contained in:
256
dist/bundle.js
vendored
256
dist/bundle.js
vendored
File diff suppressed because one or more lines are too long
96
dist/css/style.css
vendored
96
dist/css/style.css
vendored
@@ -8,7 +8,6 @@ body{
|
||||
|
||||
canvas {
|
||||
display: block;
|
||||
|
||||
}
|
||||
|
||||
* {
|
||||
@@ -16,7 +15,7 @@ canvas {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.env {
|
||||
#env {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 300px; /* must correspond to control-panel height*/
|
||||
@@ -52,15 +51,49 @@ canvas {
|
||||
grid-row: 2;
|
||||
}
|
||||
|
||||
#hyperparameters {
|
||||
grid-column: 2;
|
||||
#tab-container {
|
||||
grid-column: 2 / 4;
|
||||
grid-row: 1 / 3;
|
||||
}
|
||||
|
||||
.tabnav {
|
||||
overflow: hidden;
|
||||
background-color: #333;
|
||||
}
|
||||
.tabnav p {
|
||||
float: left;
|
||||
color: #f2f2f2;
|
||||
text-align: center;
|
||||
padding: 14px 16px;
|
||||
text-decoration: none;
|
||||
font-size: 17px;
|
||||
user-select: none;
|
||||
}
|
||||
.tabnav p:hover {
|
||||
background-color: rgb(121, 121, 121);
|
||||
color: black;
|
||||
}
|
||||
|
||||
.tab {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
grid-template-rows: 1;
|
||||
}
|
||||
|
||||
.tab#hyperparameters {
|
||||
display: none;
|
||||
|
||||
}
|
||||
|
||||
#abilities {
|
||||
grid-column: 3;
|
||||
grid-row: 1 / 3;
|
||||
.tab#editor {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.left-half {
|
||||
grid-column: 1;
|
||||
}
|
||||
|
||||
.right-half {
|
||||
grid-column: 2;
|
||||
}
|
||||
|
||||
.control-mode-button {
|
||||
@@ -70,4 +103,53 @@ canvas {
|
||||
|
||||
#none-button {
|
||||
background-color: gray;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#editor-env {
|
||||
position: absolute;
|
||||
height: 220px;
|
||||
width: 220px;
|
||||
padding: 10px;
|
||||
float: left;
|
||||
}
|
||||
#cell-selections {
|
||||
display: none;
|
||||
padding: 10px;
|
||||
grid-template-columns: 1;
|
||||
grid-template-rows: 5;
|
||||
float: right;
|
||||
}
|
||||
.cell-type {
|
||||
grid-column: 1;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border: solid black;
|
||||
border-width: 2px;
|
||||
margin: 1px;
|
||||
|
||||
}
|
||||
#mouth{
|
||||
background-color: orange;
|
||||
grid-row: 1;
|
||||
}
|
||||
#producer{
|
||||
background-color: white;
|
||||
grid-row: 2;
|
||||
}
|
||||
#mover{
|
||||
background-color: #3493eb;
|
||||
grid-row: 3;
|
||||
}
|
||||
#killer{
|
||||
background-color: red;
|
||||
grid-row: 4;
|
||||
}
|
||||
#armor{
|
||||
background-color: purple;
|
||||
grid-row: 5;
|
||||
}
|
||||
#editor-mode-cont{
|
||||
padding-top: 20px;
|
||||
}
|
||||
125
dist/html/index.html
vendored
125
dist/html/index.html
vendored
@@ -4,14 +4,13 @@
|
||||
<meta charste="UTF-8">
|
||||
<title>Evolution Simulator</title>
|
||||
<link rel="stylesheet" href="../css/style.css">
|
||||
<!-- <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css"> -->
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script src="../bundle.js"></script>
|
||||
|
||||
<div class='env'>
|
||||
<canvas id='canvas'></canvas>
|
||||
<div id='env'>
|
||||
<canvas id='env-canvas'></canvas>
|
||||
</div>
|
||||
<div class='control-panel'>
|
||||
<div id='speed-controller' class='control-set'>
|
||||
@@ -20,6 +19,8 @@
|
||||
<button id='pause-button'>Pause</button>
|
||||
<p id='fps'>Target FPS: 60</p>
|
||||
<p id='fps-actual'></p>
|
||||
<br/>
|
||||
<button id='reset-env'>Reset Environment</button>
|
||||
</div>
|
||||
|
||||
<div id='stats' class='control-set'>
|
||||
@@ -28,48 +29,84 @@
|
||||
<p id='org-record'>Highest count: </p>
|
||||
<p id='avg-mut'>Average Mutation Rate: </p>
|
||||
</div>
|
||||
|
||||
<div id='hyperparameters' class='control-set'>
|
||||
<h2>Hyperparameters</h2>
|
||||
<label for="food-prod-prob">Probability of producing food:</label>
|
||||
<input type="number" id="food-prod-prob" min=".001" max="100" value=4 step="1">
|
||||
<label for="lifespan-multiplier">Lifespan multiplier:</label>
|
||||
<input type="number" id="lifespan-multiplier" min="1" max="10000" value=100 step="1">
|
||||
<br/>
|
||||
<label for="fixed-ratio">Use fixed ratio</label>
|
||||
<input type="checkbox" id="fixed-ratio" name="scales" checked>
|
||||
<br><br/>
|
||||
<h4>Mutation Probabilities</h4>
|
||||
<label for="add-prob">Add Cell:</label>
|
||||
<input class="mut-prob" type="number" id="add-prob" min="0" max="100" value=33>
|
||||
<br/>
|
||||
<label for="change-prob">Change Cell:</label>
|
||||
<input class="mut-prob" type="number" id="change-prob" min="0" max="100" value=33>
|
||||
<br/>
|
||||
<label for="remove-prob">Remove Cell:</label>
|
||||
<input class="mut-prob" type="number" id="remove-prob" min="0" max="100" value=33>
|
||||
<br/>
|
||||
<h4>Organism Rotation</h4>
|
||||
<label for="mover-rot">Movers can rotate</label>
|
||||
<input type="checkbox" id="mover-rot" name="scales" checked>
|
||||
<br/>
|
||||
<label for="offspring-rot">Offspring rotate</label>
|
||||
<input type="checkbox" id="offspring-rot" name="scales" checked>
|
||||
<br/>
|
||||
<label for="insta-kill">Insta Kill</label>
|
||||
<input type="checkbox" id="insta-kill" name="scales">
|
||||
</div>
|
||||
|
||||
<div id='abilities' class='control-set'>
|
||||
<h2>Control Mode</h2>
|
||||
<button class='control-mode-button' id='food-button' value='Inset Border'>Drop Food</button>
|
||||
<button class='control-mode-button' id='wall-button'>Drop Wall</button>
|
||||
<button class='control-mode-button' id='kill-button'>Kill Organism</button>
|
||||
<button class='control-mode-button' id='none-button'>None</button>
|
||||
<br><br/>
|
||||
<button id='reset-env'>Reset Environment</button>
|
||||
<button id='kill-all'>Kill All Organisms</button>
|
||||
<button id='clear-walls'>Clear All Walls</button>
|
||||
<div id='tab-container' class='control-set'>
|
||||
|
||||
<div class="tabnav">
|
||||
<p class='tabnav-item' id='editor'>Editor</p>
|
||||
<p class='tabnav-item' id='hyperparameters'>Hyperparameters</p>
|
||||
</div>
|
||||
|
||||
<div id='editor' class='tab'>
|
||||
<div class='left-half'>
|
||||
<h2>Editor</h2>
|
||||
<label for="editor-mode">Edit Mode</label>
|
||||
<select name="values" id="editor-mode">
|
||||
<option value="none">None</option>
|
||||
<option value="food">Drop Food</option>
|
||||
<option value="wall">Drop Wall</option>
|
||||
<option value="kill">Kill Organism</option>
|
||||
<option value="select">Select Organism</option>
|
||||
<option value="edit">Edit Selection</option>
|
||||
<option value="clone">Clone Selection</option>
|
||||
</select>
|
||||
<br><br/>
|
||||
<button id='kill-all'>Kill All Organisms</button>
|
||||
<button id='clear-walls'>Clear All Walls</button>
|
||||
</div>
|
||||
<div class='right-half'>
|
||||
<div id='editor-env'>
|
||||
<canvas id='editor-canvas'></canvas>
|
||||
</div>
|
||||
<div id='cell-selections'>
|
||||
<div class='cell-type' id='mouth' title="Mouth: Eats adjacent food."></div>
|
||||
<div class='cell-type' id='producer' title="Producer: Produces adjacent food."></div>
|
||||
<div class='cell-type' id='mover' title="Mover: Allows for movement and rotation. Disables food production."></div>
|
||||
<div class='cell-type' id='killer' title="Killer: Harms oranisms in adjacent cells."></div>
|
||||
<div class='cell-type' id='armor' title="Armor: Negates affects of killer cell."></div>
|
||||
<button id='clear-editor'>Clear</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div id='hyperparameters' class='tab'>
|
||||
<div class='left-half'>
|
||||
<h2>Hyperparameters</h2>
|
||||
<h4>Food Production vs Lifespan</h4>
|
||||
<label for="food-prod-prob">Probability of producing food:</label>
|
||||
<input type="number" id="food-prod-prob" min=".001" max="100" value=4 step="1">
|
||||
<br/>
|
||||
<label for="lifespan-multiplier">Lifespan multiplier:</label>
|
||||
<input type="number" id="lifespan-multiplier" min="1" max="10000" value=100 step="1">
|
||||
<br/>
|
||||
<label for="fixed-ratio">Use fixed ratio</label>
|
||||
<input type="checkbox" id="fixed-ratio" name="scales" checked>
|
||||
<br><br/>
|
||||
<h4>Mutation Probabilities</h4>
|
||||
<label for="add-prob">Add Cell:</label>
|
||||
<input class="mut-prob" type="number" id="add-prob" min="0" max="100" value=33>
|
||||
<br/>
|
||||
<label for="change-prob">Change Cell:</label>
|
||||
<input class="mut-prob" type="number" id="change-prob" min="0" max="100" value=33>
|
||||
<br/>
|
||||
<label for="remove-prob">Remove Cell:</label>
|
||||
<input class="mut-prob" type="number" id="remove-prob" min="0" max="100" value=33>
|
||||
<br/>
|
||||
|
||||
</div>
|
||||
<div class='right-half'>
|
||||
<h4>Organism Rotation</h4>
|
||||
<label for="mover-rot">Movers can rotate</label>
|
||||
<input type="checkbox" id="mover-rot" name="scales" checked>
|
||||
<br/>
|
||||
<label for="offspring-rot">Offspring rotate</label>
|
||||
<input type="checkbox" id="offspring-rot" name="scales" checked>
|
||||
<br/>
|
||||
<h4>Killer Cell Effects</h4>
|
||||
<label for="insta-kill">One touch kill</label>
|
||||
<input type="checkbox" id="insta-kill" name="scales">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
const Modes = require("./ControlModes");
|
||||
const CellTypes = require("./CellTypes");
|
||||
|
||||
class EnvironmentController{
|
||||
|
||||
class CanvasController{
|
||||
constructor(env, canvas) {
|
||||
this.env = env;
|
||||
this.canvas = canvas;
|
||||
@@ -13,10 +12,14 @@ class EnvironmentController{
|
||||
this.right_click = false;
|
||||
this.cur_cell = null;
|
||||
this.cur_org = null;
|
||||
this.mode = Modes.None;
|
||||
this.highlight_org = true;
|
||||
this.defineEvents();
|
||||
}
|
||||
|
||||
setControlPanel(panel){
|
||||
this.control_panel = panel;
|
||||
}
|
||||
|
||||
defineEvents() {
|
||||
this.canvas.addEventListener('mousemove', e => {
|
||||
var prev_cell = this.cur_cell;
|
||||
@@ -32,14 +35,14 @@ class EnvironmentController{
|
||||
|
||||
if (this.cur_org != prev_org || this.cur_cell != prev_cell) {
|
||||
this.env.renderer.clearAllHighlights(true);
|
||||
if (this.cur_org != null) {
|
||||
if (this.cur_org != null && this.highlight_org) {
|
||||
this.env.renderer.highlightOrganism(this.cur_org);
|
||||
}
|
||||
else if (this.cur_cell != null) {
|
||||
this.env.renderer.highlightCell(this.cur_cell, true);
|
||||
}
|
||||
}
|
||||
this.performModeAction();
|
||||
this.mouseMove();
|
||||
});
|
||||
|
||||
this.canvas.addEventListener('mouseup', function(evt) {
|
||||
@@ -55,7 +58,7 @@ class EnvironmentController{
|
||||
}
|
||||
if (evt.button == 2)
|
||||
this.right_click = true;
|
||||
this.performModeAction();
|
||||
this.mouseDown();
|
||||
}.bind(this));
|
||||
|
||||
this.canvas.addEventListener('contextmenu', function(evt) {
|
||||
@@ -65,44 +68,18 @@ class EnvironmentController{
|
||||
this.canvas.addEventListener('mouseleave', function(){
|
||||
this.right_click = false;
|
||||
this.left_click = false;
|
||||
this.env.renderer.clearAllHighlights(true);
|
||||
}.bind(this));
|
||||
|
||||
}
|
||||
|
||||
performModeAction() {
|
||||
var mode = this.mode;
|
||||
var right_click = this.right_click;
|
||||
var left_click = this.left_click;
|
||||
if (mode != Modes.None && (right_click || left_click)) {
|
||||
var cell = this.cur_cell;
|
||||
if (cell == null){
|
||||
return;
|
||||
}
|
||||
switch(mode) {
|
||||
case Modes.FoodDrop:
|
||||
if (left_click && cell.type == CellTypes.empty){
|
||||
this.env.changeCell(cell.col, cell.row, CellTypes.food, null);
|
||||
}
|
||||
else if (right_click && cell.type == CellTypes.food){
|
||||
this.env.changeCell(cell.col, cell.row, CellTypes.empty, null);
|
||||
}
|
||||
break;
|
||||
case Modes.WallDrop:
|
||||
if (left_click && (cell.type == CellTypes.empty || cell.type == CellTypes.food)){
|
||||
this.env.changeCell(cell.col, cell.row, CellTypes.wall, null);
|
||||
}
|
||||
else if (right_click && cell.type == CellTypes.wall){
|
||||
this.env.changeCell(cell.col, cell.row, CellTypes.empty, null);
|
||||
}
|
||||
break;
|
||||
case Modes.ClickKill:
|
||||
if (this.cur_org != null)
|
||||
this.cur_org.die();
|
||||
}
|
||||
}
|
||||
mouseMove() {
|
||||
alert("mouse move must be overriden");
|
||||
}
|
||||
|
||||
|
||||
mouseDown() {
|
||||
alert("mouse down must be overriden");
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = EnvironmentController;
|
||||
module.exports = CanvasController;
|
||||
@@ -2,7 +2,10 @@ const Modes = {
|
||||
None: 0,
|
||||
FoodDrop: 1,
|
||||
WallDrop: 2,
|
||||
ClickKill: 3
|
||||
ClickKill: 3,
|
||||
Select: 4,
|
||||
Edit: 5,
|
||||
Clone: 6
|
||||
}
|
||||
|
||||
module.exports = Modes;
|
||||
@@ -1,16 +1,20 @@
|
||||
const Hyperparams = require("./Hyperparameters");
|
||||
const Hyperparams = require("../Hyperparameters");
|
||||
const Modes = require("./ControlModes");
|
||||
const CellTypes = require("./CellTypes");
|
||||
const CellTypes = require("../Organism/Cell/CellTypes");
|
||||
|
||||
class ControlPanel {
|
||||
constructor(engine) {
|
||||
this.engine = engine;
|
||||
this.defineEngineSpeedControls();
|
||||
this.defineTabNavigation();
|
||||
this.defineHyperparameterControls();
|
||||
this.defineModeControls();
|
||||
this.fps = engine.fps;
|
||||
this.organism_record=0;
|
||||
this.env_controller = this.engine.env.controller;
|
||||
this.editor_controller = this.engine.organism_editor.controller;
|
||||
this.env_controller.setControlPanel(this);
|
||||
this.editor_controller.setControlPanel(this);
|
||||
}
|
||||
|
||||
defineEngineSpeedControls(){
|
||||
@@ -35,6 +39,16 @@ class ControlPanel {
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
defineTabNavigation() {
|
||||
var self = this;
|
||||
$('.tabnav-item').click(function() {
|
||||
$('.tab').css('display', 'none');
|
||||
var tab = '#'+this.id+'.tab';
|
||||
self.engine.organism_editor.is_active = (this.id == 'editor');
|
||||
$(tab).css('display', 'grid');
|
||||
});
|
||||
}
|
||||
|
||||
defineHyperparameterControls() {
|
||||
$('#food-prod-prob').change(function() {
|
||||
var food_prob = $('#food-prod-prob').val();
|
||||
@@ -91,23 +105,45 @@ class ControlPanel {
|
||||
|
||||
defineModeControls() {
|
||||
var self = this;
|
||||
$('.control-mode-button').click( function() {
|
||||
switch(this.id){
|
||||
case "food-button":
|
||||
self.env_controller.mode = Modes.FoodDrop;
|
||||
$('#editor-mode').change( function(el) {
|
||||
var selection = $(this).children("option:selected").val();
|
||||
var prev_mode = self.env_controller.mode;
|
||||
$('#cell-selections').css('display', 'none');
|
||||
switch(selection){
|
||||
case "none":
|
||||
self.setMode(Modes.None);
|
||||
break;
|
||||
case "wall-button":
|
||||
self.env_controller.mode = Modes.WallDrop;
|
||||
case "food":
|
||||
self.setMode(Modes.FoodDrop);
|
||||
break;
|
||||
case "kill-button":
|
||||
self.env_controller.mode = Modes.ClickKill;
|
||||
case "wall":
|
||||
self.setMode(Modes.WallDrop);
|
||||
break;
|
||||
case "none-button":
|
||||
self.env_controller.mode = Modes.None;
|
||||
case "kill":
|
||||
self.setMode(Modes.ClickKill);
|
||||
break;
|
||||
case "select":
|
||||
if (prev_mode==Modes.Edit || prev_mode==Modes.Clone && self.engine.organism_editor.organism.cells.length > 1){
|
||||
if (confirm("Selecting a new organism will clear the current organism. Are you sure you wish to switch?")) {
|
||||
self.setMode(Modes.Select);
|
||||
}
|
||||
else {
|
||||
$("#editor-mode").val('edit');
|
||||
}
|
||||
}
|
||||
else {
|
||||
self.setMode(Modes.Select);
|
||||
}
|
||||
break;
|
||||
case "edit":
|
||||
self.setMode(Modes.Edit);
|
||||
$('#cell-selections').css('display', 'grid');
|
||||
break;
|
||||
case "clone":
|
||||
self.setMode(Modes.Clone);
|
||||
self.env_controller.org_to_clone = self.engine.organism_editor.getCopyOfOrg();
|
||||
break;
|
||||
}
|
||||
$(".control-mode-button" ).css( "background-color", "lightgray" );
|
||||
$("#"+this.id).css("background-color", "darkgray");
|
||||
});
|
||||
|
||||
|
||||
@@ -120,6 +156,18 @@ class ControlPanel {
|
||||
$('#clear-walls').click( function() {
|
||||
this.engine.env.clearWalls();
|
||||
}.bind(this));
|
||||
$('#clear-editor').click( function() {
|
||||
this.engine.organism_editor.clear();
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
setMode(mode) {
|
||||
this.env_controller.mode = mode;
|
||||
this.editor_controller.mode = mode;
|
||||
}
|
||||
|
||||
setEditorOrganism(org) {
|
||||
this.engine.organism_editor.setOrganismToCopyOf(org);
|
||||
}
|
||||
|
||||
changeEngineSpeed(change_val) {
|
||||
53
src/Controllers/EditorController.js
Normal file
53
src/Controllers/EditorController.js
Normal file
@@ -0,0 +1,53 @@
|
||||
const CanvasController = require("./CanvasController");
|
||||
const Modes = require("./ControlModes");
|
||||
const CellTypes = require("../Organism/Cell/CellTypes");
|
||||
|
||||
class EditorController extends CanvasController{
|
||||
constructor(env, canvas) {
|
||||
super(env, canvas);
|
||||
this.mode = Modes.None;
|
||||
this.edit_cell_type = null;
|
||||
this.highlight_org = false;
|
||||
this.defineCellTypeSelection();
|
||||
}
|
||||
|
||||
mouseMove() {
|
||||
|
||||
}
|
||||
|
||||
mouseDown() {
|
||||
if (this.edit_cell_type == null || this.mode != Modes.Edit)
|
||||
return;
|
||||
if (this.left_click)
|
||||
this.env.addCellToOrg(this.mouse_c, this.mouse_r, this.edit_cell_type);
|
||||
if (this.right_click)
|
||||
this.env.removeCellFromOrg(this.mouse_c, this.mouse_r);
|
||||
}
|
||||
|
||||
defineCellTypeSelection() {
|
||||
var self = this;
|
||||
$('.cell-type').click( function() {
|
||||
switch(this.id){
|
||||
case "mouth":
|
||||
self.edit_cell_type = CellTypes.mouth;
|
||||
break;
|
||||
case "producer":
|
||||
self.edit_cell_type = CellTypes.producer;
|
||||
break;
|
||||
case "mover":
|
||||
self.edit_cell_type = CellTypes.mover;
|
||||
break;
|
||||
case "killer":
|
||||
self.edit_cell_type = CellTypes.killer;
|
||||
break;
|
||||
case "armor":
|
||||
self.edit_cell_type = CellTypes.armor;
|
||||
break;
|
||||
}
|
||||
$(".cell-type" ).css( "border-color", "black" );
|
||||
$("#"+this.id).css("border-color", "yellow");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = EditorController;
|
||||
73
src/Controllers/EnvironmentController.js
Normal file
73
src/Controllers/EnvironmentController.js
Normal file
@@ -0,0 +1,73 @@
|
||||
const CanvasController = require("./CanvasController");
|
||||
const Organism = require('../Organism/Organism');
|
||||
const Modes = require("./ControlModes");
|
||||
const CellTypes = require("../Organism/Cell/CellTypes");
|
||||
|
||||
class EnvironmentController extends CanvasController{
|
||||
constructor(env, canvas) {
|
||||
super(env, canvas);
|
||||
this.mode = Modes.None;
|
||||
this.org_to_clone = null;
|
||||
}
|
||||
|
||||
mouseMove() {
|
||||
this.performModeAction();
|
||||
}
|
||||
|
||||
mouseDown() {
|
||||
this.performModeAction();
|
||||
}
|
||||
|
||||
performModeAction() {
|
||||
var mode = this.mode;
|
||||
var right_click = this.right_click;
|
||||
var left_click = this.left_click;
|
||||
if (mode != Modes.None && (right_click || left_click)) {
|
||||
var cell = this.cur_cell;
|
||||
if (cell == null){
|
||||
return;
|
||||
}
|
||||
switch(mode) {
|
||||
case Modes.FoodDrop:
|
||||
if (left_click && cell.type == CellTypes.empty){
|
||||
this.env.changeCell(cell.col, cell.row, CellTypes.food, null);
|
||||
}
|
||||
else if (right_click && cell.type == CellTypes.food){
|
||||
this.env.changeCell(cell.col, cell.row, CellTypes.empty, null);
|
||||
}
|
||||
break;
|
||||
case Modes.WallDrop:
|
||||
if (left_click && (cell.type == CellTypes.empty || cell.type == CellTypes.food)){
|
||||
this.env.changeCell(cell.col, cell.row, CellTypes.wall, null);
|
||||
}
|
||||
else if (right_click && cell.type == CellTypes.wall){
|
||||
this.env.changeCell(cell.col, cell.row, CellTypes.empty, null);
|
||||
}
|
||||
break;
|
||||
case Modes.ClickKill:
|
||||
if (this.cur_org != null)
|
||||
this.cur_org.die();
|
||||
break;
|
||||
|
||||
case Modes.Select:
|
||||
if (this.cur_org != null){
|
||||
this.control_panel.setEditorOrganism(this.cur_org);
|
||||
}
|
||||
break;
|
||||
|
||||
case Modes.Clone:
|
||||
if (this.org_to_clone != null){
|
||||
var new_org = new Organism(this.mouse_c, this.mouse_r, this.env, this.org_to_clone);
|
||||
if (new_org.isClear(this.mouse_c, this.mouse_r)){
|
||||
this.env.addOrganism(new_org)
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
module.exports = EnvironmentController;
|
||||
@@ -1,5 +1,6 @@
|
||||
const Environment = require('./Environment');
|
||||
const ControlPanel = require('./ControlPanel');
|
||||
const Environment = require('./Environments/Environment');
|
||||
const ControlPanel = require('./Controllers/ControlPanel');
|
||||
const OrganismEditor = require('./Environments/OrganismEditor');
|
||||
|
||||
const render_speed = 60;
|
||||
|
||||
@@ -7,6 +8,7 @@ class Engine{
|
||||
constructor(){
|
||||
this.fps = 60;
|
||||
this.env = new Environment(5);
|
||||
this.organism_editor = new OrganismEditor();
|
||||
this.controlpanel = new ControlPanel(this);
|
||||
this.env.OriginOfLife();
|
||||
this.last_update = Date.now();
|
||||
@@ -21,7 +23,7 @@ class Engine{
|
||||
if (fps > 300)
|
||||
fps = 300;
|
||||
this.fps = fps;
|
||||
this.game_loop = setInterval(function(){this.update();}.bind(this), 1000/fps);
|
||||
this.game_loop = setInterval(function(){this.environmentUpdate();}.bind(this), 1000/fps);
|
||||
this.running = true;
|
||||
if (this.fps >= render_speed) {
|
||||
if (this.render_loop != null) {
|
||||
@@ -41,23 +43,28 @@ class Engine{
|
||||
|
||||
setRenderLoop() {
|
||||
if (this.render_loop == null) {
|
||||
this.render_loop = setInterval(function(){this.env.render();this.controlpanel.update();}.bind(this), 1000/render_speed);
|
||||
this.render_loop = setInterval(function(){this.necessaryUpdate();}.bind(this), 1000/render_speed);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
update() {
|
||||
environmentUpdate() {
|
||||
this.delta_time = Date.now() - this.last_update;
|
||||
this.last_update = Date.now();
|
||||
this.env.update(this.delta_time);
|
||||
this.actual_fps = 1/this.delta_time*1000;
|
||||
if(this.render_loop == null){
|
||||
this.env.render();
|
||||
this.controlpanel.update();
|
||||
this.necessaryUpdate();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
necessaryUpdate() {
|
||||
this.env.render();
|
||||
this.controlpanel.update();
|
||||
this.organism_editor.update();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = Engine;
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
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');
|
||||
const Grid = require('../Grid/GridMap');
|
||||
const Renderer = require('../Rendering/Renderer');
|
||||
const GridMap = require('../Grid/GridMap');
|
||||
const Organism = require('../Organism/Organism');
|
||||
const CellTypes = require('../Organism/Cell/CellTypes');
|
||||
const Cell = require('../Organism/Cell/Cell');
|
||||
const EnvironmentController = require('../Controllers/EnvironmentController');
|
||||
|
||||
class Environment{
|
||||
constructor(cell_size) {
|
||||
this.renderer = new Renderer('canvas', this, cell_size);
|
||||
this.renderer = new Renderer('env-canvas', 'env', 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.renderer.renderFullGrid(this.grid_map.grid);
|
||||
this.organisms = [];
|
||||
this.walls = [];
|
||||
this.total_mutability = 0;
|
||||
@@ -85,7 +85,7 @@ class Environment{
|
||||
reset() {
|
||||
this.organisms = [];
|
||||
this.grid_map.fillGrid(CellTypes.empty);
|
||||
this.renderer.renderFullGrid();
|
||||
this.renderer.renderFullGrid(this.grid_map.grid);
|
||||
this.total_mutability = 0;
|
||||
this.OriginOfLife();
|
||||
}
|
||||
84
src/Environments/OrganismEditor.js
Normal file
84
src/Environments/OrganismEditor.js
Normal file
@@ -0,0 +1,84 @@
|
||||
const Organism = require("../Organism/Organism");
|
||||
const GridMap = require('../Grid/GridMap');
|
||||
const Renderer = require('../Rendering/Renderer');
|
||||
const CellTypes = require('../Organism/Cell/CellTypes');
|
||||
const EditorController = require("../Controllers/EditorController");
|
||||
const Cell = require("../Organism/Cell/Cell");
|
||||
|
||||
class OrganismEditor {
|
||||
constructor() {
|
||||
this.is_active = true;
|
||||
var cell_size = 20;
|
||||
this.grid_map = new GridMap(11, 11, cell_size);
|
||||
this.renderer = new Renderer('editor-canvas', 'editor-env', cell_size);
|
||||
this.controller = new EditorController(this, this.renderer.canvas);
|
||||
this.clear();
|
||||
|
||||
this.renderer.renderFullGrid(this.grid_map.grid);
|
||||
}
|
||||
|
||||
update() {
|
||||
if (this.is_active){
|
||||
this.renderer.renderHighlights();
|
||||
}
|
||||
}
|
||||
|
||||
changeCell(c, r, type, owner) {
|
||||
this.grid_map.setCellType(c, r, type);
|
||||
this.grid_map.setCellOwner(c, r, owner);
|
||||
this.renderer.renderFullGrid(this.grid_map.grid);
|
||||
}
|
||||
|
||||
// absolute c r, not local
|
||||
addCellToOrg(c, r, type) {
|
||||
var center = this.grid_map.getCenter();
|
||||
var loc_c = c - center[0];
|
||||
var loc_r = r - center[1];
|
||||
var prev_cell = this.organism.getLocalCell(loc_c, loc_r)
|
||||
if (prev_cell != null) {
|
||||
prev_cell.type = type;
|
||||
this.changeCell(c, r, type, this.organism);
|
||||
}
|
||||
else if (this.organism.addCell(type, loc_c, loc_r)){
|
||||
this.changeCell(c, r, type, this.organism);
|
||||
}
|
||||
}
|
||||
|
||||
removeCellFromOrg(c, r) {
|
||||
var center = this.grid_map.getCenter();
|
||||
var loc_c = c - center[0];
|
||||
var loc_r = r - center[1];
|
||||
if (loc_c == 0 && loc_r == 0){
|
||||
alert("Cannot remove center cell");
|
||||
return;
|
||||
}
|
||||
var prev_cell = this.organism.getLocalCell(loc_c, loc_r)
|
||||
if (prev_cell != null) {
|
||||
if (this.organism.removeCell(loc_c, loc_r)) {
|
||||
this.changeCell(c, r, CellTypes.empty, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setOrganismToCopyOf(orig_org){
|
||||
this.grid_map.fillGrid(CellTypes.empty);
|
||||
var center = this.grid_map.getCenter();
|
||||
this.organism = new Organism(center[0], center[1], this, orig_org);
|
||||
this.organism.updateGrid();
|
||||
}
|
||||
|
||||
getCopyOfOrg() {
|
||||
var new_org = new Organism(0, 0, null, this.organism);
|
||||
return new_org;
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.grid_map.fillGrid(CellTypes.empty);
|
||||
var center = this.grid_map.getCenter();
|
||||
this.organism = new Organism(center[0], center[1], this, null);
|
||||
this.organism.addCell(CellTypes.mouth, 0, 0);
|
||||
this.organism.updateGrid();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = OrganismEditor;
|
||||
@@ -1,5 +1,5 @@
|
||||
const Cell = require('./Cell');
|
||||
const CellTypes = require('./CellTypes');
|
||||
const Cell = require('../Organism/Cell/Cell');
|
||||
const CellTypes = require('../Organism/Cell/CellTypes');
|
||||
|
||||
class GridMap {
|
||||
constructor(cols, rows, cell_size, filltype=CellTypes.empty) {
|
||||
@@ -1,4 +1,4 @@
|
||||
const Neighbors = require("./Neighbors");
|
||||
const Neighbors = require("./Grid/Neighbors");
|
||||
|
||||
const Hyperparams = {
|
||||
lifespanMultiplier: 100,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const CellTypes = require("./CellTypes");
|
||||
const Hyperparams = require("./Hyperparameters");
|
||||
const Hyperparams = require("../../Hyperparameters");
|
||||
|
||||
// A cell exists in a grid system.
|
||||
class Cell{
|
||||
@@ -1,6 +1,6 @@
|
||||
const CellTypes = require("./CellTypes");
|
||||
const Directions = require("./Directions");
|
||||
const Hyperparams = require("./Hyperparameters");
|
||||
const Directions = require("../Directions");
|
||||
const Hyperparams = require("../../Hyperparameters");
|
||||
|
||||
// A local cell is a lightweight container for a cell in an organism. It does not directly exist in the grid
|
||||
class LocalCell{
|
||||
@@ -1,9 +1,9 @@
|
||||
const CellTypes = require("./CellTypes");
|
||||
const Cell = require("./Cell");
|
||||
const GridMap = require("./GridMap");
|
||||
const LocalCell = require("./LocalCell");
|
||||
const Neighbors = require("./Neighbors");
|
||||
const Hyperparams = require("./Hyperparameters");
|
||||
const CellTypes = require("./Cell/CellTypes");
|
||||
const Cell = require("./Cell/Cell");
|
||||
const GridMap = require("../Grid/GridMap");
|
||||
const LocalCell = require("./Cell/LocalCell");
|
||||
const Neighbors = require("../Grid/Neighbors");
|
||||
const Hyperparams = require("../Hyperparameters");
|
||||
const Directions = require("./Directions");
|
||||
|
||||
const directions = [[0,1],[0,-1],[1,0],[-1,0]]
|
||||
@@ -33,9 +33,11 @@ class Organism {
|
||||
|
||||
addCell(type, c, r) {
|
||||
for (var cell of this.cells) {
|
||||
if (cell.loc_col == c && cell.loc_row == r)
|
||||
if (cell.loc_col == c && cell.loc_row == r){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
this.checkProducerMover(type);
|
||||
this.cells.push(new LocalCell(type, c, r));
|
||||
return true;
|
||||
@@ -65,6 +67,15 @@ class Organism {
|
||||
return true;
|
||||
}
|
||||
|
||||
getLocalCell(c, r) {
|
||||
for (var cell of this.cells) {
|
||||
if (cell.loc_col == c && cell.loc_row == r){
|
||||
return cell;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
checkProducerMover(type) {
|
||||
if (type == CellTypes.producer)
|
||||
this.is_producer = true;
|
||||
@@ -125,8 +136,11 @@ class Organism {
|
||||
var direction_r = direction[1];
|
||||
var offset = (Math.floor(Math.random() * 2)) * 2;
|
||||
|
||||
var new_c = this.c + (direction_c*this.cells.length*2) + (direction_c*offset);
|
||||
var new_r = this.r + (direction_r*this.cells.length*2) + (direction_r*offset);
|
||||
var new_c = this.c + (direction_c*Math.min(this.cells.length*2, 15)) + (direction_c*offset);
|
||||
var new_r = this.r + (direction_r*Math.min(this.cells.length*2, 15)) + (direction_r*offset);
|
||||
|
||||
// var new_c = Math.min(this.cells.length*2, 10);
|
||||
// var new_r = Math.min(this.cells.length*2, 10);
|
||||
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;
|
||||
@@ -1,15 +1,14 @@
|
||||
|
||||
// Renderer controls access to a canvas. There is one renderer for each canvas
|
||||
class Renderer {
|
||||
constructor(canvas_id, env, cell_size) {
|
||||
constructor(canvas_id, container_id, cell_size) {
|
||||
this.cell_size = cell_size;
|
||||
this.env = env;
|
||||
this.canvas = document.getElementById(canvas_id);
|
||||
this.ctx = this.canvas.getContext("2d");
|
||||
this.canvas.width = $('.env').width();
|
||||
this.canvas.height = $('.env').height();
|
||||
this.height = canvas.height;
|
||||
this.width = canvas.width;
|
||||
this.canvas.width = $('#'+container_id).width();
|
||||
this.canvas.height = $('#'+container_id).height();
|
||||
this.height = this.canvas.height;
|
||||
this.width = this.canvas.width;
|
||||
this.cells_to_render = new Set();
|
||||
this.cells_to_highlight = new Set();
|
||||
this.highlighted_cells = new Set();
|
||||
@@ -20,8 +19,7 @@ class Renderer {
|
||||
this.ctx.fillRect(0, 0, this.height, this.width);
|
||||
}
|
||||
|
||||
renderFullGrid() {
|
||||
var grid = this.env.grid_map.grid;
|
||||
renderFullGrid(grid) {
|
||||
for (var col of grid) {
|
||||
for (var cell of col){
|
||||
this.ctx.fillStyle = cell.getColor();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
'user strict';
|
||||
'use strict';
|
||||
|
||||
import Engine from './Engine';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user