Charachromism

“Chara” is intended to be short for “character” or “characteristics”. “Chromism” is a chemistry term that stands for change in color.

This was intended to be a simulation of an over-simplified version of my observations of human group behavior.
The color of each Dot represents its core personality. In addition, each also has its own set of characteristics that influence how the Dot approaches with and is influenced by other Dots.

The simulation is not working as I intend it to yet. There are a few characteristics that I haven’t implemented yet. This is a work in progress. I would like to put the Processing program on here, but it does not run when I upload it onto OpenProcessing and I do not know why.

ArrayList allFlocks;
ArrayList allDots;
int nDots;
 
void setup() {
  size(400, 400);
  colorMode(HSB, 100);
  noStroke();
 
  nDots = 50;
 
  allFlocks = new ArrayList();
 
  allDots = new ArrayList();
  for (int i=0; i1.0) {
      ithDot.shade+=(shadeDiff*ithDot.agreeableness/100.0);
    }
 
    if (iFlock.stdev>(40.0*ithDot.openness)) {
      iFlock.removeDot(ithDot);
      if (iFlock.flockSize()==0) {
        allFlocks.remove(iFlock);
      }
      Flock fnew = new Flock();
      fnew.addDot(ithDot);
      ithDot.flock = fnew;
    }
    else {
      for (int j=0; j ithDot.radius && dh group; //prioritized members of group this Dot associates with
  //The following are the Dot's characteristics
  float agreeableness; //probability of going w/ flow of group
  float extraversion; //probability of associating with other Dots
  float openness; //probability of being interested in a different color
  float spontaneity; //probability of randomly going off somewhere
   
  Flock flock;
 
  Dot (float x, float y, float s, float rad) {
    position = new PVector(x, y);
 
    float angle = random(TWO_PI);
    velocity = new PVector(cos(angle), sin(angle));
     
    acceleration = new PVector(0, 0);
 
    shade = s;
     
    radius = rad;
 
    maxspeed = 1.0;
    maxforce = 0.01;
 
    group = new ArrayList();
    flock = new Flock();
    flock.addDot(this);
 
    agreeableness = random(0, 1.0);
    extraversion = random(0, 1.0);
    openness = random(0, 1.0);
    spontaneity = random(0, 1.0);
     
//    println(str(shade)+"   "+str(openness));
  }
 
  float checkCompatibility (float s) {
    float lower = min(s, shade);
    float higher = max(s, shade);
    float shadeDist = min(higher-lower,(100-higher)+lower);
    float distRatio = abs(shadeDist)/100;
    return distRatio;
  }
   
  void updateFlock(Flock f) {
    flock = f;
  }
 
  void run(ArrayList dots) {
    flock(dots);
    update();
    handleBoundaries();
    render();
  }
 
  void handleBoundaries() {
    if (position.x > width+radius ) position.x -= width;
    if (position.x < 0-radius     ) position.x += width;
    if (position.y > height+radius) position.y -= height;
    if (position.y < 0-radius     ) position.y += height;
  }
 
  void applyForce (PVector force) {
    acceleration.add(force);
  }
 
  //From Flocking by Daniel Shiffman
  //http://processing.org/examples/flocking.html
  void flock(ArrayList dots) {
    PVector sep = separate(allDots);
    PVector ali = align(dots);
    PVector coh = cohesion(dots);
    sep.mult(1.5);
    coh.mult(1.0);
    ali.mult(1.0);
 
    applyForce(sep);
    applyForce(coh);
    applyForce(ali);
  }
 
  // Method to update position
  void update() {
    // Update velocity
    velocity.add(acceleration);
    // Limit speed
    velocity.limit(maxspeed);
    position.add(velocity);
    // Reset accelertion to 0 each cycle
    acceleration.mult(0);
  }
 
  // A method that calculates and applies a steering force towards a target
  // STEER = DESIRED MINUS VELOCITY
  PVector seek(PVector target) {
    PVector desired = PVector.sub(target, position);  // A vector pointing from the position to the target
    // Scale to maximum speed
    desired.normalize();
    desired.mult(maxspeed);
 
    // Steering = Desired minus Velocity
    PVector steer = PVector.sub(desired, velocity);
    steer.limit(maxforce);  // Limit to maximum steering force
    return steer;
  }
 
  // Separation
  // Method checks for nearby dots and steers away
  PVector separate (ArrayList dots) {
    float desiredseparation = 15.0f;
    PVector steer = new PVector(0, 0, 0);
    int count = 0;
    // For every dot in the system, check if it's too close
    for (Dot other : dots) {
      float d = PVector.dist(position, other.position);
      // If the distance is greater than 0 and less than an arbitrary amount (0 when you are yourself)
      if ((d > 0) && (d < desiredseparation)) {
        // Calculate vector pointing away from neighbor
        PVector diff = PVector.sub(position, other.position);
        diff.normalize();
        diff.div(d);        // Weight by distance
        steer.add(diff);
        count++;            // Keep track of how many
      }
    }
    // Average -- divide by how many
    if (count > 0) {
      steer.div((float)count);
    }
 
    // As long as the vector is greater than 0
    if (steer.mag() > 0) {
      // First two lines of code below could be condensed with new PVector setMag() method
      // Not using this method until Processing.js catches up
      // steer.setMag(maxspeed);
 
      // Implement Reynolds: Steering = Desired - Velocity
      steer.normalize();
      steer.mult(maxspeed);
      steer.sub(velocity);
      steer.limit(maxforce);
    }
    return steer;
  }
 
  // Alignment
  // For every nearby dot in the system, calculate the average velocity
  PVector align (ArrayList dots) {
    float neighbordist = 50;
    PVector sum = new PVector(0, 0);
    int count = 0;
    for (Dot other : dots) {
      float d = PVector.dist(position, other.position);
      if ((d > 0) && (d < neighbordist)) {
        sum.add(other.velocity);
        count++;
      }
    }
    if (count > 0) {
      sum.div((float)count);
      // First two lines of code below could be condensed with new PVector setMag() method
      // Not using this method until Processing.js catches up
      // sum.setMag(maxspeed);
 
      // Implement Reynolds: Steering = Desired - Velocity
      sum.normalize();
      sum.mult(maxspeed);
      PVector steer = PVector.sub(sum, velocity);
      steer.limit(maxforce);
      return steer;
    }
    else {
      return new PVector(0, 0);
    }
  }
 
  // Cohesion
  // For the average position (i.e. center) of all nearby dots, calculate steering vector towards that position
  PVector cohesion (ArrayList dots) {
    float neighbordist = 50;
    PVector sum = new PVector(0, 0);   // Start with empty vector to accumulate all positions
    int count = 0;
    for (Dot other : dots) {
      float d = PVector.dist(position, other.position);
      if ((d > 0) && (d < neighbordist)) {
        sum.add(other.position); // Add position
        count++;
      }
    }
    if (count > 0) {
      sum.div(count);
      return seek(sum);  // Steer towards the position
    }
    else {
      return new PVector(0, 0);
    }
  }
 
  void render() {
    fill(shade,100,100);
    ellipse(position.x, position.y, radius, radius);
  }
}
 
 
class Flock {
  ArrayList dots;
  float avgShade;
  float pcx;
  float pcy;
  float stdev;
   
  Flock() {
    dots = new ArrayList();
    avgShade = 0;
    pcx = 0;
    pcy = 0;
    stdev = 0;
    allFlocks.add(this);
  }
   
  void updateInfo(){
    float newx = 0;
    float newy = 0;
    int n = dots.size();
    float tempsum = 0;
    float totalShade = avgShade*n;
    for (Dot d: dots) {
      PVector pos = d.position;
      newx+=pos.x;
      newy+=pos.y;
       
      tempsum+=pow((totalShade-d.shade),2);
    }
     
    pcx = newx/dots.size();
    pcy = newy/dots.size();
     
    stdev = sqrt(tempsum/n);
  }
   
  void addDot(Dot d) {
    //Using previous numbers to calculate new avgs for runtime
    int n0 = dots.size();
    float totShade0 = avgShade*n0;
    int n = n0+1;
    float totShade = totShade0+d.shade;
    //Update the avg
    avgShade = totShade/n;
     
    d.updateFlock(this);
    dots.add(d);
  }
   
  void removeDot(Dot d) {
    //Using previous numbers to calculate new avgs for runtime
    int n0 = dots.size();
    float totShade0 = avgShade*n0;
    int n = n0-1;
    float totShade = totShade0-d.shade;
    //Update the avg
    avgShade = totShade/n;
     
    dots.remove(d);
  }
   
  int flockSize() {
    return dots.size();
  }
   
  void run() {
    for (Dot d: dots) {
      d.run(dots);
    }
  }
}

Portrait(s) in a Projected Creature

Nervous from Chloe Chia on Vimeo.

In the rush of things, I seem to have forgotten a few things. 1) The ability for art to elegantly express that which is hard to express, 2) the ability for art in catharsis, and 3) reaching out to people when in need of help.

