edit mode fixes
This commit is contained in:
289
dist/bundle.js
vendored
289
dist/bundle.js
vendored
File diff suppressed because one or more lines are too long
51
dist/css/style.css
vendored
51
dist/css/style.css
vendored
@@ -14,6 +14,7 @@ canvas {
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
#env {
|
||||
@@ -81,7 +82,7 @@ canvas {
|
||||
padding: 10px
|
||||
}
|
||||
|
||||
.tab#about {
|
||||
.tab#editor {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
@@ -93,63 +94,61 @@ canvas {
|
||||
grid-column: 2;
|
||||
}
|
||||
|
||||
.control-mode-button {
|
||||
border-color: gray;
|
||||
background-color: lightgray;
|
||||
}
|
||||
|
||||
#none-button {
|
||||
background-color: gray;
|
||||
}
|
||||
|
||||
.global-mutation-in {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
#editor-panel{
|
||||
display: flex;
|
||||
}
|
||||
.edit-mode-btn {
|
||||
/* border-color: gray; */
|
||||
background-color: white;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
#drop-org {
|
||||
bottom: 0;
|
||||
}
|
||||
#editor-env {
|
||||
position: absolute;
|
||||
height: 220px;
|
||||
width: 220px;
|
||||
padding: 10px;
|
||||
float: left;
|
||||
height: 195px;
|
||||
width: 195px;
|
||||
/* 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;
|
||||
|
||||
}
|
||||
.cell-legend-type {
|
||||
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;
|
||||
|
||||
67
dist/html/index.html
vendored
67
dist/html/index.html
vendored
@@ -4,6 +4,7 @@
|
||||
<meta charste="UTF-8">
|
||||
<title>Evolution Simulator</title>
|
||||
<link rel="stylesheet" href="../css/style.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
@@ -16,28 +17,29 @@
|
||||
<div id='speed-controller' class='control-set'>
|
||||
<h2>Simulation Speed</h2>
|
||||
<input id="slider" type="range" min="1" max="300" value="60">
|
||||
<button id='pause-button'>Pause</button>
|
||||
<button id='pause-button'><i class="fa fa-pause"></i></button>
|
||||
<p id='fps'>Target FPS: 60</p>
|
||||
<p id='fps-actual'></p>
|
||||
<br/>
|
||||
<br>
|
||||
<button id='reset-env'>Reset Environment</button>
|
||||
<label for="auto-reset">Auto Reset</label>
|
||||
<input type="checkbox" id="auto-reset" checked>
|
||||
<br><br/>
|
||||
<br>
|
||||
<p id='reset-count'>Auto reset count: </p>
|
||||
<h2>Grid Size</h2>
|
||||
<label for="cell-size">Cell Size:</label>
|
||||
<input type="number" id="cell-size" min="1" max="100" value=5 step="1">
|
||||
<label for="fill-window">Fill Window</label>
|
||||
<input type="checkbox" id="fill-window" checked>
|
||||
<br/>
|
||||
<br>
|
||||
<div class='col-row-input'>
|
||||
<label for="col-input">Columns:</label>
|
||||
<input type="number" id="col-input" min="1" value=100 step="1">
|
||||
<br/>
|
||||
<br>
|
||||
<label for="row-input">Rows:</label>
|
||||
<input type="number" id="row-input" min="1" value=100 step="1">
|
||||
</div>
|
||||
<br/>
|
||||
<br>
|
||||
<button id='resize'>Resize and Reset</button>
|
||||
</div>
|
||||
|
||||
@@ -53,8 +55,16 @@
|
||||
<div id='about' class='tab'>
|
||||
<div class='left-half'>
|
||||
<h2>Welcome to the Life Engine</h2>
|
||||
<p>The life engine is a simulation of a living ecosystem, and allows organisms to survive, reproduce, spread, and compete in a very simple world. The world is a grid, and organisms are made up of cells that occupy different grid locations. Different colored cells do different things for the organism.</p>
|
||||
<p>To understand more about how the simulation works, take a look at the readme (LINK).</p>
|
||||
<p>The Life Engine simulates an evolving ecosystem and organisms that are made of cells. Different colored cells do different things.</p>
|
||||
<!-- <div id='cell-selections'>
|
||||
<div class='cell-legend-type' id='mouth' title="Mouth: Eats adjacent food."></div>
|
||||
<div class='cell-legend-type' id='producer' title="Producer: Produces adjacent food."></div>
|
||||
<div class='cell-legend-type' id='mover' title="Mover: Allows for movement and rotation."></div>
|
||||
<div class='cell-legend-type' id='killer' title="Killer: Harms oranisms in adjacent cells."></div>
|
||||
<div class='cell-legend-type' id='armor' title="Armor: Negates affects of killer cell."></div>
|
||||
<div class='cell-legend-type' id='food' title="Food: Not part of an organism. Once an organism has eaten enough food, it will reproduce."></div>
|
||||
<div class='cell-legend-type' id='wall' title="Wall: Not part of an organism. BLocks movement and reproduction."></div>
|
||||
</div> -->
|
||||
</div>
|
||||
<div class='right-half'>
|
||||
<p></p>
|
||||
@@ -64,28 +74,26 @@
|
||||
<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>
|
||||
|
||||
<button class="edit-mode-btn" id="wall" title="Drop/Remove Wall"><i class="fa fa-square"></i></button>
|
||||
<button class="edit-mode-btn" id="food" title="Drop/Remove Food"><i class="fa fa-cutlery"></i></button>
|
||||
<button class="edit-mode-btn" id="kill" title="Click to kill"><i class="fa fa-bolt"></i></button>
|
||||
|
||||
<br><br/>
|
||||
<button id='kill-all'>Kill All Organisms</button>
|
||||
<button id='clear-walls'>Clear All Walls</button>
|
||||
<button id="clear-walls" title="Clear All Walls"><i class="fa fa-window-close"></i></button>
|
||||
|
||||
</div>
|
||||
<div class='right-half'>
|
||||
<div class='right-half' id='editor-panel'>
|
||||
<button class="edit-mode-btn" id="select" title="Select organism from world"><i class="fa fa-hand-pointer-o"></i></button>
|
||||
<button class="edit-mode-btn" id="edit" title="Edit organism"><i class="fa fa-pencil"></i></button>
|
||||
<button class="edit-mode-btn" id="drop-org" title="Drop organism in world"><i class="fa fa-plus"></i></button>
|
||||
<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='mover' title="Mover: Allows for movement and rotation."></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>
|
||||
@@ -99,19 +107,19 @@
|
||||
<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/>
|
||||
<br>
|
||||
<label for="lifespan-multiplier">Lifespan multiplier:</label>
|
||||
<input type="number" id="lifespan-multiplier" min="1" max="10000" value=100 step="1">
|
||||
<br/>
|
||||
<br>
|
||||
<label for="fixed-ratio">Use fixed ratio</label>
|
||||
<input type="checkbox" id="fixed-ratio" checked>
|
||||
<h4>Organism Rotation</h4>
|
||||
<label for="mover-rot">Movers can rotate</label>
|
||||
<input type="checkbox" id="mover-rot" checked>
|
||||
<br/>
|
||||
<br>
|
||||
<label for="offspring-rot">Offspring rotate</label>
|
||||
<input type="checkbox" id="offspring-rot" checked>
|
||||
<br/>
|
||||
<br>
|
||||
<h4>Killer Cell Effects</h4>
|
||||
<label for="insta-kill">One touch kill</label>
|
||||
<input type="checkbox" id="insta-kill">
|
||||
@@ -121,16 +129,14 @@
|
||||
<br><br/>
|
||||
<h4>Mutation Rate</h4>
|
||||
<label for="evolved-mutation">Use evolved mutation rate</label>
|
||||
<input type="checkbox" id="evolved-mutation" checked>
|
||||
<label class="global-mutation-in" for="global-mutation">Global mutation rate</label>
|
||||
<input type="checkbox" id="evolved-mutation" checked> </br>
|
||||
<label class="global-mutation-in" for="global-mutation">Global mutation rate: </label>
|
||||
<input class="global-mutation-in" type="number" id="global-mutation" min="1" max="100" value=5 step="1">
|
||||
<h4>Mutation Type 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/>
|
||||
@@ -148,6 +154,7 @@
|
||||
<p id='org-count'>Organism count: </p>
|
||||
<p id='org-record'>Highest count: </p>
|
||||
<p id='avg-mut'>Average Mutation Rate: </p>
|
||||
<p id='largest-org'>Largest Organism: </p>
|
||||
</div>
|
||||
<div class='right-half'></div>
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ class ControlPanel {
|
||||
$('#fps').text("Target FPS: "+this.fps);
|
||||
}.bind(this);
|
||||
$('#pause-button').click(function() {
|
||||
if ($('#pause-button').text() == "Pause" && this.engine.running) {
|
||||
if (this.engine.running) {
|
||||
$('#pause-button').text("Play");
|
||||
this.engine.stop();
|
||||
}
|
||||
@@ -150,14 +150,10 @@ class ControlPanel {
|
||||
|
||||
defineModeControls() {
|
||||
var self = this;
|
||||
$('#editor-mode').change( function(el) {
|
||||
var selection = $(this).children("option:selected").val();
|
||||
$('.edit-mode-btn').click( function() {
|
||||
var prev_mode = self.env_controller.mode;
|
||||
$('#cell-selections').css('display', 'none');
|
||||
switch(selection){
|
||||
case "none":
|
||||
self.setMode(Modes.None);
|
||||
break;
|
||||
switch(this.id){
|
||||
case "food":
|
||||
self.setMode(Modes.FoodDrop);
|
||||
break;
|
||||
@@ -168,27 +164,20 @@ class ControlPanel {
|
||||
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);
|
||||
}
|
||||
self.setMode(Modes.Select);
|
||||
break;
|
||||
case "edit":
|
||||
self.setMode(Modes.Edit);
|
||||
$('#cell-selections').css('display', 'grid');
|
||||
$('#cell-selections').css('display', 'block');
|
||||
break;
|
||||
case "clone":
|
||||
case "drop-org":
|
||||
self.setMode(Modes.Clone);
|
||||
self.env_controller.org_to_clone = self.engine.organism_editor.getCopyOfOrg();
|
||||
break;
|
||||
}
|
||||
$('.edit-mode-btn').css('background-color', 'white');
|
||||
$('#'+this.id).css('background-color', 'lightblue');
|
||||
|
||||
});
|
||||
|
||||
var env = this.engine.env;
|
||||
@@ -198,11 +187,10 @@ class ControlPanel {
|
||||
$('#auto-reset').change(function() {
|
||||
env.auto_reset = this.checked;
|
||||
});
|
||||
$('#kill-all').click( function() {
|
||||
this.engine.env.clearOrganisms();
|
||||
}.bind(this));
|
||||
$('#clear-walls').click( function() {
|
||||
this.engine.env.clearWalls();
|
||||
if (confirm("Are you sure you want to clear all the walls?")) {
|
||||
this.engine.env.clearWalls();
|
||||
}
|
||||
}.bind(this));
|
||||
$('#clear-editor').click( function() {
|
||||
this.engine.organism_editor.clear();
|
||||
@@ -232,6 +220,8 @@ class ControlPanel {
|
||||
this.organism_record = org_count;
|
||||
$('#org-record').text("Highest count: " + this.organism_record);
|
||||
$('#avg-mut').text("Average Mutation Rate: " + Math.round(this.engine.env.averageMutability() * 100) / 100);
|
||||
$('#largest-org').text("Largest Organism: " + this.engine.env.largest_cell_count + " cells");
|
||||
$('#reset-count').text("Auto reset count: " + this.engine.env.reset_count);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,10 +12,15 @@ class EditorController extends CanvasController{
|
||||
}
|
||||
|
||||
mouseMove() {
|
||||
|
||||
if (this.right_click || this.left_click)
|
||||
this.editOrganism();
|
||||
}
|
||||
|
||||
mouseDown() {
|
||||
this.editOrganism();
|
||||
}
|
||||
|
||||
editOrganism() {
|
||||
if (this.edit_cell_type == null || this.mode != Modes.Edit)
|
||||
return;
|
||||
if (this.left_click)
|
||||
|
||||
@@ -2,6 +2,8 @@ const CanvasController = require("./CanvasController");
|
||||
const Organism = require('../Organism/Organism');
|
||||
const Modes = require("./ControlModes");
|
||||
const CellTypes = require("../Organism/Cell/CellTypes");
|
||||
const Neighbors = require("../Grid/Neighbors");
|
||||
const Cell = require("../Organism/Cell/Cell");
|
||||
|
||||
class EnvironmentController extends CanvasController{
|
||||
constructor(env, canvas) {
|
||||
@@ -29,27 +31,30 @@ class EnvironmentController extends CanvasController{
|
||||
}
|
||||
switch(mode) {
|
||||
case Modes.FoodDrop:
|
||||
if (left_click && cell.type == CellTypes.empty){
|
||||
this.env.changeCell(cell.col, cell.row, CellTypes.food, null);
|
||||
if (left_click){
|
||||
this.dropCellType(cell.col, cell.row, CellTypes.food, false);
|
||||
}
|
||||
else if (right_click && cell.type == CellTypes.food){
|
||||
this.env.changeCell(cell.col, cell.row, CellTypes.empty, null);
|
||||
else if (right_click){
|
||||
this.dropCellType(cell.col, cell.row, CellTypes.empty, false);
|
||||
}
|
||||
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);
|
||||
if (left_click){
|
||||
this.dropCellType(cell.col, cell.row, CellTypes.wall, true);
|
||||
|
||||
}
|
||||
else if (right_click && cell.type == CellTypes.wall){
|
||||
this.env.changeCell(cell.col, cell.row, CellTypes.empty, null);
|
||||
else if (right_click){
|
||||
this.dropCellType(cell.col, cell.row, CellTypes.empty, false);
|
||||
}
|
||||
break;
|
||||
case Modes.ClickKill:
|
||||
if (this.cur_org != null)
|
||||
this.cur_org.die();
|
||||
this.killNearOrganisms();
|
||||
break;
|
||||
|
||||
case Modes.Select:
|
||||
if (this.cur_org == null) {
|
||||
this.cur_org = this.findNearOrganism();
|
||||
}
|
||||
if (this.cur_org != null){
|
||||
this.control_panel.setEditorOrganism(this.cur_org);
|
||||
}
|
||||
@@ -67,12 +72,42 @@ class EnvironmentController extends CanvasController{
|
||||
}
|
||||
}
|
||||
|
||||
dropWall(cell) {
|
||||
|
||||
dropCellType(col, row, type, killBlocking=false) {
|
||||
for (var loc of Neighbors.allSelf){
|
||||
var c=col + loc[0];
|
||||
var r=row + loc[1];
|
||||
var cell = this.env.grid_map.cellAt(c, r);
|
||||
if (cell == null)
|
||||
continue;
|
||||
if (killBlocking && cell.owner != null){
|
||||
cell.owner.die();
|
||||
}
|
||||
else if (cell.owner != null) {
|
||||
continue;
|
||||
}
|
||||
this.env.changeCell(c, r, type, null);
|
||||
}
|
||||
}
|
||||
|
||||
dropFood(cell) {
|
||||
findNearOrganism() {
|
||||
for (var loc of Neighbors.all){
|
||||
var c = this.cur_cell.col + loc[0];
|
||||
var r = this.cur_cell.row + loc[1];
|
||||
var cell = this.env.grid_map.cellAt(c, r);
|
||||
if (cell.owner != null)
|
||||
return cell.owner;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
killNearOrganisms() {
|
||||
for (var loc of Neighbors.allSelf){
|
||||
var c = this.cur_cell.col + loc[0];
|
||||
var r = this.cur_cell.row + loc[1];
|
||||
var cell = this.env.grid_map.cellAt(c, r);
|
||||
if (cell.owner != null)
|
||||
cell.owner.die();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ class Environment{
|
||||
this.walls = [];
|
||||
this.total_mutability = 0;
|
||||
this.auto_reset = true;
|
||||
this.largest_cell_count = 0;
|
||||
this.reset_count = 0;
|
||||
}
|
||||
|
||||
update(delta_time) {
|
||||
@@ -41,8 +43,10 @@ class Environment{
|
||||
this.total_mutability -= this.organisms[i].mutability;
|
||||
this.organisms.splice(i, 1);
|
||||
}
|
||||
if (this.organisms.length == 0 && this.auto_reset)
|
||||
if (this.organisms.length == 0 && this.auto_reset){
|
||||
this.reset_count++;
|
||||
this.reset();
|
||||
}
|
||||
}
|
||||
|
||||
OriginOfLife() {
|
||||
@@ -58,6 +62,8 @@ class Environment{
|
||||
organism.updateGrid();
|
||||
this.total_mutability += organism.mutability;
|
||||
this.organisms.push(organism);
|
||||
if (organism.cells.length > this.largest_cell_count)
|
||||
this.largest_cell_count = organism.cells.length;
|
||||
}
|
||||
|
||||
averageMutability() {
|
||||
@@ -75,8 +81,10 @@ class Environment{
|
||||
}
|
||||
|
||||
clearWalls() {
|
||||
for(var wall of this.walls)
|
||||
this.changeCell(wall.col, wall.row, CellTypes.empty, null);
|
||||
for(var wall of this.walls){
|
||||
if (this.grid_map.cellAt(wall.col, wall.row).type == CellTypes.wall)
|
||||
this.changeCell(wall.col, wall.row, CellTypes.empty, null);
|
||||
}
|
||||
}
|
||||
|
||||
clearOrganisms() {
|
||||
@@ -85,7 +93,7 @@ class Environment{
|
||||
this.organisms = [];
|
||||
}
|
||||
|
||||
reset() {
|
||||
reset(clear_walls=true) {
|
||||
this.organisms = [];
|
||||
this.grid_map.fillGrid(CellTypes.empty);
|
||||
this.renderer.renderFullGrid(this.grid_map.grid);
|
||||
|
||||
@@ -8,8 +8,8 @@ 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);
|
||||
var cell_size = 13;
|
||||
this.grid_map = new GridMap(15, 15, cell_size);
|
||||
this.renderer = new Renderer('editor-canvas', 'editor-env', cell_size);
|
||||
this.controller = new EditorController(this, this.renderer.canvas);
|
||||
this.clear();
|
||||
|
||||
@@ -12,10 +12,15 @@
|
||||
// x
|
||||
// . .
|
||||
|
||||
//allSelf ...
|
||||
// ...
|
||||
// ...
|
||||
|
||||
const Neighbors = {
|
||||
all: [[0, 1],[0, -1],[1, 0],[-1, 0],[-1, -1],[1, 1],[-1, 1],[1, -1]],
|
||||
adjacent: [[0, 1],[0, -1],[1, 0],[-1, 0]],
|
||||
corners: [[-1, -1],[1, 1],[-1, 1],[1, -1]]
|
||||
corners: [[-1, -1],[1, 1],[-1, 1],[1, -1]],
|
||||
allSelf: [[0, 0],[0, 1],[0, -1],[1, 0],[-1, 0],[-1, -1],[1, 1],[-1, 1],[1, -1]]
|
||||
}
|
||||
|
||||
module.exports = Neighbors;
|
||||
@@ -145,8 +145,8 @@ class Organism {
|
||||
this.env.addOrganism(org);
|
||||
org.updateGrid();
|
||||
}
|
||||
|
||||
this.food_collected -= this.foodNeeded();
|
||||
|
||||
}
|
||||
|
||||
mutate() {
|
||||
|
||||
Reference in New Issue
Block a user