control tabs, organism editor, code refactor

This commit is contained in:
MaxRobinsonTheGreat
2020-07-18 00:31:46 -06:00
parent 2fc2ba7b80
commit ebb39df34a
21 changed files with 524 additions and 402 deletions

View File

@@ -0,0 +1,85 @@
class CanvasController{
constructor(env, canvas) {
this.env = env;
this.canvas = canvas;
this.mouse_x;
this.mouse_y;
this.mouse_c;
this.mouse_r;
this.left_click = false;
this.right_click = false;
this.cur_cell = null;
this.cur_org = null;
this.highlight_org = true;
this.defineEvents();
}
setControlPanel(panel){
this.control_panel = panel;
}
defineEvents() {
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.highlight_org) {
this.env.renderer.highlightOrganism(this.cur_org);
}
else if (this.cur_cell != null) {
this.env.renderer.highlightCell(this.cur_cell, true);
}
}
this.mouseMove();
});
this.canvas.addEventListener('mouseup', function(evt) {
evt.preventDefault();
this.left_click=false;
this.right_click=false;
}.bind(this));
this.canvas.addEventListener('mousedown', function(evt) {
evt.preventDefault();
if (evt.button == 0) {
this.left_click = true;
}
if (evt.button == 2)
this.right_click = true;
this.mouseDown();
}.bind(this));
this.canvas.addEventListener('contextmenu', function(evt) {
evt.preventDefault();
});
this.canvas.addEventListener('mouseleave', function(){
this.right_click = false;
this.left_click = false;
this.env.renderer.clearAllHighlights(true);
}.bind(this));
}
mouseMove() {
alert("mouse move must be overriden");
}
mouseDown() {
alert("mouse down must be overriden");
}
}
module.exports = CanvasController;

View File

@@ -0,0 +1,11 @@
const Modes = {
None: 0,
FoodDrop: 1,
WallDrop: 2,
ClickKill: 3,
Select: 4,
Edit: 5,
Clone: 6
}
module.exports = Modes;

View File

@@ -0,0 +1,192 @@
const Hyperparams = require("../Hyperparameters");
const Modes = require("./ControlModes");
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(){
this.slider = document.getElementById("slider");
this.slider.oninput = function() {
this.fps = this.slider.value
if (this.engine.running) {
this.changeEngineSpeed(this.fps);
}
$('#fps').text("Target FPS: "+this.fps);
}.bind(this);
$('#pause-button').click(function() {
if ($('#pause-button').text() == "Pause" && this.engine.running) {
$('#pause-button').text("Play");
this.engine.stop();
}
else if (!this.engine.running){
$('#pause-button').text("Pause");
this.engine.start(this.fps);
}
}.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();
if ($('#fixed-ratio').is(":checked")) {
Hyperparams.foodProdProb = food_prob;
Hyperparams.calcProducerFoodRatio(false);
$('#lifespan-multiplier').val(Hyperparams.lifespanMultiplier);
}
else{
Hyperparams.foodProdProb = food_prob;
}
}.bind(this));
$('#lifespan-multiplier').change(function() {
var lifespan = $('#lifespan-multiplier').val();
if ($('#fixed-ratio').is(":checked")) {
Hyperparams.lifespanMultiplier = lifespan;
Hyperparams.calcProducerFoodRatio(true);
$('#food-prod-prob').val(Hyperparams.foodProdProb);
}
else {
Hyperparams.lifespanMultiplier = lifespan;
}
}.bind(this));
$('.mut-prob').change( function() {
switch(this.id){
case "add-prob":
Hyperparams.addProb = this.value;
Hyperparams.balanceMutationProbs(1);
break;
case "change-prob":
Hyperparams.changeProb = this.value;
Hyperparams.balanceMutationProbs(2);
break;
case "remove-prob":
Hyperparams.removeProb = this.value;
Hyperparams.balanceMutationProbs(3);
break;
}
$('#add-prob').val(Math.floor(Hyperparams.addProb));
$('#change-prob').val(Math.floor(Hyperparams.changeProb));
$('#remove-prob').val(Math.floor(Hyperparams.removeProb));
});
$('#mover-rot').change(function() {
Hyperparams.moversCanRotate = this.checked;
});
$('#offspring-rot').change(function() {
Hyperparams.offspringRotate = this.checked;
});
$('#insta-kill').change(function() {
Hyperparams.instaKill = this.checked;
});
}
defineModeControls() {
var self = this;
$('#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 "food":
self.setMode(Modes.FoodDrop);
break;
case "wall":
self.setMode(Modes.WallDrop);
break;
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;
}
});
$('#reset-env').click( function() {
this.engine.env.reset();
}.bind(this));
$('#kill-all').click( function() {
this.engine.env.clearOrganisms();
}.bind(this));
$('#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) {
this.engine.stop();
this.engine.start(change_val)
this.fps = this.engine.fps;
}
update() {
$('#fps-actual').text("Actual FPS: " + Math.floor(this.engine.actual_fps));
var org_count = this.engine.env.organisms.length;
$('#org-count').text("Organism count: " + org_count);
if (org_count > this.organism_record)
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);
}
}
module.exports = ControlPanel;

View 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;

View 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;