WP_001713

I originally had numerous separate ideas for the assignments, but after numerous iterations and talk of being ‘poetic’, I realized that this creature that I made–originally intended to be a “live stress ball”–could have so much more meaning when placed into context. Especially if that context is my own studio in the Design school. Lately, I have been feeling very nervous in general about all of my classes, ever so precariously keeping the balance between them, outside activities, and mental states. The stress of it can be overwhelming, and leave one feeling very trapped as I do now.

WP_001715WP_001714

But in the process of making the video, and watching my own creature almost ‘come to terms’ with his confines, I can’t help but wonder whether or not such stress and pressure that I feel is merely an artificial boundary I place upon myself. It is up to me to figure out, given the limitations upon my skills and my time, what am I capable of doing, rather than focusing just on the limits and failures.

WP_001718

This is definitely the same sort of thinking with which I approached these assignments, keeping it as simple as possible, and working with the code that I’m most comfortable with. On the programming end, there are still many things I would like to fix later on as I get more and more fluent in Processing. One of those things includes figuring out how to get the creature attracted to the mouse, since at the moment a mouse press only activates a different gravity vector (which, I admit, I modified throughout the process of filming). I couldn’t quite figure out how to recall each node that creates the spring skeleton of the creature…

WP_001717

Unfortunately Javascript mode doesn’t seem to like my sketch and refuses to run in the OpenProcessing applet… Will have to figure out how to work that kink.

 

Buzz – Slurp

I began this project with a simple question in mind, how could I simulate a living creature? I thought about making something that would expand and deflate to simulate breathing. The simplest thing was to plug some eyes onto a shape, as Golan pointed out to me.By making it blink once in a while, the object becomes alive. My thoughts wandered and eventually landed on food. Creatures all need to eat right? So I started to formulate a critter that would devour another critter. I wanted to make something approachable, entertaining, and different from my previous projects.

After some quick sketches, I decided to create a baby chameleon-like creature, named Camel.

camel_2

camel_3

camel_4

camel1

I wanted to give my creature an environment where he could live, but it would have to be contained enough so he wouldn’t escape. The first thought that came into mind was just to make a simple boxed out area on the canvas so he wouldn’t be able to step out of the border. Simple enough right? However, I felt like that didn’t depict the life of a chameleon. A chameleon is a slow careful creature that spends most of its life up in the tree tops, catching bugs. I thought that this type easy-going lifestyle needed a fluid shape that would represent something soft, without extreme changes.

Furthermore, I wanted to describe a cycle in life. When the fly would buzz around the chameleon, within a certain range of Camel’s vision, he would reach out for the fly with his tongue. But Camel is still a baby, so sometimes the fly would get away when it twitches violently enough. The viewer can also chose to help out Camel catch the fly. The fly naturally wants to run away from anything coming towards it, so if you push scare it in the right direction, Camel will be able to eat it.

 

Keyfleas

The Keyfleas live on a two-dimensional flatland. They travel as a flock, over key mountains and through aluminum valleys. They avoid touching letterforms, since they suspect that the symbols are of some evil origin. On occasion, a hostile tentacle invades the flatland and disturbs its inhabitants.

