diff --git a/Changelog.md b/Changelog.md
index bf73909..844c04a 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -3,14 +3,20 @@
## 1.0.2 (current development)
### UI Enhancements:
-- Button to generate random walls with perlin noise generator
+- New tab for world controls
+ - Relocated grid controls, auto reset to this tab
+ - Button to generate random walls with perlin noise
+ - Options for starting state, including simple producer and empty state
+ - Option to not clear walls when resetting
+ - Option to pause on total extinction
+- Combined `Movers can rotate` and `Offspring rotate` simulation controls into `Rotation enabled`
- Can now drag view while rendering is off
### Simulation Enhancements:
+-
### Bug Fixes:
- Armor is no longer ignored when checking for clear reproduction space
--
Thanks to contributors:
diff --git a/dist/css/style.css b/dist/css/style.css
index a0624dc..f0a008f 100644
--- a/dist/css/style.css
+++ b/dist/css/style.css
@@ -57,11 +57,15 @@ body{
img {
image-rendering: -moz-crisp-edges;
- image-rendering: -webkit-crisp-edges;
- image-rendering: pixelated;
- image-rendering: crisp-edges;
- width: 60%;
+ image-rendering: -webkit-crisp-edges;
+ image-rendering: pixelated;
+ image-rendering: crisp-edges;
+ object-fit: cover;
+ width: 85%;
+ max-width: 500px;
+ max-height: 40%;
border-radius: 10px;
+ overflow: hidden;
}
button {
@@ -134,6 +138,10 @@ button:active{
background-color: #81d2c7;
color: black;
}
+.open-tab {
+ background-color: #66a39b;
+ color: black;
+}
.tab {
grid-template-columns: repeat(2, 1fr);
@@ -256,4 +264,16 @@ button:active{
}
#maximize-hot-control {
right: 10px;
+}
+
+.grid-size-in {
+ width: 75px;
+}
+
+#video {
+ height: 100%;
+ max-height: 190px;
+ margin: auto;
+ margin-bottom: 0;
+ padding-bottom: 0;
}
\ No newline at end of file
diff --git a/dist/index.html b/dist/index.html
index 5585f26..0835452 100644
--- a/dist/index.html
+++ b/dist/index.html
@@ -24,58 +24,35 @@
-
-
Simulation Controls
@@ -186,11 +199,8 @@
Lifespan multiplier:
- Movers can rotate
-
-
- Offspring rotate
-
+ Rotation Enabled
+
One touch kill
diff --git a/src/Controllers/ControlPanel.js b/src/Controllers/ControlPanel.js
index fcbe8b3..f566692 100644
--- a/src/Controllers/ControlPanel.js
+++ b/src/Controllers/ControlPanel.js
@@ -1,6 +1,7 @@
const Hyperparams = require("../Hyperparameters");
const Modes = require("./ControlModes");
const StatsPanel = require("../Stats/StatsPanel");
+const WorldConfig = require("../WorldConfig");
class ControlPanel {
constructor(engine) {
@@ -8,9 +9,9 @@ class ControlPanel {
this.defineMinMaxControls();
this.defineHotkeys();
this.defineEngineSpeedControls();
- this.defineGridSizeControls();
this.defineTabNavigation();
this.defineHyperparameterControls();
+ this.defineWorldControls();
this.defineModeControls();
this.defineChallenges();
this.fps = engine.fps;
@@ -114,11 +115,14 @@ class ControlPanel {
defineEngineSpeedControls(){
this.slider = document.getElementById("slider");
this.slider.oninput = function() {
- this.fps = this.slider.value
+ const max_fps = 300;
+ this.fps = this.slider.value;
+ if (this.fps>=max_fps) this.fps = 1000;
if (this.engine.running) {
this.changeEngineSpeed(this.fps);
}
- $('#fps').text("Target FPS: "+this.fps);
+ let text = this.fps >= max_fps ? 'MAX' : this.fps;
+ $('#fps').text("Target FPS: "+text);
}.bind(this);
$('.pause-button').click(function() {
$('.pause-button').find("i").toggleClass("fa fa-pause");
@@ -134,18 +138,39 @@ class ControlPanel {
$('.headless').click(function() {
$('.headless').find("i").toggleClass("fa fa-eye");
$('.headless').find("i").toggleClass("fa fa-eye-slash");
- if (Hyperparams.headless){
+ if (WorldConfig.headless){
$('#headless-notification').css('display', 'none');
this.engine.env.renderFull();
}
else {
$('#headless-notification').css('display', 'block');
}
- Hyperparams.headless = !Hyperparams.headless;
+ WorldConfig.headless = !WorldConfig.headless;
}.bind(this));
}
- defineGridSizeControls() {
+ defineTabNavigation() {
+ this.tab_id = 'about';
+ var self = this;
+ $('.tabnav-item').click(function() {
+ $('.tab').css('display', 'none');
+ var tab = '#'+this.id+'.tab';
+ $(tab).css('display', 'grid');
+ $('.tabnav-item').removeClass('open-tab')
+ $('#'+this.id+'.tabnav-item').addClass('open-tab');
+ self.engine.organism_editor.is_active = (this.id == 'editor');
+ self.stats_panel.stopAutoRender();
+ if (this.id === 'stats') {
+ self.stats_panel.startAutoRender();
+ }
+ else if (this.id === 'editor') {
+ self.editor_controller.refreshDetailsPanel();
+ }
+ self.tab_id = this.id;
+ });
+ }
+
+ defineWorldControls() {
$('#fill-window').change(function() {
if (this.checked)
$('.col-row-input').css('display' ,'none');
@@ -168,25 +193,20 @@ class ControlPanel {
this.stats_panel.reset();
}.bind(this));
- }
- defineTabNavigation() {
- this.tab_id = 'about';
- var self = this;
- $('.tabnav-item').click(function() {
- $('.tab').css('display', 'none');
- var tab = '#'+this.id+'.tab';
- $(tab).css('display', 'grid');
- self.engine.organism_editor.is_active = (this.id == 'editor');
- self.stats_panel.stopAutoRender();
- if (this.id === 'stats') {
- self.stats_panel.startAutoRender();
- }
- else if (this.id === 'editor') {
- self.editor_controller.refreshDetailsPanel();
- }
- self.tab_id = this.id;
+ $('#auto-reset').change(function() {
+ WorldConfig.auto_reset = this.checked;
});
+ $('#auto-pause').change(function() {
+ WorldConfig.auto_pause = this.checked;
+ });
+ $('#clear-walls-reset').change(function() {
+ WorldConfig.clear_walls_on_reset = this.checked;
+ })
+
+ $('#start-state').change ( function() {
+ WorldConfig.start_state = $("#start-state").val();
+ }.bind(this));
}
defineHyperparameterControls() {
@@ -197,11 +217,8 @@ class ControlPanel {
Hyperparams.lifespanMultiplier = $('#lifespan-multiplier').val();
}.bind(this));
- $('#mover-rot').change(function() {
- Hyperparams.moversCanRotate = this.checked;
- });
- $('#offspring-rot').change(function() {
- Hyperparams.offspringRotate = this.checked;
+ $('#rot-enabled').change(function() {
+ Hyperparams.rotationEnabled = this.checked;
});
$('#insta-kill').change(function() {
Hyperparams.instaKill = this.checked;
@@ -258,8 +275,7 @@ class ControlPanel {
Hyperparams.setDefaults();
$('#food-prod-prob').val(Hyperparams.foodProdProb);
$('#lifespan-multiplier').val(Hyperparams.lifespanMultiplier);
- $('#mover-rot').prop('checked', Hyperparams.moversCanRotate);
- $('#offspring-rot').prop('checked', Hyperparams.offspringRotate);
+ $('#rot-enabled').prop('checked', Hyperparams.rotationEnabled);
$('#insta-kill').prop('checked', Hyperparams.instaKill);
$('#evolved-mutation').prop('checked', !Hyperparams.useGlobalMutability);
$('#add-prob').val(Hyperparams.addProb);
@@ -324,15 +340,10 @@ class ControlPanel {
$('#clear-env').click( () => {
env.reset(true, false);
this.stats_panel.reset();
- env.auto_reset = false;
- $('#auto-reset').prop('checked', false);;
});
$('#random-walls').click( function() {
this.env_controller.randomizeWalls();
}.bind(this));
- $('#auto-reset').change(function() {
- env.auto_reset = this.checked;
- });
$('#clear-walls').click( function() {
this.engine.env.clearWalls();
}.bind(this));
@@ -406,7 +417,7 @@ class ControlPanel {
$('#fps-actual').text("Actual FPS: " + Math.floor(this.engine.actual_fps));
$('#reset-count').text("Auto reset count: " + this.engine.env.reset_count);
this.stats_panel.updateDetails();
- if (Hyperparams.headless)
+ if (WorldConfig.headless)
this.updateHeadlessIcon(delta_time);
}
diff --git a/src/Controllers/EnvironmentController.js b/src/Controllers/EnvironmentController.js
index 5e8b963..17da00f 100644
--- a/src/Controllers/EnvironmentController.js
+++ b/src/Controllers/EnvironmentController.js
@@ -4,7 +4,7 @@ const Modes = require("./ControlModes");
const CellStates = require("../Organism/Cell/CellStates");
const Neighbors = require("../Grid/Neighbors");
const FossilRecord = require("../Stats/FossilRecord");
-const Hyperparams = require("../Hyperparameters");
+const WorldConfig = require("../WorldConfig");
const Perlin = require("../Utils/Perlin");
class EnvironmentController extends CanvasController{
@@ -98,7 +98,7 @@ class EnvironmentController extends CanvasController{
}
performModeAction() {
- if (Hyperparams.headless && this.mode != Modes.Drag)
+ if (WorldConfig.headless && this.mode != Modes.Drag)
return;
var mode = this.mode;
var right_click = this.right_click;
diff --git a/src/Environments/WorldEnvironment.js b/src/Environments/WorldEnvironment.js
index fdf48c3..5c3f9b9 100644
--- a/src/Environments/WorldEnvironment.js
+++ b/src/Environments/WorldEnvironment.js
@@ -6,6 +6,7 @@ const CellStates = require('../Organism/Cell/CellStates');
const EnvironmentController = require('../Controllers/EnvironmentController');
const Hyperparams = require('../Hyperparameters.js');
const FossilRecord = require('../Stats/FossilRecord');
+const WorldConfig = require('../WorldConfig');
class WorldEnvironment extends Environment{
constructor(cell_size) {
@@ -18,7 +19,6 @@ class WorldEnvironment extends Environment{
this.organisms = [];
this.walls = [];
this.total_mutability = 0;
- this.auto_reset = true;
this.largest_cell_count = 0;
this.reset_count = 0;
this.total_ticks = 0;
@@ -45,7 +45,7 @@ class WorldEnvironment extends Environment{
}
render() {
- if (Hyperparams.headless) {
+ if (WorldConfig.headless) {
this.renderer.cells_to_render.clear();
return;
}
@@ -58,24 +58,37 @@ class WorldEnvironment extends Environment{
}
removeOrganisms(org_indeces) {
+ let start_pop = this.organisms.length;
for (var i of org_indeces.reverse()){
this.total_mutability -= this.organisms[i].mutability;
this.organisms.splice(i, 1);
}
- if (this.organisms.length == 0 && this.auto_reset){
- this.reset_count++;
- this.reset(false);
+ if (this.organisms.length === 0 && start_pop > 0) {
+ if (WorldConfig.auto_pause)
+ $('.pause-button')[0].click();
+ else if(WorldConfig.auto_reset) {
+ this.reset_count++;
+ this.reset(false);
+ }
}
}
OriginOfLife() {
var center = this.grid_map.getCenter();
- var org = new Organism(center[0], center[1], this);
- org.anatomy.addDefaultCell(CellStates.mouth, 0, 0);
- org.anatomy.addDefaultCell(CellStates.producer, 1, 1);
- org.anatomy.addDefaultCell(CellStates.producer, -1, -1);
- this.addOrganism(org);
- FossilRecord.addSpecies(org, null);
+ switch (WorldConfig.start_state){
+ case 'simple-prod':
+ var org = new Organism(center[0], center[1], this);
+ org.anatomy.addDefaultCell(CellStates.mouth, 0, 0);
+ org.anatomy.addDefaultCell(CellStates.producer, 1, 1);
+ org.anatomy.addDefaultCell(CellStates.producer, -1, -1);
+ this.addOrganism(org);
+ FossilRecord.addSpecies(org, null);
+ break;
+ case 'random-orgs':
+ break;
+ case 'no-orgs':
+ break;
+ }
}
addOrganism(organism) {
@@ -136,7 +149,7 @@ class WorldEnvironment extends Environment{
return;
this.organisms = [];
- this.grid_map.fillGrid(CellStates.empty);
+ this.grid_map.fillGrid(CellStates.empty, !WorldConfig.clear_walls_on_reset);
this.renderer.renderFullGrid(this.grid_map.grid);
this.total_mutability = 0;
this.total_ticks = 0;
diff --git a/src/Grid/GridMap.js b/src/Grid/GridMap.js
index 24f167c..84db4ca 100644
--- a/src/Grid/GridMap.js
+++ b/src/Grid/GridMap.js
@@ -21,9 +21,10 @@ class GridMap {
}
}
- fillGrid(state) {
+ fillGrid(state, ignore_walls=false) {
for (var col of this.grid) {
for (var cell of col) {
+ if (ignore_walls && cell.state===CellStates.wall) continue;
cell.setType(state);
cell.owner = null;
cell.cell_owner = null;
diff --git a/src/Hyperparameters.js b/src/Hyperparameters.js
index 4199cd9..67ece3c 100644
--- a/src/Hyperparameters.js
+++ b/src/Hyperparameters.js
@@ -16,8 +16,7 @@ const Hyperparams = {
this.changeProb = 33;
this.removeProb = 33;
- this.moversCanRotate = true;
- this.offspringRotate = true;
+ this.rotationEnabled = true;
this.foodBlocksReproduction = true;
this.moversCanProduce = false;
diff --git a/src/Organism/Cell/GridCell.js b/src/Organism/Cell/GridCell.js
index 10d637b..fd3bdff 100644
--- a/src/Organism/Cell/GridCell.js
+++ b/src/Organism/Cell/GridCell.js
@@ -5,7 +5,7 @@ const Hyperparams = require("../../Hyperparameters");
class Cell{
constructor(state, col, row, x, y){
this.owner = null; // owner organism
- this.cell_owner = null; // owner cell of ^that organism
+ this.cell_owner = null; // specific body cell of the owner organism that occupies this grid cell
this.setType(state);
this.col = col;
this.row = row;
diff --git a/src/Organism/Organism.js b/src/Organism/Organism.js
index 589bfb9..ef38f03 100644
--- a/src/Organism/Organism.js
+++ b/src/Organism/Organism.js
@@ -17,7 +17,7 @@ class Organism {
this.anatomy = new Anatomy(this)
this.direction = Directions.down; // direction of movement
this.rotation = Directions.up; // direction of rotation
- this.can_rotate = Hyperparams.moversCanRotate;
+ this.can_rotate = Hyperparams.rotationEnabled;
this.move_count = 0;
this.move_range = 4;
this.ignore_brain_for = 0;
@@ -63,7 +63,7 @@ class Organism {
//produce mutated child
//check nearby locations (is there room and a direct path)
var org = new Organism(0, 0, this.env, this);
- if(Hyperparams.offspringRotate){
+ if(Hyperparams.rotationEnabled){
org.rotation = Directions.getRandomDirection();
}
var prob = this.mutability;
diff --git a/src/WorldConfig.js b/src/WorldConfig.js
new file mode 100644
index 0000000..1923453
--- /dev/null
+++ b/src/WorldConfig.js
@@ -0,0 +1,9 @@
+const WorldConfig = {
+ headless: false,
+ clear_walls_on_reset: false,
+ start_state: 'simple-prod',
+ auto_reset: true,
+ auto_pause: false,
+}
+
+module.exports = WorldConfig;
\ No newline at end of file