Kinetic Interfaces – Midterm (Moon) Andrew Huang

Author: Andrew Huang Project name: Underfire! A bullet hell game Professor: Moon Date: Nov 3 2018 Goal: To Create a Upper body immersive bullet hell / dodging game. Description: After playing some Undertale and bullet hell games over the last couple of weeks, I was inspired to create a more kinetic and interactive version of the game. I […]

// ANDREW
// KINETIC INTERFACES MIDTERM
// make tracking easier and add endgame
import gab.opencv.*;
import processing.video.*;
import java.awt.*;

Capture video;
OpenCV opencv;

ArrayList<Ball> balls = new ArrayList<Ball>();
PImage img, flameimg;
Health hp;
void setup() {
  size(500, 500
  );
  background(255);
  noStroke();
  smooth();
  noStroke();
  hp = new Health();
  fill(0);
  rect(mouseX, mouseY, 50, 7);
  img = loadImage("frisk.png");
  flameimg = loadImage("flame.png");

  video = new Capture(this, 640/4, 480/4);
  opencv = new OpenCV(this, 640/4, 480/4);
  opencv.loadCascade(OpenCV.CASCADE_FRONTALFACE);  

  video.start();
}
float inputx = 0, inputy = 0, facex = 0, facey = 0;
void draw() {
  opencv.loadImage(video);
  Rectangle[] faces = opencv.detect();
  background(#354c7c);
  text(frameRate, 20, 20);
  text("Balls added: " + balls.size(), 20, 40); 
  rectMode(CENTER);
  if (faces.length > 0) {
    inputx = map(faces[0].x, 0, 640/4, 500, -120);
    inputy = map(faces[0].y, 0, 480/4, 50, 400);
    facex = faces[0].width;
    facey = faces[0].height;
  }
  pushMatrix();
  image(img, inputx - img.width/20, inputy - img.height/20, img.width/10, img.height/10);
  stroke(100);
  noFill();
 // println(inputx, inputy);
  rect( inputx, inputy, img.width/10, img.height/10);
  popMatrix();
  hp.display();
  for (int i=0; i<balls.size(); i++) {
    balls.get(i).track(inputx, inputy);
    balls.get(i).bounce();
    balls.get(i).display();
    if (balls.get(i).removeBall(i)) {
      hp.hit();
    }
    //balls.get(i).age++;
  }
  if (frameCount % 100 == 0) {
    float r = random(0, 1);
    if (r > 0.5) {
      balls.add(new Ball(random(0, width), 10));
    } else {
      balls.add(new Ball(random(0, width), height));
    }
  }
  if (frameCount % 500 == 0 && hp.health < 100) {
    hp.health = ( hp.health + 20 ) > 100 ? 100 : hp.health + 20;
    for (int i = 0; i < balls.size(); i++) {
      balls.get(i).removeBall(i);
    }
  }
  if (hp.getHealth() <= 0) {
    textSize(40);
    fill(255, 0, 0);
    text("GAME OVER", width/3, height/2);
    text("SCORE: "  + hp.getHits(), width/3, height/2 + 50);
    noLoop();
    //delay(9999999);
  }
  pushMatrix();
  image(video, width/2 - 640/8, height-125);
  popMatrix();
}
void captureEvent(Capture c) {
  c.read();
}

void mouseClicked() {
  float r = random(0, 1);
  if (r > 0.5) {
    balls.add(new Ball(random(0, width), 10));
  } else {
    balls.add(new Ball(random(0, width), height));
  }
}

class Ball {
  float x, y, size;
  color clr;
  float xspeed, yspeed;
  float age = 0;

  Ball(float tempX, float tempY) {
    x = tempX;
    y = tempY;
    size = 20;
    clr = color(random(255), random(255), random(255));

    xspeed = random(-5, 5);
    yspeed = random(3, 5);
  }

  void display() {
    //fill(clr);
    tint(clr);
    image(flameimg, x,y,size*2,size*2);
    noTint();
    //ellipse(x, y, size, size);
  }

  void move() {
    x += xspeed;
    y += yspeed;
  }
  
  void track(float xx, float yy){
    float easing = 0.01;
     x += (xx - x) * easing;
     y += (yy - y) * easing;
  }

  void bounce() {

    if ((x>mouseX-25) && (x<mouseX+25) && (y > mouseY-3.5)) {
      yspeed = -yspeed;
    } 


    if (y < 0) {
      yspeed = -yspeed;
    } 
    if (x < 0) {
      xspeed = -xspeed;
    } else if (x > width) {
      xspeed = -xspeed;
    }
  }

  boolean removeBall(int i) { // hitdetection
    if (dist(inputx, inputy, x, y) < 50 || age > 400) {
      balls.remove(i);
      return true;
    }
    return false;
  }
}
class Health {
  float health = 100;
  float MAX_HEALTH = 100;
  float rectWidth = 200;
  float hits;
  
  Health(){
    return;
  }
  void display(){
    if (health < 25){
    fill(255, 0, 0);
    }  else if (health < 50) {
    fill(255, 200, 0);
    } else {
    fill(0, 255, 0);
    }
  
    noStroke();
    // Get fraction 0->1 and multiply it by width of bar
    float drawWidth = (health / MAX_HEALTH) * rectWidth;
    rectMode(CORNER);
    rect(200, 10, drawWidth, 10); 
    
    // Outline
    stroke(255);
    noFill();
    rect(200, 10, rectWidth, 10);
    stroke(0);
  }
  float getHealth(){
    return health;
  }
  float getHits(){
    return hits;
  }
  void hit(){
    health-= 5;
    hits++;
  }
  
}

Kinetic Interface – Midterm Project (Emerald)

Course Name: Kinetic interface Instructor: Moon Partner: Ribirth Description Basically our project is an educational hotpot game. It shows players different time that different food need to be cooked in a hotpot. We use leap motion to enable the grab gesture of the player, so it gives a more physical sense of use chopsticks to […]

import processing.sound.*;
SoundFile file;
SoundFile readyFile;
SoundFile no;
SoundFile yes;

//import
//  ddf.minim.*; 
//Minim minim;  
//AudioPlayer player; 



int stage = 0;
int time = 0;
int foodtime = 0; 


float opacity1 = 0;
float opacity2 = 0;
float opacity3 = 0;
float opacity4 = 0;
float opacity5 = 0;
float opacity6 = 0;


float handX, handY;
float HG;

PFont myFont;
PImage background;
PImage clock;
PImage star;
PImage timebar;
PImage start;
PImage table;

PImage meat;
PImage cabbage;
PImage shiitake;
PImage crab;
PImage goat;
PImage meatball;

PImage meat1;
PImage cabbage1;
PImage shiitake1;
PImage crab1;
PImage goat1;
PImage meatball1;

PImage pot;
PImage chopstick1;
PImage chopstick2;

PImage success;
PImage fail;


void setup() {


  size(600, 600);
  background(255);

  leapMotion_setup();
  myFont = createFont("Skia-Regular_Bold", 32);
  textFont(myFont);

  file = new SoundFile(this, "bgm.mp3");
  file.loop();
  //minim = new
  //  Minim(this); 
  readyFile = new SoundFile(this, "ready.mp3");
  no = new SoundFile(this, "no.mp3");
  yes = new SoundFile(this, "yes.mp3");


  background = loadImage("background.jpg");
  start = loadImage("start.png");
  table = loadImage("table.jpg");

  meat = loadImage("meat.png");
  cabbage = loadImage("cabbage.png");
  shiitake = loadImage("shiitake.png");
  crab = loadImage("crab.png");
  goat = loadImage("goat.png");
  meatball = loadImage("meatball.png");

  pot = loadImage("pot.png");
  chopstick1 = loadImage("chopstick.png");
  chopstick2 = loadImage("chopstick.png");

  meat1 = loadImage("meat1.png");
  cabbage1 = loadImage("cabbage1.png");
  shiitake1 = loadImage("shiitake1.png");
  crab1 = loadImage("crab1.png");
  goat1 = loadImage("goat1.png");
  meatball1 = loadImage("meatball1.png");

  timebar = loadImage("timebar.png");
  star = loadImage("star.png");
  clock = loadImage("clock.png");
  success = loadImage("success.png");
  fail = loadImage("fail.png");
}

void draw() {



  leapMotion_draw();



  switch( stage ) {
  case 0: 
    stage_opening();
    break;
  case 1:
    stage_play();

    break;
  case 2:
    break;
  }
}




void stage_opening() {

  pushMatrix();
  background(background);
  imageMode(CENTER);
  translate(width/2, height/2);
  scale(0.5);
  image(start, 0, 0);
  popMatrix();
  
  stroke(10);
  fill(252, 98, 80);
  text("Crab to Strat!",200,200);

  if (HG>0.6) {
    readyFile.play();
    pushMatrix();
    background(background);
    //background(255);
    imageMode(CENTER);
    translate(width/2, height/2);
    scale(0.4);
    image(start, 0, 0);
    //player.play();
    popMatrix(); 
    time ++;
    println(time);
    if (time>10) {
      stage = 1;
    }
  }
}

// add interaction here

//if (mousePressed) {
//  stage = 1;
//}
//background(255, 255, 0);
//fill(255);
//text("StartPage", 10, 20);



void stage_play() {
  background(255);
  image(table, 0, 0, width*2, height*2);
  image(meat, 70, 200, 100, 100);
  image(cabbage, 70, 350, 100, 100);
  image(shiitake, 540, 200, 100, 100);
  image(crab, 540, 350, 100, 100);
  image(goat, 210, 470, 100, 100);
  image(meatball, 400, 470, 100, 100);
  image(timebar, 250, 170, 700, 500);


  pushStyle();
  imageMode(CENTER);
  image(pot, width/2, height/2, 369, 232);
  popStyle();

  pushMatrix();
  pushStyle();
  translate(handX, handY);
  rotate(PI/1.2);
  imageMode(CENTER);
  image(chopstick1, 0, 15, 150, 15);
  popStyle();
  popMatrix();

  pushMatrix();
  pushStyle();
  translate(handX, handY);
  rotate(PI/1.1);
  imageMode(CENTER);
  image(chopstick2, 0, -15, 150, 15);
  popStyle();
  popMatrix();

  pushStyle();
  tint(255, 255, 255, opacity1);
  image(meat1, handX-60, handY+20, 40, 50);
  popStyle();
  pushStyle();
  tint(255, 255, 255, opacity2);
  image(cabbage1, handX-60, handY+20, 40, 80);
  popStyle();
  pushStyle();
  tint(255, 255, 255, opacity3);
  image(shiitake1, handX-60, handY+20, 30, 30);
  popStyle();
  pushStyle();
  tint(255, 255, 255, opacity4);
  image(crab1, handX-60, handY+20, 40, 50);
  popStyle();
  pushStyle();
  tint(255, 255, 255, opacity5);
  image(goat1, handX-60, handY+20, 50, 50);
  popStyle();
  pushStyle();
  tint(255, 255, 255, opacity6);
  image(meatball1, handX-60, handY+20, 30, 30);
  popStyle();

  float dist1 = dist(handX, handY, 120, 200 );
  float dist2 = dist(handX, handY, 120, 350 );
  float dist3 = dist(handX, handY, 590, 220 );
  float dist4 = dist(handX, handY, 590, 370 );
  float dist5 = dist(handX, handY, 290, 490 );
  float dist6 = dist(handX, handY, 480, 480 );
  float dist_drop = dist(handX-30, handY+30, 300, 300);


  image(star, 50+foodtime*3, 115, 400, 400);
  image(clock, 520, 60, 140, 120);

 // ====  meat ==== //

  if (opacity1 == 0) {
    if (dist1 < 50 && HG > 0.6) {
      opacity1 = 300;
    }
  }
  if (opacity1 == 300 && dist_drop < 100) {
    fill(0, 0, 0);
    text(foodtime/6, 510, 70);
    foodtime ++;
    println(foodtime); 
    stroke(10);
    fill(255);
    if (foodtime>90) {
      fill (232, 42, 6);
      text ("OVER COOKED!", 220, 100);
    } else if (foodtime>60 & foodtime<90) {
      fill(232, 118, 80);
      text ("READY!", 190, 100);
    } else if (foodtime<60) {
      text ("NOT YET!", 80, 100);
    }
  } else if (opacity1 == 300 && foodtime < 90 && foodtime > 60 && dist_drop > 100 ) {
    pushStyle();
    tint(255, 255, 255, opacity1);
    image(success, 300, 300, 200, 200);
    popStyle();
    pushStyle();
    tint(0, 0, 0, opacity1-280);
    image(meat1, handX-60, handY+20, 40, 50);
    popStyle();
  } else if (opacity1 == 300 && foodtime > 90 && dist_drop > 100) {
    pushStyle();
    tint(255, 255, 255, opacity1);
    image(fail, 300, 300, 200, 200);
    popStyle();
    pushStyle();
    tint(0, 0, 0, opacity1);
    image(meat1, handX-60, handY+20, 40, 50);
    popStyle();
  } else if (opacity1 == 300 && foodtime > 1 && foodtime < 60 && dist_drop > 100) {
    pushStyle();
    tint(255, 255, 255, opacity1);
    image(fail, 300, 300, 200, 200);
    popStyle();
  }
  if (opacity1 == 300 && HG < 0.5) {
    foodtime = 0;
    opacity1 = 0;
  }


  // ====  cabbage ==== //


  if (opacity2 == 0) {
    if (dist2 < 50 && HG > 0.6) {
      opacity2 = 300;
    }
  }
  if (opacity2 == 300 && dist_drop < 100) {
    fill(0, 0, 0);
    text(foodtime/2, 510, 70);
    foodtime ++;
    println(foodtime); 
    stroke(10);
    fill(255);
    if (foodtime>90) {
      fill (232, 42, 6);
      text ("OVER COOKED!", 220, 100);
    } else if (foodtime>60 & foodtime<90) {
      fill(232, 118, 80);
      text ("READY!", 190, 100);
    } else if (foodtime<60) {
      text ("NOT YET!", 80, 100);
    }
  } else if (opacity2 == 300 && foodtime < 90 && foodtime > 60 && dist_drop > 100 ) {
    pushStyle();
    tint(255, 255, 255, opacity2);
    image(success, 300, 300, 200, 200);
    popStyle();
    pushStyle();
    tint(0, 0, 0, opacity2-280);
    image(cabbage1, handX-60, handY+20, 40, 80);
    popStyle();
  } else if (opacity2 == 300 && foodtime > 90 && dist_drop > 100) {
    pushStyle();
    tint(255, 255, 255, opacity2);
    image(fail, 300, 300, 200, 200);
    popStyle();
    pushStyle();
    tint(0, 0, 0, opacity2);
    image(cabbage1, handX-60, handY+20, 40, 80);
    popStyle();
  } else if (opacity2 == 300 && foodtime > 1 && foodtime < 60 && dist_drop > 100) {
    pushStyle();
    tint(255, 255, 255, opacity2);
    image(fail, 300, 300, 200, 200);
    popStyle();
  }
  if (opacity2 == 300 && HG < 0.5) {
    foodtime = 0;
    opacity2 = 0;
  }


  // ====  shiitake ==== //
  if (opacity3 == 0) {
    if (dist3 < 50 && HG > 0.6) {
      opacity3 = 300;
    }
  }
  if (opacity3 == 300 && dist_drop < 100) {
    fill(0, 0, 0);
    text(foodtime/2, 510, 70);
    foodtime ++;
    println(foodtime); 
    stroke(10);
    fill(255);
    if (foodtime>90) {
      fill (232, 42, 6);
      text ("OVER COOKED!", 220, 100);
    } else if (foodtime>60 & foodtime<90) {
      fill(232, 118, 80);
      text ("READY!", 190, 100);
    } else if (foodtime<60) {
      text ("NOT YET!", 80, 100);
    }
  } else if (opacity3 == 300 && foodtime < 90 && foodtime > 60 && dist_drop > 100 ) {
    pushStyle();
    tint(255, 255, 255, opacity3);
    image(success, 300, 300, 200, 200);
    popStyle();
    pushStyle();
    tint(0, 0, 0, opacity3-280);
    image(shiitake1, handX-60, handY+20, 30, 30);
    popStyle();
  } else if (opacity3 == 300 && foodtime > 90 && dist_drop > 100) {
    pushStyle();
    tint(255, 255, 255, opacity3);
    image(fail, 300, 300, 200, 200);
    popStyle();
    pushStyle();
    tint(0, 0, 0, opacity3);
    image(shiitake1, handX-60, handY+20, 30, 30);
    popStyle();
  } else if (opacity3 == 300 && foodtime > 1 && foodtime < 60 && dist_drop > 100) {
    pushStyle();
    tint(255, 255, 255, opacity3);
    image(fail, 300, 300, 200, 200);
    popStyle();
  }
  if (opacity3 == 300 && HG < 0.5) {
    foodtime = 0;
    opacity3 = 0;
  }

  // ====  crab ==== //
  if (opacity4 == 0) {
    if (dist4 < 50 && HG > 0.6) {
      opacity4 = 300;
    }
  }
  if (opacity4 == 300 && dist_drop < 100) {
    fill(0, 0, 0);
  text(foodtime/3, 510, 70);
    foodtime ++;
    println(foodtime); 
    stroke(10);
    fill(255);
    if (foodtime>90) {
      fill (232, 42, 6);
      text ("OVER COOKED!", 220, 100);
    } else if (foodtime>60 & foodtime<90) {
      fill(232, 118, 80);
      text ("READY!", 190, 100);
    } else if (foodtime<60) {
      text ("NOT YET!", 80, 100);
    }
  } else if (opacity4 == 300 && foodtime < 90 && foodtime > 60 && dist_drop > 100 ) {
    pushStyle();
    tint(255, 255, 255, opacity4);
    image(success, 300, 300, 200, 200);
    popStyle();
    pushStyle();
    tint(0, 0, 0, opacity4-280);
    image(crab1, handX-60, handY+20, 40, 50);
    popStyle();
  } else if (opacity4 == 300 && foodtime > 90 && dist_drop > 100) {
    pushStyle();
    tint(255, 255, 255, opacity4);
    image(fail, 300, 300, 200, 200);
    popStyle();
    pushStyle();
    tint(0, 0, 0, opacity4);
    image(crab1, handX-60, handY+20, 40, 50);
    popStyle();
  } else if (opacity4 == 300 && foodtime > 1 && foodtime < 60 && dist_drop > 100) {
    pushStyle();
    tint(255, 255, 255, opacity4);
    image(fail, 300, 300, 200, 200);
    popStyle();
  }
  if (opacity4 == 300 && HG < 0.5) {
    foodtime = 0;
    opacity4 = 0;
  }


  // ====  goat ==== //
  if (opacity5 == 0) {
    if (dist5 < 50 && HG > 0.6) {
      opacity5 = 300;
    }
  }
  if (opacity5 == 300 && dist_drop < 100) {
    fill(0, 0, 0);
  text(foodtime/7, 510, 70);
    foodtime ++;
    println(foodtime); 
    stroke(10);
    fill(255);
    if (foodtime>90) {
      fill (232, 42, 6);
      text ("OVER COOKED!", 220, 100);
    } else if (foodtime>60 & foodtime<90) {
      fill(232, 118, 80);
      text ("READY!", 190, 100);
    } else if (foodtime<60) {
      text ("NOT YET!", 80, 100);
    }
  } else if (opacity5 == 300 && foodtime < 90 && foodtime > 60 && dist_drop > 100 ) {
    pushStyle();
    tint(255, 255, 255, opacity5);
    image(success, 300, 300, 200, 200);
    popStyle();
    pushStyle();
    tint(0, 0, 0, opacity5-280);
    image(goat1, handX-60, handY+20, 50, 50);
    popStyle();
  } else if (opacity5 == 300 && foodtime > 90 && dist_drop > 100) {
    pushStyle();
    tint(255, 255, 255, opacity5);
    image(fail, 300, 300, 200, 200);
    popStyle();
    pushStyle();
    tint(0, 0, 0, opacity5);
    image(goat1, handX-60, handY+20, 50, 50);
    popStyle();
  } else if (opacity5 == 300 && foodtime > 1 && foodtime < 60 && dist_drop > 100) {
    pushStyle();
    tint(255, 255, 255, opacity5);
    image(fail, 300, 300, 200, 200);
    popStyle();
  }
  if (opacity5 == 300 && HG < 0.5) {
    foodtime = 0;
    opacity5 = 0;
  }


  // ==== meatball ==== //
  if (opacity6 == 0) {
    if (dist6 < 50 && HG > 0.6) {
      opacity6 = 300;
    }
  }
  if (opacity6 == 300 && dist_drop < 100) {
    fill(0, 0, 0);
  text(foodtime/4, 510, 70);
    foodtime ++;
    println(foodtime); 
    stroke(10);
    fill(255);
    if (foodtime>90) {
      fill (232, 42, 6);
      text ("OVER COOKED!", 220, 100);
    } else if (foodtime>60 & foodtime<90) {
      fill(232, 118, 80);
      text ("READY!", 190, 100);
    } else if (foodtime<60) {
      text ("NOT YET!", 80, 100);
    }
  } else if (opacity6 == 300 && foodtime < 90 && foodtime > 60 && dist_drop > 100 ) {
    pushStyle();
    tint(255, 255, 255, opacity6);
    image(success, 300, 300, 200, 200);
    popStyle();
    pushStyle();
    tint(0, 0, 0, opacity6-280);
    image(meatball1, handX-60, handY+20, 30, 30);
    popStyle();
  } else if (opacity6 == 300 && foodtime > 90 && dist_drop > 100) {
    pushStyle();
    tint(255, 255, 255, opacity6);
    image(fail, 300, 300, 200, 200);
    popStyle();
    pushStyle();
    tint(0, 0, 0, opacity6);
    image(meatball1, handX-60, handY+20, 30, 30);
    popStyle();
  } else if (opacity6 == 300 && foodtime > 1 && foodtime < 60 && dist_drop > 100) {
    pushStyle();
    tint(255, 255, 255, opacity6);
    image(fail, 300, 300, 200, 200);
    popStyle();
  }
  if (opacity6 == 300 && HG < 0.5) {
    foodtime = 0;
    opacity6 = 0;
  }
}

import de.voidplus.leapmotion.*;

LeapMotion leap;

void leapMotion_setup() {

  leap = new LeapMotion(this);
  
}


// ======================================================
// 1. Callbacks

void leapOnInit() {
  // println("Leap Motion Init");
}
void leapOnConnect() {
  // println("Leap Motion Connect");
}
void leapOnFrame() {
  // println("Leap Motion Frame");
}
void leapOnDisconnect() {
  // println("Leap Motion Disconnect");
}
void leapOnExit() {
  // println("Leap Motion Exit");
}


void leapMotion_draw() {

  int fps = leap.getFrameRate();
  for (Hand hand : leap.getHands ()) {


    // ==================================================
    // 2. Hand

    int     handId             = hand.getId();
    PVector handPosition       = hand.getPosition();
    PVector handStabilized     = hand.getStabilizedPosition();
    PVector handDirection      = hand.getDirection();
    PVector handDynamics       = hand.getDynamics();
    float   handRoll           = hand.getRoll();
    float   handPitch          = hand.getPitch();
    float   handYaw            = hand.getYaw();
    boolean handIsLeft         = hand.isLeft();
    boolean handIsRight        = hand.isRight();
    float   handGrab           = hand.getGrabStrength();
    float   handPinch          = hand.getPinchStrength();
    float   handTime           = hand.getTimeVisible();
    PVector spherePosition     = hand.getSpherePosition();
    float   sphereRadius       = hand.getSphereRadius();

    // --------------------------------------------------
    // Drawing
    //hand.draw();
    
    handX = hand.getPosition().x;
    handY = hand.getPosition().y;
    
    HG = handGrab;

    // ==================================================
    // 3. Arm

    if (hand.hasArm()) {
      Arm     arm              = hand.getArm();
      float   armWidth         = arm.getWidth();
      PVector armWristPos      = arm.getWristPosition();
      PVector armElbowPos      = arm.getElbowPosition();
    }


    // ==================================================
    // 4. Finger

    Finger  fingerThumb        = hand.getThumb();
    // or                        hand.getFinger("thumb");
    // or                        hand.getFinger(0);

    Finger  fingerIndex        = hand.getIndexFinger();
    // or                        hand.getFinger("index");
    // or                        hand.getFinger(1);

    Finger  fingerMiddle       = hand.getMiddleFinger();
    // or                        hand.getFinger("middle");
    // or                        hand.getFinger(2);

    Finger  fingerRing         = hand.getRingFinger();
    // or                        hand.getFinger("ring");
    // or                        hand.getFinger(3);

    Finger  fingerPink         = hand.getPinkyFinger();
    // or                        hand.getFinger("pinky");
    // or                        hand.getFinger(4);
    
    
    


    for (Finger finger : hand.getFingers()) {
      // or              hand.getOutstretchedFingers();
      // or              hand.getOutstretchedFingersByAngle();

      int     fingerId         = finger.getId();
      PVector fingerPosition   = finger.getPosition();
      PVector fingerStabilized = finger.getStabilizedPosition();
      PVector fingerVelocity   = finger.getVelocity();
      PVector fingerDirection  = finger.getDirection();
      float   fingerTime       = finger.getTimeVisible();

      // ------------------------------------------------
      // Drawing

      // Drawing:
      // finger.draw();  // Executes drawBones() and drawJoints()
      //finger.drawBones();
      //finger.drawJoints();

      // ------------------------------------------------
      // Selection

      


      // ================================================
      // 5. Bones
      // --------
      // https://developer.leapmotion.com/documentation/java/devguide/Leap_Overview.html#Layer_1

      Bone    boneDistal       = finger.getDistalBone();
      // or                      finger.get("distal");
      // or                      finger.getBone(0);

      Bone    boneIntermediate = finger.getIntermediateBone();
      // or                      finger.get("intermediate");
      // or                      finger.getBone(1);

      Bone    boneProximal     = finger.getProximalBone();
      // or                      finger.get("proximal");
      // or                      finger.getBone(2);

      Bone    boneMetacarpal   = finger.getMetacarpalBone();
      // or                      finger.get("metacarpal");
      // or                      finger.getBone(3);

      // ------------------------------------------------
      // Touch emulation

      int     touchZone        = finger.getTouchZone();
      float   touchDistance    = finger.getTouchDistance();

      switch(touchZone) {
      case -1: // None
        break;
      case 0: // Hovering
        // println("Hovering (#" + fingerId + "): " + touchDistance);
        break;
      case 1: // Touching
        // println("Touching (#" + fingerId + ")");
        break;
      }
    }


    // ==================================================
    // 6. Tools

    for (Tool tool : hand.getTools()) {
      int     toolId           = tool.getId();
      PVector toolPosition     = tool.getPosition();
      PVector toolStabilized   = tool.getStabilizedPosition();
      PVector toolVelocity     = tool.getVelocity();
      PVector toolDirection    = tool.getDirection();
      float   toolTime         = tool.getTimeVisible();

      // ------------------------------------------------
      // Drawing:
       tool.draw();

      // ------------------------------------------------
      // Touch emulation

      int     touchZone        = tool.getTouchZone();
      float   touchDistance    = tool.getTouchDistance();

      switch(touchZone) {
      case -1: // None
        break;
      case 0: // Hovering
        // println("Hovering (#" + toolId + "): " + touchDistance);
        break;
      case 1: // Touching
        // println("Touching (#" + toolId + ")");
        break;
      }
    }
  }


  // ====================================================
  // 7. Devices

  for (Device device : leap.getDevices()) {
    float deviceHorizontalViewAngle = device.getHorizontalViewAngle();
    float deviceVericalViewAngle = device.getVerticalViewAngle();
    float deviceRange = device.getRange();
  }
}