Although I had several ideas for contexts in which an augmented projection could exist, most of them amounted to arbitrary particles careening across a surface. No poetry, no narrative. So instead of an architectural surface as originally planned, I project on an Apple Keyboard. My reasons for this are both practical and conceptual. The keys are clean and white, and the Pico projector can attach via Manfotto Magic Arm to a nearby table. This addresses the constraints of a low powered projector, as well as issues relating to variable lighting and surface conditions. My solution for key calibration was as follows: key-shaped boundaries are placed in the Box2D world using the mouse, and then the key is pressed in order to map that body to its corresponding key. This calibration process can be seen at the end of the video.

But these are only technical considerations; more important was choosing a context in which a narrative – albeit a simple one – could emerge. The suggestion that there are parasitic entities living in our devices is an interesting an unsettling one. An obvious inspiration for this project was Chris Sugrue’s “Delicate Boundaries”, where light bugs crawl out of the screen and onto the viewer’s hand.

A project which explores the delicate boundary between screen space and physical space


An improved Keyfleas might develop creatures with more character than mere filled ellipses (see Delicate Boundaries above). Or the shapes might pulsate and respond to keystrokes in a more intelligent manner than they currently do.

img003

Penny Door

There’s a little door in Doherty that can only be opened with the use of a coin. Coins clank off the sides of the door and each other, giving passerbys hints as to how to get in. Originally, I wanted to do a double projection that had glowing particles slipping in and out of the door, but that would’ve required multiple projectors + connecting multiple sketches together via osc, and I didn’t have the time to work it all out. I ended up having projection issues anyways–the projector I was using was too small and too weak to project onto the space!

I’d love to do more projection mapping work, perhaps next time with a little pico projector + RPi combo. I found it’s ridiculously difficult to line up the projectors, even with Keystone–I’d like to try my hand at computer vision next time.

import ddf.minim.spi.*;
import ddf.minim.signals.*;
import ddf.minim.*;
import ddf.minim.analysis.*;
import ddf.minim.ugens.*;
import ddf.minim.effects.*;

import pbox2d.*;
import org.jbox2d.collision.shapes.*;
import org.jbox2d.common.*;
import org.jbox2d.dynamics.*;
import org.jbox2d.dynamics.contacts.*;
import org.jbox2d.dynamics.joints.*;
import org.jbox2d.collision.shapes.Shape;



PImage penny;

Minim minim;
AudioSample clang;
AudioSample bigClang;

//door size
float door = 60.5 * 5 * 1.5;
float lastHit;
boolean caliDoor;

//box2D world
PBox2D box2d;

//stuff
ArrayList movers;
Boundary[] walls = new Boundary[4];

import deadpixel.keystone.*;
Keystone ks;
CornerPinSurface surface;
PGraphics offscreen;

void setup() {
  size(640*2, 360*2, P3D);
  ks = new Keystone(this);
  surface = ks.createCornerPinSurface(int(640*1.5), int(360*1.5), 20);
  offscreen = createGraphics(int(640*1.5), int(360*1.5), P3D);
  smooth();

  // http://en.wikipedia.org/wiki/Penny_(United_States_coin)
  penny = loadImage("2010_cent_obverse.png"); 

  minim = new Minim(this);
  // http://www.freesound.org/people/timgormly/sounds/170958/
  clang = minim.loadSample("clang.wav", 512);
  // http://www.freesound.org/people/DJ%20Chronos/sounds/123587/
  bigClang = minim.loadSample("loud_clang.aiff", 512);


  box2d = new PBox2D(this);
  box2d.createWorld();
  box2d.listenForCollisions();
  // No global gravity force
  box2d.setGravity(0, -2);

  movers = new ArrayList();
  for (int i = 0; i < 8; i++) {
    movers.add(new Mover(random(30, 60), offscreen.width/2, offscreen.height/2));
  }
  float cx = offscreen.width/2;
  float cy = offscreen.height/2;
  walls[0] = new Boundary((cx - door/2), cy, 1, offscreen.height);
  walls[1] = new Boundary(cx + door/2, cy, 1, offscreen.height);
  walls[2] = new Boundary(cx, cy - door/2, offscreen.width, 1);
  walls[3] = new Boundary(cx, cy + door/2, offscreen.width, 1);
}

void draw() {

  PVector surfaceMouse = surface.getTransformedMouse();
  offscreen.beginDraw();
  offscreen.background(0);

  // We must always step through time!
  box2d.step();

  for (Mover m : movers) {
    m.display();
  }
  for (int i = 0; i < 4; i++) {
    walls[i].display();
  }

  if (caliDoor == true) {
    offscreen.noFill();
    offscreen.strokeWeight(3);
    offscreen.stroke(255);
    offscreen.rect(width/2, height/2, door, door);
  } else {offscreen.stroke(0);}
  offscreen.endDraw();
  background(0);
  surface.render(offscreen);
}

// Collision event functions!
void beginContact(Contact cp) {

  clang.trigger();
}
// Objects stop touching each other
void endContact(Contact cp) {
}
void keyPressed() {
  switch(key) {
  case 'c':
    // enter/leave calibration mode, where surfaces can be warped 
    // and moved
    ks.toggleCalibration();
    if (caliDoor == false) {
      caliDoor = true;
    } 
    else {
      caliDoor = false;
    }
    break;

  case 'l':
    // loads the saved layout
    ks.load();
    break;

  case 's':
    // saves the layout
    ks.save();
    break;
  }
}

// The Nature of Code
// 
// Spring 2012
// PBox2D example

// A fixed boundary class

class Boundary {

  // A boundary is a simple rectangle with x,y,width,and height
  float x;
  float y;
  float w;
  float h;
  
  // But we also have to make a body for box2d to know about it
  Body b;

  Boundary(float x_,float y_, float w_, float h_) {
    x = x_;
    y = y_;
    w = w_;
    h = h_;

    // Define the polygon
    PolygonShape sd = new PolygonShape();
    // Figure out the box2d coordinates
    float box2dW = box2d.scalarPixelsToWorld(w/2);
    float box2dH = box2d.scalarPixelsToWorld(h/2);
    // We're just a box
    sd.setAsBox(box2dW, box2dH);


    // Create the body
    BodyDef bd = new BodyDef();
    bd.type = BodyType.STATIC;
    bd.position.set(box2d.coordPixelsToWorld(x,y));
    b = box2d.createBody(bd);
    
    // Attached the shape to the body using a Fixture
    b.createFixture(sd,1);
    
    b.setUserData(this);
  }

  // Draw the boundary, if it were at an angle we'd have to do something fancier
  void display() {
    fill(0);
    stroke(0);
    rectMode(CENTER);
    offscreen.rect(x,y,w,h);
  }

}

// The Nature of Code
// 
// Spring 2011
// PBox2D example

// Showing how to use applyForce() with box2d

class Mover {

  // We need to keep track of a Body and a radius
  Body body;
  float r;

  Mover(float r_, float x, float y) {
    r = r_;
    // Define a body
    BodyDef bd = new BodyDef();
    bd.type = BodyType.DYNAMIC;

    // Set its position
    bd.position = box2d.coordPixelsToWorld(x, y);
    body = box2d.world.createBody(bd);

    // Make the body's shape a circle
    CircleShape cs = new CircleShape();
    cs.m_radius = box2d.scalarPixelsToWorld(r);

    // Define a fixture
    FixtureDef fd = new FixtureDef();
    fd.shape = cs;
    // Parameters that affect physics
    fd.density = 0.8;
    fd.friction = 0.3;
    fd.restitution = 1.1;

    body.createFixture(fd);

    body.setLinearVelocity(new Vec2(random(-5, 5), random(-5, -5)));
    body.setAngularVelocity(random(-1, 1));
  }

  void applyForce(Vec2 v) {
    body.applyForce(v, body.getWorldCenter());
  }


  void display() {
    // We look at each body and get its screen position
    Vec2 pos = box2d.getBodyPixelCoord(body);
    // Get its angle of rotation
    float a = body.getAngle();
    offscreen.pushMatrix();
    offscreen.translate(pos.x, pos.y);
    offscreen.rotate(a);
    offscreen.image(penny,-r,-r,r*2, r*2);
    offscreen.popMatrix();
  }
}

The Wind Walker

The Wind Walker likes to use his head to feel for subtle variations in wind currents. He moves if he feels uncomfortable or bored.

Play with the Wind Walker on OpenProcessing (requires Java)

Behavior is more important than visual realism in creating the illusion of life. We observe this in Karl Sims’ “Evolved Virtual Creatures”, a simulation in which evolved box creatures interact with their environment in surprising and often humorous ways.

With this principle in mind, I sought to invent a charming creature with lifelike mannerisms. I drew inspiration from two sources: the dutch artist Theo Jansen, and the Kikkerland line of Wind Up Toys.

A wind-powered Strandbeest (Dutch: strand = beach) roams a beach A charming toy that teaches children about the perils of the adult world

I wrote a custom spring system based on Hooke’s Law to control his limbs, and the sketch runs using the P3D renderer. It is interactive in a limited sense – if one clicks, the Wind Walker turns to face the mouse.

img001 Preliminary sketches with greasy fingers

Lil Nippers

Unfortunately, this doesn’t look nearly as good in tiny youtube format, as it’s actually 1000+ pixels wide. The Macs in the clusters are huge and I wanted to make a thing that takes up most, if not all of the space. The nippers are pretty simple in nature: you feed them by typing on your keyboard, and after they eat a certain amount they will explode and become two tiny nippers. If there’s no food left for them to eat, their will to leave dissipates and they slowly move to a stop. Poor little nippers!

Originally, I wanted to assign more significance to the act of typing–there’s a residual element of that left over as the most frequent letters found in the English language (e, t, and a) give the nippers more energy than the least common (z, q, x). This was easily cribbed from Wikipedia, lots of people have done research into this and little kids use it to break each other’s substitution ciphers. As it stands, it’s more fun to smash keys and watch the nippers run around.

Were I to have more time to work on this, I would’ve loved to add a way for the nippers to slowly die. They each have their own different speeds, and when you run the program you’ll sometimes notice one brutally beating the competition, picking up food left and right and leaving slow, hungry nippers in its dust. I’d like to have them slow to a stop and begin to shrink if they haven’t eaten in a certain amount of time, reminding us that the circle of life involves stone-cold competition.


int zoom = 400;
PImage lLeg;
PImage rLeg;
PImage body;

//---GLOBAL COLORS---
color green = color(163, 169, 72);
color yellow = color(237, 185, 46);
color orange = color(248, 89, 49);
color red = color(206, 24, 54);
color blue = color(0, 153, 137);

//---FOOD STUFF---
ArrayList foods;

//---BUG STUFF---
ArrayList bugs;

//for adding bugs
ArrayList bugCoords;
int queue;

//for bugs eating foods
int distDex;

void setup() {
size(1800+zoom, 300);
noStroke();
smooth();

foods = new ArrayList();

bugs = new ArrayList();
bugs.add(new Bug(random(width-400), random(height*.75, height)));

bugCoords = new ArrayList();

rLeg = loadImage("rightleg.png");
lLeg = loadImage("leftleg.png");
body = loadImage("body.png");

}

void draw() {
background(230);
fill(255);
Bug zoomy = bugs.get(0);
pushMatrix();
translate(width-height-50+cos(zoomy.xpos/2), -height/4);
pushMatrix();
translate(height/3+25,height-23);
image(lLeg, -18, 3*sin(zoomy.xpos),height/6,height/6);
image(rLeg, 18, 3*cos(zoomy.xpos), height/6, height/6);
popMatrix();
image(body, 0, 0, height, height);
popMatrix();
rect(0, 0, width-399, height);
fill(230);
rect(0, height*.75, width-400, height);

for (Food f : foods) {
f.display();
}

for (Bug b : bugs) {

//get the closest food
float leastDist = -1;
float tempDist;
if (foods.size() > 0) {
for (int i = 0; i < foods.size(); i++) { Food g = foods.get(i); if (leastDist < 0) { leastDist = dist(b.xpos, b.ypos, g.x, g.y); distDex = i; } tempDist = dist(b.xpos, b.ypos, g.x, g.y); if (tempDist < leastDist) { distDex = i; leastDist = tempDist; } } } if (foods.size() > 0) {
Food goal = foods.get(distDex);
b.id = distDex;
b.seek(goal.x, goal.y);
}

if (foods.size() < 1) { b.vx = lerp(b.vx, 0, .001); b.vy = lerp(b.vy, 0, .001); } if ((dist(b.xpos, b.ypos, b.goalx, b.goaly) < 3) && (foods.size() > 0)) {
Food g = foods.get(b.id);
b.eat(g.priority);
foods.remove(b.id);

b.vx = lerp(b.vx, 0, .001);
b.vy = lerp(b.vy, 0, .001);
}

b.size = lerp(b.size, b.desiredSize, .1);

if (b.isMature() == true) {
b.desiredSize = 0.05;
bugCoords.add(b.xpos);
bugCoords.add(b.ypos);
queue += 1;
}

b.update();
b.display();
}

// safely add bugs
if (queue > 0) {
for (int i = 0; i < queue; i++) { float x = bugCoords.get(i); float y = bugCoords.get(i+1); bugs.add(new Bug(x+5, y)); } queue = 0; bugCoords.clear(); } } //---------------------------------------------------- //-- CHECK THE KEYBOARD FOR DELICIOUS FOOD! -- //---------------------------------------------------- void keyReleased() { //upper case if (int(key) >= 65 && int(key) < = 90) { float xpos = random(10, width-400-50); float ypos = random(height*.75+15, height - 5); int pri = checkUpper(key); if (pri != 0) { foods.add(new Food(xpos, ypos, 8, checkUpper(key))); } } //lower case else if (int(key) >= 97 && int(key) < = 122) { float xpos = random(10, width-400-50); float ypos = random(height*.75+15, height - 5); int pri = checkLower(key); if (pri != 0) { foods.add(new Food(xpos, ypos, 8, checkLower(key))); } } } //---------------------------------------------------- //-- GRAB COLOR/PRIORITY INFO FROM KEYBOARD -- //---------------------------------------------------- int checkLower(char letter) { int pri = 0; if ("eta".indexOf(str(letter)) > -1) {
pri = 5;
}
else if ("oinshr".indexOf(str(letter)) > -1) {
pri = 4;
}
else if ("dlcumwfg".indexOf(str(letter)) > -1) {
pri = 3;
}
else if ("ypbvk".indexOf(str(letter)) > -1) {
pri = 2;
}
else if ("xqz".indexOf(str(letter)) > -1) {
pri = 1;
}
return pri;
}

int checkUpper(char letter) {
int pri = 0;
if ("ETA".indexOf(str(letter)) > -1) {
pri = 5;
}
else if ("OSINSHR".indexOf(str(letter)) > -1) {
pri = 4;
}
else if ("DLCUMWFG".indexOf(str(letter)) > -1) {
pri = 3;
}
else if ("YPBVK".indexOf(str(letter)) > -1) {
pri = 2;
}
else if ("XQZ".indexOf(str(letter)) > -1) {
pri = 1;
}
return pri;
}

