Skip to content

Instantly share code, notes, and snippets.

@LABCAT
Forked from dribnet/.block
Last active June 8, 2017 12:40
Show Gist options
  • Select an option

  • Save LABCAT/8970af075aae2ac0f2428c32a18707f4 to your computer and use it in GitHub Desktop.

Select an option

Save LABCAT/8970af075aae2ac0f2428c32a18707f4 to your computer and use it in GitHub Desktop.
17.1.MDDN242 PS4
license: mit
// note: this file is poorly named - it can generally be ignored.
// helper functions below for supporting blocks/purview
function saveBlocksImages(doZoom) {
if(doZoom == null) {
doZoom = false;
}
// generate 960x500 preview.jpg of entire canvas
// TODO: should this be recycled?
var offscreenCanvas = document.createElement('canvas');
offscreenCanvas.width = 960;
offscreenCanvas.height = 500;
var context = offscreenCanvas.getContext('2d');
// background is flat white
context.fillStyle="#FFFFFF";
context.fillRect(0, 0, 960, 500);
context.drawImage(this.canvas, 0, 0, 960, 500);
// save to browser
var downloadMime = 'image/octet-stream';
var imageData = offscreenCanvas.toDataURL('image/jpeg');
imageData = imageData.replace('image/jpeg', downloadMime);
p5.prototype.downloadFile(imageData, 'preview.jpg', 'jpg');
// generate 230x120 thumbnail.png centered on mouse
offscreenCanvas.width = 230;
offscreenCanvas.height = 120;
// background is flat white
context = offscreenCanvas.getContext('2d');
context.fillStyle="#FFFFFF";
context.fillRect(0, 0, 230, 120);
if(doZoom) {
// pixelDensity does the right thing on retina displays
var pd = this._pixelDensity;
var sx = pd * mouseX - pd * 230/2;
var sy = pd * mouseY - pd * 120/2;
var sw = pd * 230;
var sh = pd * 120;
// bounds checking - just displace if necessary
if (sx < 0) {
sx = 0;
}
if (sx > this.canvas.width - sw) {
sx = this.canvas.width - sw;
}
if (sy < 0) {
sy = 0;
}
if (sy > this.canvas.height - sh) {
sy = this.canvas.height - sh;
}
// save to browser
context.drawImage(this.canvas, sx, sy, sw, sh, 0, 0, 230, 120);
}
else {
// now scaledown
var full_width = this.canvas.width;
var full_height = this.canvas.height;
context.drawImage(this.canvas, 0, 0, full_width, full_height, 0, 0, 230, 120);
}
imageData = offscreenCanvas.toDataURL('image/png');
imageData = imageData.replace('image/png', downloadMime);
p5.prototype.downloadFile(imageData, 'thumbnail.png', 'png');
}

PS4 MDDN 242 2017

Wu Xing - Five Elements/Planets - Evolution of Energy Narrative

This simulation is based on the Wu Xing philosophy also known as the five elements theory. The narrative shows the evolution of energy (chi) over the course of time. The different types of energy are more dominating during the different phases of the cosmic cycle. The five elements are also known as the five planets so I have chosen use the solar system as the scene for the narrative.

When choosing the image to use, I went back to my source of inspiration for problem set two. I have created an image based on the ‘Rising Sun’ flag from Japan. This supports my narrative very well. A sun is created in the center of the canvas and the elements are scattered throughout the rest of the canvas as the rays of the sun.

The are six agents within the simulation. Five of agents each represent a different element of the Wu Xing philosophical theory. The other agent represents the Sun and it is located in the center of the canvas/solar system.

The sun is a static agent. It is not affected by its neighbours and it does not move or change size. However it does change colour depending on the current state of nature.

The size and speed settings are the key variables that can change the narrative. The faster an element is moving the quicker the narrative will unfold. The same applies to the speed setting. The elements actually move faster as their size increases so changing the size setting also affects the speed of the narrative.

The other variable that has a great effect on the narrative is the percentage value for the random change that an element will change its state during a phase. I found that if this was set too low it didn’t appear that the element was the dominating energy. If it was set too high then the element become too dominating.

The Rules

The simulation is affected by five phases used to represent the current state of nature. Each step of the simulation represents one day and each of the phases has the following lengths:

  • Wood/Spring (Green) - 72 days
  • Fire/Summer (Red) - 72 days
  • Metal/Autumn (Silver) - 72 days
  • Water/Winter (Blue) - 72 days
  • Earth (Brown) - 4 periods of 18 days, the earth phase occurs in between each of the other phases

The five elements are all dynamic agents, constantly compelled to travel around the sun. The Wu Xing consists of two interaction cycles, a generating cycle and a overcoming cycle. The rules of the simulation have been derived from these interaction cycles:

If an element is the same as the phase of the current state of nature then it will increase in size when it collides with a neighbour that it is generated by. The elements increase in size based on the following:

  • metal is generated by earth
  • water is generated by metal
  • wood is generated by water
  • fire is generated by wood
  • earth is generated by fire

If an element collides with a neighbour that it is overcome by then it will either decrease in size or transform into the other element type:

  • earth is overcome by wood
  • metal is overcome by fire
  • water is overcome by earth
  • wood is overcome by metal
  • fire is overcome by water

If an element is the same as the phase of the current state of nature it will decrease in size. Otherwise it transforms into the element it is overcome by.

There is one other rule that is very important for demonstrating which element type is the dominating energy during the current phase. Using a random number there is a small chance (a percentage based on the current glyph size) that any given element will be transformed into the phase that represents the current state of nature.

Design Process

The simulation I have created have been driven a lot by the code provided during the different parts of the assignment. In parts two and three I created a farm based simulation which worked really well.

Part four introduced a new level of functionality which provided new inspiration so I decided to switch to a new idea. I think the narrative of my simulation is working great and I am very pleased with the final result.

I had the majority of the simulation finished by the commit for result3. However I didn't think it looked as good as it could so I spent some time improving the design. I also made some code adjustments that greatly improved the motion of the elements and the narrative that is being expressed.

