Deer Hunter

face1

face2

I once participated in a game design conversation, and one of the ideas we developed was to have a predator hiding its size so it can sneak up on its prey. The devouring idea is also inspired by Thatgamecompany’s Flow. I feel by using the mouth as the catalyst for consuming, I can put the player into a more emersive atmosphere, and maybe make them feel either bad or empowered as they turn deer into explosions of blood. I feel I can improve upon the game by adding in sound effects and music, but finding the perfect ones take more time than I anticipated.

I used the position of the head to determine whether the blob should go left or right on screen. Changing the height of my mouth will change the size of the blob, and when that height go past a certain threshold, the blob turns into a monster and devour the deer. It will revert back to a small blob once the player closes his/her mouth again.

Balls and Legs

clock1 clock2 clock3

“Everyone you know someday will die” – The Flaming Lips

No matter how strong a relationship or how durable a material is, the passage of time will erode it. The blobs and the legs fall down as each minute passes, each trying to bounce or twitch its way back up top, but it will never achieve its old position ever again. We too can struggle against the flow of time, but we cannot win.

I like the organic feel of the blob, but I feel like it could be more irregular to look even weirder. I also wanted the legs to represent something, such as the hours, but since my clock resets every 12 hours, 12 legs is not enough. They also look weird without being attached to a ball so I just attached them randomly to balls.

int square_width = 15;
Ball[] balls;
Leg[] legs;
int past_second = -1;
PImage leg_img;

class Ball{
  int x, y, diameter, stop_point;
  float speed, acceleration;
  int dx, dy, dd;

  Ball(int a, int b, int d)
  {
    x = a;
    y = b;
    diameter = d;
    speed = 0.0;
    acceleration = 0.0;
    stop_point = (int)random(-30, 30);
    dx = (int)random(-3,3);
    dy = (int)random(-3,3);

    // delta diameter
    dd = (int)random(5,15);
    if(random(-1,1) < 0.0)
      dd *= -1.0;
  }

  /**
   * drops the ball
   */
  void drop()
  {
    acceleration = 0.9;
  }

  void draw_ball()
  {
    // make the ball fall
    if(y < height - 40 + stop_point || (speed < 0.0))
    {
      y += speed;
      speed += acceleration;
    }
    else if(abs(speed) > 3.5)
      speed *= -0.4;

    float percent = (millis() % 1000.0)/1000.0;
    if(percent > 0.5)
      percent = 1.0 - percent;

    stroke(200, 50 + diameter);
    fill(20, 50 + diameter);
    ellipse(x+percent*dx, y+percent*dy, diameter+percent*dd, diameter+percent*dd);
  }
}

class Leg{
  float direction;
  float theta, leg_scale, dtheta;
  Ball ball;

  Leg(Ball ba)
  {
    ball = ba;
    leg_scale = random(0.8, 1.2);
    theta = random(-0.5, 0.5);
     
    direction = 1.0;
    if(random(-1,1) < 0.0)
      direction *= -1;
  }

  void draw_leg()
  {
    pushMatrix();
    
    float percent = (millis() % 1000.0)/1000.0;
    if(percent > 0.5)
      percent = 1.0 - percent;

    translate(ball.x, ball.y);

    if(ball.x > width/2)
      scale(-leg_scale,leg_scale);
    else
      scale(leg_scale,leg_scale);

    if(0.0 < ball.speed && ball.speed < 0.1)
      percent = 1.0 + 0.03*percent;

    float on_ground = 0.0;
    float speed = 1.0;
    if(ball.acceleration != 0.0)
    {
      on_ground = 0.006*ball.y;
      speed = ball.speed;
    }

    rotate(theta+percent*0.09*(direction*speed)+on_ground);

    image(leg_img, 0, 0);

    popMatrix();
  }
}

void setup() {
  size(600, 600);
  randomSeed(15251);
  initialize_balls();
  leg_img = loadImage("leg.png");
  initialize_legs();
  set_to_current_time();
  
}

/**
 * initializes the clock to current time
 */
void set_to_current_time()
{
  int minute_passed = 60*hour() + minute();
  for(int i = 0; i < minute_passed; i++)
  {
    int r = (int)random(0,720);
    Ball random_ball = balls[r];
    
    // select a ball that hasnt already fallen
    while(random_ball.speed != 0.0)
    {
      r = (int)random(0,720);
      random_ball = balls[r];
    }

    random_ball.drop();
  }
}

/**
 * allocate the ball objects
 */
void initialize_balls(){
  balls = new Ball[720];
  int i = 0;
  while(i < balls.length)
  {
    int x = 0;
    int y = 20;
    while((x < width/2 && y > 2*x/3 + random(-10,10)) || 
          (x > width/2 && y > 2*(width - x)/3 + random(-10,10))
          )
    {
      x = (int)random(20, width-20);
      y = (int)random(5, height/3);
    }

    int s = (int)random(20, 50);

    balls[i] = new Ball(x, y, s);
    i++;
  }
}

/**
 * allocate the leg objects
 */
void initialize_legs()
{
  legs = new Leg[20];
  for(int i = 0; i < legs.length; i++)
  {
    Ball b = balls[(int)random(0,720)];
    while(!(b.x < 200 || b.x > 300))
      b = balls[(int)random(0,720)];

    legs[i] = new Leg(b);
  }

}

/**
 * draw the gradient for the background
 */
void draw_background(){

  for(int i = 0; i < height; i++)
  {
    stroke(100-i/7, 50-i/12, 70-i/10);
    line(0, i, width, i);
  }
}

void draw() {
  draw_background();

  // resets the clock every 12 hours
  if(hour() % 12 == 0 && minute() % 60 == 0 && millis() % 1000.0 < 100.0)
  {
    initialize_balls();
    initialize_legs();
  }

  // selects random ball to drop every minute
  if(second() == 0 && past_second != second())
  {
    int r = (int)random(0,720);
    Ball random_ball = balls[r];
    
    // select a ball that hasnt already fallen
    while(random_ball.speed != 0.0)
    {
      r = (int)random(0,720);
      random_ball = balls[r];
    }
    random_ball.drop();
  }
  past_second = second();

  // draw the balls
  for(int i = 0; i < balls.length; i++)
  {
    Ball b = balls[i];
    b.draw_ball();
  }

  // draw the legs
  for(int i = 0; i < legs.length; i++)
  {
    Leg l = legs[i];
    l.draw_leg();
  }
}

Winter Scene GIF

output

sketch

I started off by playing with the noise function, and when I was observing it, I thought the way it moved looked like a row of soldiers marching. Thus I decided to create infinite rows of noise soldiers walking towards the viewer. However, after I coded it up, I realized that what I had looked more like a waterfall, so I just created a scene by going from there instead.

During the entire process of creating this gif, I spend a lot of time worrying how I could get it to loop. Not taking risks made me feel like I did not learn as much as I could from this project. Also, I did not realize that there was a template uploaded, which could have saved me a lot of time. Thirdly, I found out that I enjoy watching my animation more when I am listening to some relaxing music, rather than being in silence, so I feel it might have been better if instead it is a music video with more contents. The combined effects made me feel serene, which I am glad for.

Thanks to Daniel Shiffman for his code of the particle system.

int square_width = 15;
color skycolor = color(40,40,40);
boolean sunrise = true;
int snowcolor = 140;
int stay = 0;
int frames = 0;

ParticleSystem ps1, ps2;

class Particle {
  PVector location;
  PVector velocity;
  PVector acceleration;
  float lifespan;

  Particle(PVector l) {
    acceleration = new PVector(0,0.1);
    velocity = new PVector(random(-10,10),1.0);
    location = l.get();
    lifespan = 255.0;
  }

  void run() {
    update();
    display();
  }

  // Method to update location
  void update() {
    velocity.add(acceleration);
    location.add(velocity);
    lifespan -= 1.0;
  }

  // Method to display
  void display() {
    stroke(255,200 - blue(skycolor) + 2);
    fill(255, 200 - blue(skycolor) + 2);
    ellipse(location.x,location.y,8,8);
  }
  
  // Is the particle still useful?
  boolean isDead() {
    if (lifespan < 0.0) {
      return true;
    } else {
      return false;
    }
  }
}




// A class to describe a group of Particles
// An ArrayList is used to manage the list of Particles 

class ParticleSystem {
  ArrayList particles;
  PVector origin;

  ParticleSystem(PVector location) {
    origin = location.get();
    particles = new ArrayList();
  }

  void addParticle() {
    particles.add(new Particle(origin));
  }

  void run() {
    for (int i = particles.size()-1; i >= 0; i--) {
      Particle p = particles.get(i);
      p.run();
      if (p.isDead()) {
        particles.remove(i);
      }
    }
  }
}


class Row_of_Noise{
  int start, end;
  float row;

  Row_of_Noise(int s, int e, float r)
  {
    start = s;
    end = e;
    row = r;
  }

  void walk_forward()
  {
    row *= 1.03;
    if(row > height)
      row = 0.1;

    start = width/2-(int)row*3;
    end = width/2+(int)row*3; 
  }
}

Row_of_Noise[] RoN;

void setup() {
  size(600, 600);
  stroke(0);
  smooth();
  noiseSeed(15251);
  initialize_rows_of_noise();
  ps1 = new ParticleSystem(new PVector(width/3,-50));
  ps2 = new ParticleSystem(new PVector(2*width/3,-50));
}

void initialize_rows_of_noise(){
  RoN = new Row_of_Noise[40];
  float r = 0.1;
  for(int i = 0; i < RoN.length; i++)
  {
    r *= 1.3;
    RoN[i] = new Row_of_Noise(width/2-(int)r*2, 
                              width/2+(int)r*2, 
                              r);
  }
}

void draw_row_of_noise(Row_of_Noise ron)
{
  beginShape();
  float theta = 0.0;
  for(int x = ron.start; x < ron.end; x++)
  {
    
    if(x % 50 == 0)
    {
      endShape();
      beginShape();
    }
    
    if(x % 50 < 10)
      continue;

    float y = noise((millis()/1000.0 + x)%50.0) * 
                   ((float)(ron.end - ron.start)/ 6.0) + ron.row;
    vertex(x-5,y+300);
  }
  endShape();
}

void draw() {

  if(53 < frames && frames < 285)
    saveFrame("outputgif/myname-loop-" + nf(frames,4) + ".png");
  if(blue(skycolor) > 200)
  {
    sunrise = false;
    if(stay == 0)
      stay = 50;
    else
      stay--;
  }

  if(blue(skycolor) < 10)
  {  
    sunrise = true;
    if(stay == 0)
      stay = 50;
    else
      stay--;
  }

  if(stay == 0)
  {
    if(sunrise)
    {
      skycolor = color(red(skycolor)+1, green(skycolor)+2, blue(skycolor)+3);
      snowcolor++;
    }
    else
    {
      skycolor = color(red(skycolor)-1, green(skycolor)-2, blue(skycolor)-3);
      snowcolor--;
    }
  }

  background(skycolor);
  stroke(snowcolor);

  for(int i = 0; i < width; i++)
    line(i,noise(i/400.0)*100.0 + 245,i,height);

  // draws the waterfall
  stroke(0,100,200);
  noFill();
  for(int i = 0; i < RoN.length; i++)
  {
    draw_row_of_noise(RoN[i]);
    RoN[i].walk_forward();
  }

  ps1.addParticle();
  ps1.run();
  ps2.addParticle();
  ps2.run();

  frames++;
}

Dave-LOOKINGOUTWARDS-2

The Stone Spray Project by Petr Novikov, Inder Shergill and Anna Kulik is a robot which generates sculptures from sand. The final products it creates look great, but the process of making them are even more mesmerizing. The way it moves seem almost human, and as it slowly carves out every detail, the sculpture­­­­­ grows out in an organic manner. Using sand as a medium is also intriguing, as I always thought of it as a flowing form instead of a solid state.

However, I do feel that if the robot can also make concrete sculptures rather than just generative forms alone, it would have more appeal to larger groups of people. Also I would have enjoyed a longer footage of the robot working.

Its use of sand as material to make 3D objects by a computer reminded me of Markus Kayser’s Solar Sinter Project, although Kayser melts the sand into glass before using it while The Stone Spray Object mixes the sand with substances to make it stabilize.

Oscillate by Daniel Sierra features threads vibrating to the sound of music. I have become a big fan of visualization, and this piece does it exceptionally well by having perfect sync between what is seen and what is heard, thus creating a powerful engrossing atmosphere. He also kept the animations fresh by having different viewpoints and by generating multiple effects, ranging from those similar to slivers of sand to fading flames. The heavier techno section in the middle of the video I feel is the weakest part, as it takes away the ambient atmosphere generated by the rest of the video. The visualization of music with threads and particles is similar to the lyrics video of Madness by Muse, however Oscillate uses a completely different kind of music and only uses abstract shapes instead of typography.

trailers_anemone by John Carpenter allows the audience to interact with an abstract form projected onto a wall. The movement and shape of the form caught my attention because of its color, its glow, and how it uses threads as much of its shape causes it to look electronic, or at least similar to some type of data visualization. But when it starts to move, it becomes organic, as the threads and lights start swimming in patterns reminiscent of schools of fish. I can just stare at its movements for days. However, the video is a bit short, and does not show all the interactive possibilities I would like to see, and I ended up longing for more details on the project. The lighted up organic forms moving as if though they are swimming is similar to Thatgamecompany’s Flow, although the presentation of Flow is very different from trailers_anemone which allows for more direct human interaction.

Dave-Schotter

dave-schotter-screenshot

 

I never did much with interactivity and animation in Processing before so I decided to incorporate it into this. The user decides when to stop.Try it out here:

Click and hold the mouse and then shake on the canvas to produce Schotter’s effect.

int square_width = 15;
float acceleration = 0.0;

class Square{
  float x,y,theta;
  float direction;

  Square(float a, float b, float t)
  {
    x = a;
    y = b;
    theta = t;
    direction = 1.0;
  }

  void change_angle(float t){
    theta = t;
  }

  void change_Xcoord(float i){
    x = i;
  }

  void change_Ycoord(float i){
    y = i;
  }

  void change_direction(float d){
    direction = d;
  }
}

Square squaresArray[][];

/**
 * initialize the default squares
 */
void generate_squares(){
  squaresArray = new Square[height/square_width][width/square_width];
  for (int y = 0; y < height/square_width; y++) {
    for(int x = 0; x < width/square_width; x++){
      squaresArray[y][x] = new Square(x*square_width,y*square_width,0);
    } 
  }

}

void setup() {
  size(510, 600);
  background(255);
  frameRate(30);
  noFill();

  generate_squares();
}

void mouseClicked(){
  for (int y = 1; y < squaresArray.length - 1; y++) {
    for(int x = 1; x < squaresArray[y].length - 1; x++){
      int a = Math.round(random(0,1));
      if(a == 0)
        a = -1;

      squaresArray[y][x].change_direction((float)a);
    }
  }
}

void draw(){

  // refresh screen
  background(255);

  float should_move;  // decides whether we should change Y coord
  if(!mousePressed)   // if user is dragging
  {
    acceleration = acceleration/1.1;
    should_move = 0.0;
  }
  else        // the user let go
  {
    acceleration = (mouseX - pmouseX)*0.007;
    should_move = 1.0;
  }

  // loop through to draw squares
  for (int y = 1; y < squaresArray.length - 1; y++) {
    for(int x = 1; x < squaresArray[y].length - 1; x++){

      Square square = squaresArray[y][x];

      pushMatrix();

      // rotate the square by theta
      translate((int)square.x,
            (int)square.y);
      rotate(square.theta);

      // record new angle
      square.change_angle(square.theta +
                  acceleration*(y/height + 1)*
                  (y*random(0.0,0.05) *
                  square.direction));

      // record new y location (squares slowly shift downward)
      square.change_Ycoord(square.y +
                  abs(acceleration)*
                  should_move*
                  ((y*y)/100.0));

      // draw the rectangle
      rect(0,0,square_width,square_width);

      popMatrix();
    }
  }
}

Seizure Light

Should an intruder ever break into my house, I would send a text to IFTTT. This would trigger every single wall in my house, which will be made out of giant light bulbs, to flash rapidly with magenta and blue. This technique is known to induce seizures, as accidentally demonstrated after the initial airing of an episode of Pokemon in 1997, which send 685 viewers to hospitals. This will hopefully buy me enough time to escape, call the police, or kick the intruder while he/she is down.

drawing

Reverse

1. Draw a small rectangle r anywhere on the paper.
2. Draw a set of at least 10 small rectangles, which I will call S, going every which way around r.
3. Select a random element s from S, then select a random edge of s, and extend that edge outward away from r. The length of the edge should be much longer than the original edge.
4. Randomly decide whether to draw a random amount of edges perpendicular to the one you just drew.
5. Repeat step 3 to 4 until satisfied.
6. Repeat step 1 to step 5 until satisfied.

reverse

Animals

Instruction:

code

Here are the images produced:

instruction_1 instruction_2 instruction_3

The drawings of each animal are a lot more detailed than I have anticipated. I was expecting quantity over quality, but I got only 3 animals for 2 of the drawings. People also did not shake their head as much as I expected either. In the end I feel that was a redundant instruction.

The reason why I wrote this in pseudo-Python code is because I was appalled by Sol LeWitt’s instructions; I refused to use English as medium for my instructions. However, the day after I wrote this, I realized that English in fact can convey the same message much better (less confusing and more concise), something along the lines of “start from the smallest animal you can think of, keep drawing a larger animal than the previous eating that. If your animal is too large, start from smallest animal again. Stop when you are bored”.

Math was Invented for a Reason

WP_000639

I drew the first 2 lines with some struggle, but I managed by crossing out the instructions I have already finished. However, starting from the third line, I was no longer able to keep track of which points are the points for the line, and which points are the reference points for drawing those points. Yes, this instruction is code, but it is a disgustingly bad one. Math was invented for a reason, and if Sol LeWitt even attempted to be efficient, he would put parentheses around phrases to emphasize where the description of each point or reference point started and ended. A good code would be able to execute the same drawing with just a few lines. But of course, this was not his intention, so be it.