class Bug {
float xpos, ypos;
float vx, vy;
float dist;
float size = 0.05;
float desiredSize = size;
float ms = 100;
float goalx, goaly;
int id;
float speed;
float lastAte;

Bug(float xin, float yin) {
xpos = xin;
ypos = yin;
size = 0.05;
vx = 0;
vy = 0;
speed = random(.5,1.2);
}

void display() {
noStroke();
fill(52, 27, 27);
pushMatrix();
float depth = 1-((height-ypos)/height);
translate(xpos, ypos+cos(xpos/2)-depth*size*ms/2);
scale(depth*size, depth*size);
fill(72, 47, 47);
ellipse(-(ms/20), (ms/2)+sin(xpos), ms/10, ms/10);
fill(52, 27, 27);
ellipse(2*cos(millis()/200), 0, ms, ms);
ellipse((ms/20), (ms/2)+cos(xpos), ms/10, ms/10);
popMatrix();
}

void eat(float foodSize) {
desiredSize += foodSize / 100;
lastAte = millis();
}

void seek(float goalxin, float goalyin) {
goalx = goalxin;
goaly = goalyin;
float absx = goalx - xpos;
float absy = goaly - ypos;
float dist = sqrt((absx * absx) + (absy * absy));
vx = absx / dist * speed;
vy = absy / dist * speed;
}

void update() {
xpos += vx;
ypos += vy;

if (xpos + vx > width-400-(ms*size/2)) {
vx *= -1;
xpos = min(xpos, width-400-(ms*size/2));
}
else if (xpos + vx < 0) { vx *= -1; xpos = max(xpos, 0); } if (ypos + vy > height) {
vy *= -1;
ypos = min(ypos, height);
}
else if (ypos + vy < height*.75) { vy *= -1; ypos = max(ypos, height*.75); } } boolean isMature() { if (size > 1) {
return true;
}
return false;
}
}

class Food {
float x, y, dia;
int priority;
color flavor;

Food (float xin, float yin, float din, int pri) {
x = xin;
y = yin;
dia = din;
priority = pri;

//------SET COLOR-------
if (pri == 5) {
flavor = red;
}
else if (pri == 4) {
flavor = orange;
}
else if (pri == 3) {
flavor = yellow;
}
else if (pri == 2) {
flavor = green;
}
else if (pri == 1) {
flavor = blue;
}
}

void display() {
fill(flavor);
pushMatrix();
translate(x,y);
scale(1-((height-y)*2/height),1-((height-y)*2/height));
ellipse(0,0,dia,dia);
popMatrix();
}

boolean isGone() {
if (dia < 1) { return true; } return false; } }

Ticha-Do you hear the birdie sing

My creature ended up not being an abstract or fantastical mystical one, but a relatively normal-looking robin that responds to the user’s voice. Lately, I’ve been doing a lot of work with the AudioInput library in processing because of the level of interactivity it offers between the user and the program. As someone who grew up in a musically oriented environment, I strongly believe that music is one of the best methods of bonding individuals. Thus, I created a robin that responds to singing but runs away when the input audio level exceeds a certain threshold. At the certain point, the robin will start to dance and even sing along once it has gained enough of the user’s trust.

I admit that I am still not completely satisfied with this project – I had spent so much time on trying to make the audio work and handling awkward boolean logic that I was not able to make the simulation as sophisticated as I wanted it to be. Nevertheless, this was a very valuable learning experience for me as it forced me to reason about my code more carefully and reacquainted me with good ol’ null pointer exceptions.

Dropbox link for the code because OpenProcessing hates me: https://www.dropbox.com/s/m1pbwk68zsvgkzz/singing_bird.zip

Ralph-Assignment-07-Life

20131017_082320

This piece is a simple evolution simulator. I was inspired by my complete bafflement at the Evolution vs Creationism “debate” in the United States. I could not understand how such a simple logic behind the concept of evolution was so difficult to understand for so many people, so I created a created a very basic emulation of it. The reference in this piece is the pepper moth case, where a population of species of moth near London clearly changed color depending on the pollution level. Similarly, the finches in the simulation has a higher probability of eating a moth that has greater contrast with the background. The speed of the simulation and the shade of the tree is also adjustable by the user, so there’s no bullshit going on here.

Never Give Up (round 2)

The creature works hard to collect bubbles into a grid, and the user can either mess up its work by moving individual bubbles to anger it, or completely obliterate its creation, causing it to break down into panic.

Changes: the creature collects the bubbles into a grid, the creature moves nonlinearly, and the user can click on individual bubbles to move them and cause a slightly less intense reaction from the creature, who will just grunt and continue its duty.