function Agent1() {
//the life stage of the agent
this.life_stage = 'seedling';
//maturity of the seedling and fruit - ranges from 0-205
this.maturity = 0;
//ripeness of the fruit - ranges from 7-255
this.ripeness = 7;
// setup is run when the agent is reset
// value is a number between 0 and 100
this.setup = function(value) {
//if the value > 95 then the agent will be a tree
if(value > 95) {
this.life_stage = 'tree';
}
//otherwise it will be a seedling
else {
this.life_stage = 'seedling';
}
}
// this happens generally on mouse over
this.activate = function() {
this.life_stage = 'tree';
}
// decide on your next move based on neighbors (but don't do it yet)
this.step = function(neighbors) {
var num_trees_nearby = 0;
var num_fruit_nearby = 0;
//calculate how many of the nearby neighbors are trees or fruit
for(var i =0; i < neighbors.length; i++){
if(neighbors[i].agent.life_stage === 'tree'){
num_trees_nearby++;
}
if(neighbors[i].agent.life_stage === 'fruit'){
num_fruit_nearby++;
}
}
//if current life stage is a seedling
if(this.life_stage === 'seedling'){
this.next_life_stage = 'seedling';
//if maturity is greater than 200
if(this.maturity > 200){
//and the number of trees or fruit nearby is greater than 2
if(num_trees_nearby > 2 || num_fruit_nearby > 2){
//then the next life stage is a tree
this.next_life_stage = 'tree';
}
}
//otherwise
else {
//the maturity level increases if less than 200
if(this.maturity < 200){
this.maturity += 10.25;
}
}
}
//if current life stage is a tree
else if(this.life_stage === 'tree'){
this.next_life_stage = 'tree';
//if number of trees nearby is greater than 4
if(num_trees_nearby > 4){
//then the next life stage is fruit
this.next_life_stage = 'fruit';
}
}
//if current life stage is a fruit
else if(this.life_stage === 'fruit'){
this.next_life_stage = 'fruit';
//if the fruit is not ripe yet, increase the ripeness
if (this.ripeness < 255){
this.ripeness += 8;
}
//if the fruit is ripe and also mature then it starts to rot
else if (this.maturity > 0){
this.maturity -= 5;
}
//once the fruit is completly rotten, then the agent reverts to its original state as a seedling
else {
this.next_life_stage = 'seedling';
this.maturiy = 0;
this.ripeness = 7;
}
}
}
// execute the next move you decided on
this.update_state = function() {
this.life_stage = this.next_life_stage;
}
this.draw = function(size) {
stroke(0);
noStroke();
if(this.life_stage === 'seedling'){
drawSeedlingState(size);
}
else if(this.life_stage === 'tree'){
drawTree(size);
}
else if(this.life_stage === 'fruit'){
drawFeijoa(size, this.maturity, this.ripeness);
}
}
}
/**
* draws the seedling state
* @param {Number} size - determines how big the seedling will be
*/
function drawSeedlingState(size){
//first create an array of raindrops
var raindrops = [];
for (var i = 0; i <= 32; i++) {
raindrops.push(new rainDrop(size));
}
//the animate the rain drops to simulate rain
for (var i = 32; i >= 0; i--) {
raindrops[i].move();
raindrops[i].draw();
if (raindrops[i].y >= size) {
raindrops[i].y = 0;
}
}
//draw a sun in the top right hand corder
fill(255,204,26);
arc(size, 0, size/2, size/2, 0+HALF_PI, PI);
//draw the grass at the bottom of the square
fill(51, 200, 25);
rect(0, size - size/16, size, size/16);
//finally, draw the seedling at the bottom of the square
//fill(128,0,0);
//ellipse(0 + size/2, size -size/12, size/8, size/8);
fill(128,0,0);
rectMode(CENTER);
rect(0 + size/2, size -size/12, size/32, size/8);
rectMode(CORNER);
fill(5, 205, 30);
translate(0 + size/2, size -size/6);
rotate(PI/4);
ellipse(size/32, 0-size/24, size/16, size/8);
rotate(PI+PI/2);
ellipse(size/32-size/16, 0-size/24, size/16, size/8);
}
/**
* raindrop object consisting of 3 internal parameters and 2 functions
* @param {Number} size - determines how big the raindrop will be
*/
function rainDrop(size) {
//set the size of the rain drop
this.size = size;
//set the x position of the rain drop
this.x = random((size/32), (size - size/32));
//set the y position of the rain drop
this.y = random((size/32), (size - size/32));
//the move function increase the y value of the rain drop
this.move = function() {
if(this.y < this.size){
this.y += random(3);
}
};
//the draw function draws the rain drop
this.draw = function() {
strokeWeight(0);
fill(86, 170, 255, 255);
ellipse(this.x, this.y, size/32, size/32);
};
}
/**
* draws a tree
* @param {Number} size - determines how big the tree will be
*/
function drawTree(size){
fill(5, 205, 30);
rect(0 + size/4, size - size/4, size/2, size/4);
triangle(0, size-size/8, size/2, size/4, size, size-size/8);
triangle(0+size/8, size-size/2, size/2, 0, size-size/8, size-size/2);
}
/**
* draws a feijoa
* @param {Number} size - determines how big the feijoa will be
* @param {Number} maturity - the 'G' value of the fill colour for the main shapes of the feijoa
* @param {Number} ripeness - the 'A' value of the fill colour for the main shapes of the feijoa
*/
function drawFeijoa(size, maturity = 205, ripeness = 255){
stroke(25,68,14);
strokeWeight(size*0.0234375);
fill(128, maturity, 0, ripeness);
triangle(size*0.421875, size*0.046875, size*0.484375, size*0.125, size*0.46875, size*0.03125);
triangle(size*0.531250, size*0.046875, size*0.500000, size*0.125, size*0.59375, size*0.06250);
ellipse(size*0.5, size*0.5, size*0.625, size*0.8046875);
noFill();
stroke(40,95,30);
arc(size*0.5, size*0.484375, size*0.562500, size*0.7812500, PI+HALF_PI, TWO_PI+HALF_PI*0.85);
stroke(25,68,14);
arc(size*0.5, size*0.500000, size*0.546875, size*0.8046875, PI+HALF_PI, TWO_PI-QUARTER_PI*1.2);
strokeWeight(0);
fill(18,62,11);
ellipse(size*0.625000, size*0.625000, size*0.03125);
ellipse(size*0.687500, size*0.562500, size*0.03125);
ellipse(size*0.656250, size*0.500000, size*0.03125);
ellipse(size*0.593750, size*0.718750, size*0.03125);
ellipse(size*0.656250, size*0.687500, size*0.03125);
ellipse(size*0.625000, size*0.656250, size*0.03125);
ellipse(size*0.531250, size*0.750000, size*0.03125);
fill(50,95,40);
ellipse(size*0.625000, size*0.546875, size*0.03125);
ellipse(size*0.562500, size*0.531250, size*0.03125);
ellipse(size*0.546875, size*0.562500, size*0.03125);
ellipse(size*0.593750, size*0.437500, size*0.03125);
ellipse(size*0.656250, size*0.468750, size*0.03125);
}
function Agent2() {
//the life stage of the agent
this.life_stage = 'seedling';
//maturity of the seedling and fruit - ranges from 0-205
this.maturity = 0.0;
this.next_maturity = 0.0;
//ripeness of the fruit - ranges from 7-255
this.ripeness = 7;
this.next_ripeness = 7;
//the amount of rainfall in a cell - ranges from 0-205
this.rainfall = 0.0;
this.next_rainfall = 0.0;
// setup is run when the agent is reset
// value is a number between 0 and 100
this.setup = function(value, agent_type) {
this.rainfall = value;
this.next_rainfall = this.rainfall;
this.agent_type = agent_type;
}
// this happens generally on mouse over
this.activate = function() {
this.rainfall = 100.0;
}
// decide on your next move based on neighbors (but don't do it yet)
this.step = function(neighbors) {
var todays_rainfall = 0;
var num_trees_nearby = 0;
for(var i=0; i<neighbors.length; i++) {
//if it has been raining in a neighboring agent then it will start raining in this agent
if(neighbors[i].agent.rainfall > todays_rainfall) {
todays_rainfall = neighbors[i].agent.rainfall;
}
//if the neighbor is a tree add it to the number of trees nearby
if(neighbors[i].agent.life_stage === 'tree'){
if(this.agent_type == 0) {
num_trees_nearby++;
}
//in this climate only keep track on the nubmber of trees nearby on the x axis
else if(this.agent_type && neighbors[i].y == 0){
num_trees_nearby++;
}
}
}
//the different agent types represent different type of climates
//in one climate it rains more than in the other
if(this.agent_type == 0) {
this.next_rainfall = 0.8 * todays_rainfall;
}
else {
this.next_rainfall = 0.6 * todays_rainfall;
}
//the rainfall should never be greater than 100
if(this.next_rainfall > 100) {
this.next_rainfall = 100;
}
//if there is very little rainfall
else if(this.next_rainfall < 1){
var will_it_rain = floor(random(1, 100));
//then there is 1% chance of a storm
if(will_it_rain < 2){
this.activate();
}
}
//if current life stage is a seedling
if(this.life_stage === 'seedling'){
this.next_life_stage = 'seedling';
//if the seedling has received enough rain to mature, it becomes a tree
if(this.maturity > 200){
this.next_life_stage = 'tree';
this.next_maturity = 205;
}
//otherwise it continues to mature
else {
this.next_maturity = this.maturity + this.next_rainfall/5;
}
}
//if current life stage is a tree
else if(this.life_stage === 'tree'){
this.next_life_stage = 'tree';
//if the agent_type is 1 and the number of trees nearby is greater than 1 or the number of trees nearby is greater than 3
if((num_trees_nearby > 1 && this.agent_type) || num_trees_nearby > 4){
//then the next life stage is fruit
this.next_life_stage = 'fruit';
}
}
//if current life stage is a fruit
else if(this.life_stage === 'fruit'){
this.next_life_stage = 'fruit';
//if the fruit is not ripe yet, increase the ripeness
if (this.ripeness < 255){
this.next_ripeness = this.ripeness + 8;
}
//if the fruit is ripe and also mature then it starts to rot
else if (this.maturity > 0){
this.next_maturity = this.maturity - 5;
}
//once the fruit is completly rotten, then the agent reverts to its original state as a seedling
else {
this.next_life_stage = 'seedling';
this.next_maturity = 0;
this.next_ripeness = 7;
}
}
}
// execute the next move you decided on
this.update_state = function() {
this.rainfall = this.next_rainfall;
this.life_stage = this.next_life_stage;
this.ripeness = this.next_ripeness;
this.maturity = this.next_maturity;
}
this.draw = function(size) {
var low, high = color(100, 100, 100);
//determine the background colour of the agent based on whether or not it is fruit or its agent type
if(this.life_stage === 'fruit'){
low = color(232,232,232);
}
else {
if(this.agent_type == 0) {
low = color(86, 170, 225);
}
else {
low = color(220, 122, 4);
}
}
var c = lerpColor(low, high, this.rainfall / 100.0);
strokeWeight(0);
//the rain effect only applies to seedlings
if(this.life_stage === 'seedling'){
fill(c);
}
else {
fill(low);
}
ellipse(size/2, size/2, size, size);
if(this.life_stage === 'seedling'){
drawSeedlingState(size, this.rainfall);
}
else if(this.life_stage === 'tree'){
drawTree(size);
}
else if(this.life_stage === 'fruit'){
drawFeijoa(size, this.maturity, this.ripeness);
}
}
}
/**
* draws the seedling state
* @param {Number} size - determines how big the seedling will be
*/
function drawSeedlingState(size, rainfall){
//first create an array of raindrops
var rainfall = floor(rainfall/4);
var raindrops = [];
if(rainfall > 1){
for (var i = 0; i <= rainfall; i++) {
raindrops.push(new rainDrop(size));
}
//the animate the rain drops to simulate rain
for (var i = rainfall; i >= 0; i--) {
raindrops[i].draw();
}
}
//finally, draw the seedling at the bottom of the square
fill(128,0,0);
rectMode(CENTER);
rect(0 + size/2, size -size/16, size/32, size/8);
rectMode(CORNER);
fill(5, 205, 30);
translate(0 + size/2, size -size/6);
rotate(PI/4);
ellipse(size/32, 0-size/24, size/16, size/8);
rotate(PI+PI/2);
ellipse(size/32-size/16, 0-size/24, size/16, size/8);
}
/**
* raindrop object consisting of 3 internal parameters and 2 functions
* @param {Number} size - determines how big the raindrop will be
*/
function rainDrop(size) {
//set the size of the rain drop
this.size = size;
//set the x position of the rain drop
this.x = random((size/32 * 6), (size - (size/32 * 6)));
//set the y position of the rain drop
this.y = random((size/32 * 6), (size - (size/32 * 6)));
//the draw function draws the rain drop
this.draw = function() {
strokeWeight(0);
fill(86, 170, 255, 255);
ellipse(this.x, this.y, size/32, size/32);
};
}
/**
* draws a tree
* @param {Number} size - determines how big the tree will be
*/
function drawTree(size){
fill(128,0,0);
rectMode(CENTER);
rect(0 + size/2, size-size/8, size/32, size/4);
rectMode(CORNER);
fill(5, 205, 30);
triangle(0+size*0.15, size-size*0.2, size/2, size/4, size-size*0.15, size-size*0.2);
triangle(0+size/4, size-size*0.5, size/2, 0+size*0.1, size-size/4, size-size*0.5);
}
/**
* draws a feijoa
* @param {Number} size - determines how big the feijoa will be
* @param {Number} maturity - the 'G' value of the fill colour for the main shapes of the feijoa
* @param {Number} ripeness - the 'A' value of the fill colour for the main shapes of the feijoa
*/
function drawFeijoa(size, maturity = 205, ripeness = 255){
stroke(25,68,14);
strokeWeight(size*0.0234375);
fill(128, maturity, 0, ripeness);
triangle(size*0.421875, size*0.046875, size*0.484375, size*0.125, size*0.46875, size*0.03125);
triangle(size*0.531250, size*0.046875, size*0.500000, size*0.125, size*0.59375, size*0.06250);
ellipse(size*0.5, size*0.5, size*0.625, size*0.8046875);
noFill();
stroke(40,95,30);
arc(size*0.5, size*0.484375, size*0.562500, size*0.7812500, PI+HALF_PI, TWO_PI+HALF_PI*0.85);
stroke(25,68,14);
arc(size*0.5, size*0.500000, size*0.546875, size*0.8046875, PI+HALF_PI, TWO_PI-QUARTER_PI*1.2);
strokeWeight(0);
fill(18,62,11);
ellipse(size*0.625000, size*0.625000, size*0.03125);
ellipse(size*0.687500, size*0.562500, size*0.03125);
ellipse(size*0.656250, size*0.500000, size*0.03125);
ellipse(size*0.593750, size*0.718750, size*0.03125);
ellipse(size*0.656250, size*0.687500, size*0.03125);
ellipse(size*0.625000, size*0.656250, size*0.03125);
ellipse(size*0.531250, size*0.750000, size*0.03125);
fill(50,95,40);
ellipse(size*0.625000, size*0.546875, size*0.03125);
ellipse(size*0.562500, size*0.531250, size*0.03125);
ellipse(size*0.546875, size*0.562500, size*0.03125);
ellipse(size*0.593750, size*0.437500, size*0.03125);
ellipse(size*0.656250, size*0.468750, size*0.03125);
}
//their are five phases used to describe the current state of nature
//the earth phase is a shorter phase that occurs in between each of the other phase
var phases_of_nature = [
['earth', 18],
['wood', 72],
['earth', 18],
['fire', 72],
['earth', 18],
['metal', 72],
['earth', 18],
['water', 72]
];
//the sun is located in the center of the canvas
//it changes colour in sync with the phases of nature
var sun_colours = {
'earth' : '#fbc02d',
'wood' : '#f9a825',
'fire' : '#f57f17',
'metal' : '#ffeb3b ',
'water' : '#fdd835'
}
//keeps track of which phase is the current state
var phase_pointer = 0;
//current phase
var current_phase = 'earth';
//days remaining in this phase
var days_remaining = 18;
//the five agent types are represented as follows
//these agent types can be created during their phase of nature
//there is an extra agent type 'sun' which is only generated on setup
var elements = [
'earth',
'metal',
'fire',
'wood',
'water'
];
//a JSON object containing arrays of three colours for each of the elements
var element_colours = {
'earth' : ['#a1887f', '#3e2723', '#6d4c41'],
'metal' : ['#e0e0e0', '#424242', '#757575'],
'fire' : ['#e57373', '#b71c1c', '#e53935'],
'wood' : ['#81c784', '#1b5e20', '#43a047'],
'water' : ['#64b5f6', '#0d47a1', '#1e88e5']
};
//if an agent collides with a particular neighbour its size will be increased
var generated_by = {
'metal' : 'earth', //metal is generated by earth
'water' : 'metal', //water is generated by metal
'wood' : 'water', //wood is generated by water
'fire' : 'wood', //fire is generated by wood
'earth' : 'fire' //earth is generated by fire
};
//if an agent collides with a particular neighbour it will be overcome by it and change to its state
var overcome_by = {
'earth' : 'wood', //earth is overcome by wood
'metal' : 'fire', //metal is overcome by fire
'water' : 'earth', //water is overcome by earth
'wood' : 'metal', //wood is overcome by metal
'fire' : 'water' //fire is overcome by water
};
function Agent3Preload() {
}
function Agent3() {
//max size determines how big an agent can be
this.max_size = 0;
//size_adjuster is the amount that the size of an agent will increase or decreae by when changing size
this.size_adjuster = 0;
//variable used to prevent the size from changing to easily
this.steps_between_size_change = 1;
//number_steps determines how many steps an agent will take before changing direction
this.number_steps = 0;
// setup is run when the agent is reset
// value is a number between 0 and 100
this.setup = function(value, agent_type, agent_size) {
//during setup the only agent type greater than 0 are setup
if(agent_type > 0){
//set the agent_type using the elements array
this.agent_type = elements[agent_type];
this.max_size = agent_size;
this._size = this.max_size/4;
this.size_adjuster = this.max_size/4;
}
//0 is not set up because instead an extra agent type 'sun' is created
//this agent type is the only truly static agent type
//it is not not affected by other agents, it does not move and it does not change size
else {
this.agent_type = 'sun';
this._size = agent_size * 2;
}
}
// this happens generally on mouse over
// this function is not used in this simulation
this.activate = function() {
}
// decide on your next move based on neighbors
this.step = function(neighbors, radius) {
//the sun is always static and not affected by its neighbours
if(this.agent_type == 'sun'){
return;
}
//there is a random chance that an agent will be reborn as the element of the current phase
var become_current_phase = random(0, 100);
//a small percentage - needs to be higher during the earth phase as it is shorter
var random_chance = 1.5 - (phases_of_nature[phase_pointer][1] /100);
//this is used to demonstrate that this element is the dominating energy during this phase
//it also ensures that none of the 5 different agent types will ever become extinct
if(become_current_phase <= random_chance){
print(current_phase);
this.agent_type = current_phase;
}
//calculate the direction to travel every 10 steps
this.number_steps = this.number_steps - 1;
if(this.number_steps < 0) {
this.number_steps = 30;
this.current_direction = this.calculateDirection(radius);
}
v = this.current_direction.copy();
//add a little bit of randomness to the movement
v.add(p5.Vector.random2D().mult(radius/2));
//gravity draws the element back to the center if it gets to close to the edges
var gravity = this.createGravity();
v.sub(gravity[0], gravity[1]);
for(var i=0; i<neighbors.length; i++) {
var npos = neighbors[i].pos;
var d = npos.mag();
//if there is a collision then the agent may change state or increase size depending on which agent it has collided with
if ((d > 0) && (d < radius + neighbors[i].radius)) {
//if the collision is with the sun then push the element away
if(neighbors[i].agent.agent_type == 'sun'){
var reverse_gravity = this.createReverseGravity();
v.sub(reverse_gravity[0], reverse_gravity[1]);
}
else {
// Calculate vector pointing away from neighbor
var move_away = npos.mult(-3);
move_away.normalize();
move_away.mult(d*.3); // Weight by distance
v.add(move_away);
//an agent will only increase in size if it is equal to the current_phase and collides with an agent that it is generated by
if(this.agent_type == current_phase && neighbors[i].agent.agent_type == generated_by[this.agent_type]){
this.steps_between_size_change -= 1;
//make sure the value for size is never higher than the max size
if(this._size < this.max_size && this.steps_between_size_change == 0) {
this._size += this.size_adjuster;
this.steps_between_size_change = 20;
}
}
//if an agent collides with an agent that it is overcome by
if(neighbors[i].agent.agent_type == overcome_by[this.agent_type]){
//the agent will change to a new agent if is not equal to the current_phase
if(this.agent_type != current_phase){
this.agent_type = overcome_by[this.agent_type];
}
//otherwise it will just decrease in size
else {
this.steps_between_size_change -= 1;
if(this._size > this.size_adjuster && this.steps_between_size_change == 0) {
this._size -= this.size_adjuster;
this.steps_between_size_change = 20;
}
}
}
}
}
}
return v;
}
this.draw = function(radius) {
var size = radius * 4;
if(this.agent_type == 'sun'){
strokeWeight(0);
fill(sun_colours[current_phase]);
hexagon(0, 0, size/4);
}
else {
this.drawElement(size);
}
}
/*
* function used to draw the three circlies that represent the element
* @param {Number} size - size of the outer circle
*/
this.drawElement = function(size) {
stroke(255);
strokeWeight(1);
fill(element_colours[this.agent_type][2]);
ellipse(0, 0, size, size);
strokeWeight(0);
fill(element_colours[this.agent_type][1]);
ellipse(0, 0, size*0.66, size*0.66);
strokeWeight(0);
fill(element_colours[this.agent_type][0]);
ellipse(0, 0, size*0.25, size*0.25);
}
/*
* function to calculate which direction an agent should travel
* the agents are always trying to travel anti-clockwise around the sun
* inspired by the movement functionality implemented here: http://bl.ocks.org/HenryLeungVuw/4af688077859644d566f6a9cb2dccad3/5e68663fd84288a41a2301a15410e76cc01e1f1c
* @param {Number} size - current size of the agent
* @return {Vector} - the direction the agent should travel
*/
this.calculateDirection = function(size){
var dirX = 480 - this._x;
var dirY = 250 - this._y;
var vX = 0;
var vY = 0;
var movement = size / 4;
//bottom right hand corner of the canvas
if(dirY >= 0 && dirX >= 0){
vX = -movement;
vY = movement;
}
//top left hand corner of the canvas
else if(dirY < 0 && dirX < 0){
vX = movement;
vY = -movement;
}
//bottom left hand corner of the canvas
else if(dirY >= 0 && dirX < 0){
vX = -movement;
vY = -movement;
}
//top right hand corner of the canvas
else if(dirY < 0 && dirX >= 0){
vX = movement;
vY = movement;
}
return createVector(vX, vY);
}
/*
* This function determines if an element is to close to edges of the solar system
* @return {Array} - an array of values that will be substrated from the vector of the agent
*/
this.createGravity = function(){
var glyphSize = parseInt(sizeSelector.value(), 10);
var rand = floor(random(1, glyphSize));
var radius = glyphSize / 2;
var min_x = radius + 1;
var min_y = radius + 1;
var max_x = int(canvasWidth - radius) - 1;
var max_y = int(canvasHeight - radius) -1;
if(this._y >= max_y){
return [-rand, rand];
}
else if(this._y <= min_y){
return [rand, -rand];
}
else if(this._x >= max_x){
return [rand, rand];
}
else if(this._x <= min_x){
return [-rand, -rand];
}
else {
return [0, 0];
}
}
/*
* This function determines which direction an element should move if it collides with the sun
* @return {Array} - an array of values that will be substrated from the vector of the agent
*/
this.createReverseGravity = function(){
var glyphSize = parseInt(sizeSelector.value(), 10);
var rand = floor(random(1, glyphSize));
var dirX = 480 - this._x;
var dirY = 250 - this._y;
var vector_values = [];
//bottom right hand corner of the canvas
if(dirY >= 0 && dirX >= 0){
vector_values = [rand*4, rand];
}
//top left hand corner of the canvas
else if(dirY < 0 && dirX < 0){
vector_values = [-rand*4, -rand];
}
//bottom left hand corner of the canvas
else if(dirY >= 0 && dirX < 0){
vector_values = [-rand, rand];
}
//top right hand corner of the canvas
else if(dirY < 0 && dirX >= 0){
vector_values = [rand, -rand];
}
return vector_values;
}
}
/*
* function to draw a hexagon shape
* adapted from: https://p5js.org/examples/form-regular-polygon.html
* not included in the above object as it is a function that should be available globally
* @param {Number} x - x-coordinate of the hexagon
* @param {Number} y - y-coordinate of the hexagon
* @param {Number} radius - radius of the hexagon
*/
function hexagon(x, y, radius) {
angleMode(RADIANS);
var angle = TWO_PI / 6;
beginShape();
for (var a = TWO_PI/12; a < TWO_PI + TWO_PI/12; a += angle) {
var sx = x + cos(a) * radius;
var sy = y + sin(a) * radius;
vertex(sx, sy);
}
endShape(CLOSE);
}
<head>
<script src="http://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.7/p5.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.7/addons/p5.dom.js"></script>
<script language="javascript" type="text/javascript" src=".purview_helper.js"></script>
<script language="javascript" type="text/javascript" src="agent3.js"></script>
<script language="javascript" type="text/javascript" src="sketch.js"></script>
<style>
body { padding: 0; margin: 0; }
.inner { position: absolute; }
#controls {
font: 300 12px "Helvetica Neue";
padding: 5;
margin: 5;
background: #f0f0f0;
opacity: 0.0;
-webkit-transition: opacity 0.2s ease;
-moz-transition: opacity 0.2s ease;
-o-transition: opacity 0.2s ease;
-ms-transition: opacity 0.2s ease;
}
#controls:hover { opacity: 0.9; }
</style>
</head>
<body style="background-color:white">
<div class="outer">
<div class="inner">
<div id="canvasContainer"></div>
</div>
<div class="inner" id="controls" height="500px">
<table>
<tr>
<td>World</td>
<td id="selector1Container"></td>
</tr>
<tr>
<td>Size</td>
<td id="selector2Container"></td>
</tr>
<tr>
<td>Speed</td>
<td id="selector3Container"></td>
</tr>
<tr>
<td></td>
<td id="playButtonContainer"></td>
</tr>
<tr>
<td></td>
<td id="clearButtonContainer"></td>
</tr>
<tr>
<td></td>
<td id="checkContainer"></td>
</tr>
</div>
</div>
</table>
</body>
{
"commits": [
{
"sha": "f1b3bc71cbbe794ac1d92c749e409141fccea134",
"name": "final"
},
{
"sha": "87dbe5e4e2d9dc1e1b59a2daf198d084e826b0c9",
"name": "result3"
},
{
"sha": "8da2b3ecb5cd61ed9ab7de3c7eedac88d72965db",
"name": "result2"
},
{
"sha": "edff2ba35335cd5d499cac39170a2299990d94d6",
"name": "result1"
},
{
"sha": "a2eafe38ad3a66338c66a0e3d63eaa05dcea5128",
"name": "sketch"
}
]
}
<head>
<script src="http://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.7/p5.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.7/addons/p5.dom.js"></script>
<script language="javascript" type="text/javascript" src=".purview_helper.js"></script>
<script language="javascript" type="text/javascript" src="sketch.js"></script>
<style>
.button, .match-number {
width: 108px;
}
</style>
</head>
<body style="background-color:white">
<div class="outer">
<div class="inner">
<div id="canvasContainer"></div>
</div>
</div>
</table>
</body>
var canvasWidth = 960;
var canvasHeight = 500;
var is_playing = false;
var show_oddball = false;
var modeSelector;
var sizeSelector;
var speedSelector;
var max_vals = [360, 100, 100];
var allAgents = [];
var numActiveAgents = 0;
var clearButton, randomButton, playButton, stepButton, stopButton;
var backgroundImage = null;
var agentLookupWidth = 1;
var agentLookupHeight = 1;
var agentLookupTable = [0];
var haveSeenMovement = false;
function preload() {
backgroundImage = loadImage("z_background.jpg");
// this is called for static assets your agents need
Agent3Preload();
}
function setup() {
frameRate(3);
// create the drawing canvas, save the canvas element
var main_canvas = createCanvas(canvasWidth, canvasHeight);
main_canvas.parent('canvasContainer');
modeSelector = createSelect();
modeSelector.option('grid');
modeSelector.option('hexgrid');
// modeSelector.option('vornoi');
// modeSelector.option('freestyle');
modeSelector.changed(gridTypeChanged);
modeSelector.value('hexgrid');
modeSelector.parent('selector1Container');
sizeSelector = createSelect();
sizeSelector.option('16');
sizeSelector.option('32');
sizeSelector.option('64');
sizeSelector.option('128');
sizeSelector.option('256');
sizeSelector.parent('selector2Container');
sizeSelector.value('32');
sizeSelector.changed(sizeChangedEvent);
speedSelector = createSelect();
speedSelector.option('1');
speedSelector.option('2');
speedSelector.option('5');
speedSelector.option('10');
speedSelector.option('24');
speedSelector.option('60');
speedSelector.parent('selector3Container');
speedSelector.value('60');
speedSelector.changed(speedChangedEvent);
stepButton = createButton('step');
stepButton.mousePressed(stepButtonPressedEvent);
stepButton.parent('playButtonContainer');
playButton = createButton('play');
playButton.mousePressed(playButtonPressedEvent);
playButton.parent('playButtonContainer');
// stopButton = createButton('stop');
// stopButton.mousePressed(stopButtonPressedEvent);
// stopButton.parent('playButtonContainer');
clearButton = createButton('reset');
clearButton.mousePressed(clearButtonPressedEvent);
clearButton.parent('clearButtonContainer');
randomButton = createButton('random');
randomButton.mousePressed(randomButtonPressedEvent);
randomButton.parent('clearButtonContainer');
// guideCheckbox = createCheckbox('', false);
// guideCheckbox.parent('checkContainer');
// guideCheckbox.changed(guideChangedEvent);
// setup lookup table from pixels
backgroundImage.loadPixels();
var p = backgroundImage.pixels;
agentLookupHeight = backgroundImage.height;
agentLookupWidth = backgroundImage.width;
agentLookupTable = new Array(agentLookupHeight);
for(var j=0; j<agentLookupHeight; j++) {
agentLookupTable[j] = new Array(agentLookupWidth);
for(var i=0; i<agentLookupWidth; i++) {
var ix = 4 * (j * agentLookupWidth + i);
if(p[ix] > 128 && p[ix+1] > 128 && p[ix+2] > 128) {
// white
agentLookupTable[j][i] = 0;
}
else if(p[ix] < 128 && p[ix+1] < 128 && p[ix+2] < 128) {
// black
agentLookupTable[j][i] = 1;
}
else if(p[ix] > p[ix+1] && p[ix] > p[ix+2] ) {
// red-ish
agentLookupTable[j][i] = 2;
}
else if(p[ix+1] > p[ix] && p[ix+1] > p[ix+2] ) {
// green-ish
agentLookupTable[j][i] = 3;
}
else {
agentLookupTable[j][i] = 4;
}
}
}
noLoop();
refreshGridData();
modeChangedEvent();
speedChangedEvent();
playButtonPressedEvent();
}
/*
function mouseClicked() {
if (mouseX > width/4) {
refreshGridData();
}
redraw();
}
*/
var numGridRows;
var numGridCols;
var gridValues; // row, col order
var gridOffsetX, gridOffsetY;
var gridSpacingX, gridSpacingY;
// Generate data for putting glyphs in a grid
function clamp(num, min, max) {
return Math.min(Math.max(num, min), max);
}
function getNewAgent() {
a = new Agent3();
return a;
}
function lookupAgentType(x, y, size) {
s2 = size/2;
x += s2;
y += s2;
if(x < 0 || y < 0 || x >= canvasWidth || y >= canvasHeight) {
print("ERROR");
return 0;
}
var ix = int(map(x, 0, canvasWidth, 0, agentLookupWidth));
var iy = int(map(y, 0, canvasHeight, 0, agentLookupHeight));
return agentLookupTable[iy][ix];
}
function refreshGridData() {
var mode = modeSelector.value();
var glyphSize = parseInt(sizeSelector.value(), 10);
if (mode == "hexgrid") {
if(glyphSize == 16) {
numGridCols = 58;
numGridRows = 33;
gridOffsetX = 20;
gridSpacingX = 16;
gridOffsetY = 1;
gridSpacingY = 15;
}
if(glyphSize == 32) {
numGridCols = 30;
numGridRows = 17;
gridOffsetX = 10;
gridSpacingX = 31;
gridOffsetY = 2;
gridSpacingY = 29;
}
else if(glyphSize == 64) {
numGridCols = 13;
numGridRows = 7;
gridOffsetX = 35;
gridSpacingX = 66;
gridOffsetY = 35;
gridSpacingY = 59;
}
else if(glyphSize == 128) {
numGridCols = 7;
numGridRows = 4;
gridOffsetX = 10;
gridSpacingX = 132;
gridOffsetY = 0;
gridSpacingY = 118;
}
else if(glyphSize == 256) {
numGridCols = 3;
numGridRows = 2;
gridOffsetX = 96;
gridSpacingX = 262;
gridOffsetY = 0;
gridSpacingY = 234;
}
}
else if(glyphSize == 128) {
numGridCols = 7;
numGridRows = 3;
gridOffsetX = 10;
gridSpacingX = 136;
gridOffsetY = 20;
gridSpacingY = 166;
}
else if(glyphSize == 256) {
numGridCols = 3;
numGridRows = 1;
gridOffsetX = 20;
gridSpacingX = 320;
gridOffsetY = 100;
gridSpacingY = 500;
}
else if(glyphSize == 64) {
numGridCols = 14;
numGridRows = 7;
gridOffsetX = 3;
gridSpacingX = 68;
gridOffsetY = 6;
gridSpacingY = 71;
}
else if(glyphSize == 32) {
numGridCols = 24;
numGridRows = 13;
gridOffsetX = 4;
gridSpacingX = 40;
gridOffsetY = 4;
gridSpacingY = 38;
}
else if(glyphSize == 16) {
numGridCols = 48;
numGridRows = 25;
gridOffsetX = 1;
gridSpacingX = 20;
gridOffsetY = 1;
gridSpacingY = 20;
}
// this updates the grid to account for center spacing
gridOffsetX += glyphSize/2;
gridOffsetY += glyphSize/2;
// determine active agents and reset
numActiveAgents = 0;
var hexOffset = (mode == "hexgrid");
gridValues = new Array(numGridRows);
for (var i=0; i<numGridRows; i++) {
var tweakedNumGridCols = numGridCols;
if (hexOffset && i%2 == 1) {
tweakedNumGridCols = numGridCols - 1;
}
gridValues[i] = new Array(tweakedNumGridCols);
for (var j=0; j<tweakedNumGridCols; j++) {
if(numActiveAgents >= allAgents.length) {
allAgents.push(getNewAgent());
}
gridValues[i][j] = allAgents[numActiveAgents];
numActiveAgents = numActiveAgents + 1;
}
}
// assign positions
for (var i=0; i<numGridRows; i++) {
var tweakedNumGridCols = numGridCols;
var offsetX = 0;
if (hexOffset && i%2 == 1) {
offsetX = gridSpacingX / 2;
tweakedNumGridCols = numGridCols - 1;
}
for (var j=0; j<tweakedNumGridCols; j++) {
gridValues[i][j]._x = gridOffsetX + j * gridSpacingX + offsetX;
gridValues[i][j]._y = gridOffsetY + i * gridSpacingY;
gridValues[i][j]._type = lookupAgentType(gridValues[i][j]._x, gridValues[i][j]._y, glyphSize);
if(gridValues[i][j]._type > 1) {
gridValues[i][j]._static = false;
gridValues[i][j]._size = glyphSize/4;
}
else {
gridValues[i][j]._static = true;
gridValues[i][j]._size = glyphSize/4;
}
}
}
// setup
for (var i=0; i<numActiveAgents; i++) {
var agent = allAgents[i];
agent.setup(0, agent._type, agent._size);
}
// compute neighbors
computeNeighbors(glyphSize);
}
function computeNeighbors(glyphSize) {
var mode = modeSelector.value();
var hexOffset = (mode == "hexgrid");
for (var i=0; i<numActiveAgents; i++) {
allAgents[i]._neighbors = []
}
var dist_thresh = 2.0;
if(hexOffset) {
dist_thresh = 1.4;
}
for (var i=0; i<numActiveAgents; i++) {
var agent = allAgents[i];
// agent.setup(0, agent._type);
for (var j=i+1; j<numActiveAgents; j++) {
var other = allAgents[j]
var d = dist(agent._x, agent._y, other._x, other._y) / glyphSize;
if (d < dist_thresh) {
var o1 = {
'distance': d,
'agent': other,
'radius': other._size,
'x': other._x - agent._x,
'y': other._y - agent._y,
'pos': createVector(other._x - agent._x, other._y - agent._y)
}
agent._neighbors.push(o1)
var o2 = {
'distance': d,
'agent': agent,
'radius': agent._size,
'x': agent._x - other._x,
'y': agent._y - other._y,
'pos': createVector(agent._x - other._x, agent._y - other._y)
}
other._neighbors.push(o2)
}
}
}
}
function speedChangedEvent() {
var speed = parseInt(speedSelector.value(), 10);
frameRate(speed)
}
function sizeChangedEvent() {
var mode = modeSelector.value();
refreshGridData();
redraw();
}
function guideChangedEvent() {
show_oddball = guideCheckbox.checked();
redraw();
}
function modeChangedEvent() {
var mode = modeSelector.value();
if (is_playing) {
playButton.elt.textContent = "pause";
stepButton.attribute('disabled','');
// stopButton.removeAttribute('disabled');
}
else {
playButton.elt.textContent = "play";
stepButton.removeAttribute('disabled');
// stopButton.attribute('disabled','');
}
if (mode === "drive") {
// disable the button
// button.attribute('disabled','');
// enable the size selector
sizeSelector.removeAttribute('disabled');
}
else {
// enable the button
// button.removeAttribute('disabled');
// enable the size selector
// sizeSelector.removeAttribute('disabled');
// refresh data
// refreshGridData();
}
if (mode === "hexgrid") {
// refresh data
// refreshGridData();
}
redraw();
}
function gridTypeChanged() {
modeChangedEvent();
refreshGridData();
redraw();
}
function clearButtonPressedEvent() {
refreshGridData();
for(var i=0; i<numActiveAgents; i++) {
var agent = allAgents[i];
agent.setup(0, agent._type, agent._size);
}
redraw();
}
function randomButtonPressedEvent() {
// refreshGridData();
for(var i=0; i<numActiveAgents; i++) {
var agent = allAgents[i];
agent.setup(random(100), agent._type, agent._size);
}
redraw();
}
function playButtonPressedEvent() {
if(is_playing) {
is_playing = false
noLoop();
}
else {
is_playing = true;
loop();
}
modeChangedEvent()
// refreshGridData();
redraw();
}
function stepButtonPressedEvent() {
is_playing = true;
// refreshGridData();
redraw();
is_playing = false;
}
function stopButtonPressedEvent() {
// refreshGridData();
redraw();
}
var colorBack = "rgb(0, 0, 0)"
function highlightGlyph(glyphSize) {
halfSize = glyphSize / 2.0;
stroke(0, 0, 255, 128);
noFill();
strokeWeight(4);
ellipse(halfSize, halfSize, glyphSize+4);
fill(0);
strokeWeight(1);
}
function drawGrid() {
var glyphSize = parseInt(sizeSelector.value(), 10);
background(colorBack);
for (var i=0; i<numActiveAgents; i++) {
resetMatrix();
agent = allAgents[i];
translate(agent._x, agent._y);
agent.draw(agent._size);
resetMatrix();
if (show_oddball) {
translate(agent._x, agent._y);
highlightGlyph(glyphSize)
}
}
}
function clamp(num, min, max) {
return num <= min ? min : num >= max ? max : num;
}
function stepGrid() {
var glyphSize = parseInt(sizeSelector.value(), 10);
var radius = glyphSize / 2;
//some small adjustments made here to keep the agents completly within the canvas
var min_x = radius + 1;
var min_y = radius + 1;
var max_x = int(canvasWidth - radius) - 1;
var max_y = int(canvasHeight - radius) - 1;
var updatedAgents = new Array(numActiveAgents);
for (var i=0; i<numActiveAgents; i++) {
// make a shallow copy of the agent
agent = allAgents[i];
var clone = Object.assign({}, agent);
agent._new_me = clone;
var movement = clone.step(clone._neighbors, clone._size);
if(typeof movement !== 'undefined') {
haveSeenMovement = true;
var new_x = clone._x + movement.x;
var new_y = clone._y + movement.y;
clone._x = clamp(new_x, min_x, max_x);
clone._y = clamp(new_y, min_y, max_y);
}
updatedAgents[i] = clone;
}
for (var i=0; i<numActiveAgents; i++) {
allAgents[i] = updatedAgents[i];
}
if(haveSeenMovement) {
// copy new version of neighbors
computeNeighbors(glyphSize);
}
else {
for (var i=0; i<numActiveAgents; i++) {
agent = allAgents[i];
var old_neighbors = agent._neighbors;
for(var j=0; j<old_neighbors.length; j++) {
if ('_new_me' in old_neighbors[j].agent) {
agent._neighbors[j].agent = agent._neighbors[j].agent._new_me;
}
}
}
// weakly check optimization assertion (not a memory leak)
for (var i=0; i<numActiveAgents; i++) {
if ('_new_me' in allAgents[i]) {
print("you flubbed the _new_me setup");
}
}
}
//at the end of the step, calculate the current phase and determine whether or not it is time to change
if(days_remaining > 0){
days_remaining--;
}
else {
if(phase_pointer < 7){
phase_pointer++;
current_phase = phases_of_nature[phase_pointer][0];
days_remaining = phases_of_nature[phase_pointer][1];
}
else {
phase_pointer = 0;
current_phase = phases_of_nature[phase_pointer][0];
days_remaining = phases_of_nature[phase_pointer][1];
}
}
}
function activateGrid(x, y) {
var glyphSize = parseInt(sizeSelector.value(), 10);
for (var i=0; i<numActiveAgents; i++) {
agent = allAgents[i];
if( (agent._x <= x) && (agent._x + glyphSize > x) &&
(agent._y <= y) && (agent._y + glyphSize > y) ) {
agent.activate();
}
}
}
function mouseClicked () {
activateGrid(mouseX, mouseY);
drawGrid();
}
function draw () {
var mode = modeSelector.value();
// first do all steps
if (is_playing) {
stepGrid();
}
// then do activate
activateGrid(mouseX, mouseY);
// the do all draws
drawGrid();
resetMatrix();
}
function keyTyped() {
if (key == '!') {
saveBlocksImages();
}
else if (key == '@') {
saveBlocksImages(true);
}
else if (key == ' ') {
playButtonPressedEvent();
}
else if (key == 's') {
var old_value = guideCheckbox.checked();
guideCheckbox.checked(!old_value);
guideChangedEvent();
}
else if (key == '1') {
sizeSelector.value('16');
sizeChangedEvent()
}
else if (key == '2') {
sizeSelector.value('32');
sizeChangedEvent()
}
else if (key == '3') {
sizeSelector.value('64');
sizeChangedEvent()
}
else if (key == '4') {
sizeSelector.value('128');
sizeChangedEvent()
}
else if (key == '5') {
sizeSelector.value('256');
sizeChangedEvent()
}
else if (key == 'd') {
modeSelector.value('drive');
modeChangedEvent()
}
else if (key == 'g') {
modeSelector.value('grid');
gridTypeChanged()
}
else if (key == 'r') {
modeSelector.value('random');
modeChangedEvent()
}
else if (key == 'h') {
modeSelector.value('hexgrid');
gridTypeChanged()
}
}
function keyPressed() {
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment