shuann-Body

Link to app: https://detailed-feet.glitch.me/

GIF:

Sketch:

My original idea was pretty different from what I eventually finished. Originally I wanted to create a drawing tool that one can draw with his/her pupils. The line would trace where the eye had been and the entire canvas would erase itself if the person blinks. However, I was having trouble to distinguish different state of the eyes with the face tracking templet code and decided to go to a different direction.

Then the new idea I had was to use the cereal head movement to control a basic character. I first thought of the more conventional multiple level of floors that a character could be placed into by change the vertical position of the head. However I realized that did not make much sense since I want to use head turn to trigger "jump". The left&right motion does not naturally map to the up&down motion of the jump. Therefore I redesigned the floor to be vertical and have the character run up the screen to avoid obstacles. That been said, this not a game yet as it does not have any level design, no goals to achieve, etc. As it for now, it's more like an exploration on the kind of controllers that can be implemented. If there is more time, I would like to turn this into a game that two people can play against each other at the same time.

Still Image:

 Video:

var local;
var obs = [];
var dir = [1, -1];
var player1 = null;
var stuck = false;
var score1 = 0;
var vel = 8;
 
var from;
var to;
var bgcX = 0;
 
function setup() {
 
  createCanvas(640, 480);
  background(0);
 
  //this is where posenet initlizes and webcam stuff happens
  PoseZero.init();
 
  //this is you, check out agent.js for adding properties and functions
  local = new Agent();
 
  player1 = new player(width/2,height*2/3,random(dir));
  obs[0] = new obstacle(width/2, height/2, random(15,21), random(dir));
  obs[1] = new obstacle(width/2, height/3, random(15,21), random(dir));
 
}
 
function draw() {
  background(255);
 
	local.update(PoseZero.get());// update your skeleton
 
  push();
  if (local.data.pose != null){ 
    push();
    if (player1.dir === 1){
      bgcX = width/2;
      from = color(255,100,147);
      to = color(255,182,193);
    }
    if (player1.dir === -1){
      bgcX = 0;
      from = color(255,182,193);
      to = color(255,100,147);
    }
    noStroke();
    fill(150);
    var widthRect = width/40;
    noStroke();
    for (var i=0;i<20;i++){
      inter = lerpColor(from,to,(i+1)*(1/20));
      fill(inter);
      rect(bgcX + i*widthRect,0,widthRect,height);
    }
    pop();
 
    PoseZero.draw_pose(local.data.pose,{color:local.data.color})
 
    if (player1.dir === 1){
      text("shake your head RIGHT" , width/2 + 170, height - 20);
    }
    if (player1.dir === -1){
      text("shake your head LEFT ", 20, height - 20);
    }
 
    push();
    drawPlayground();
 
    palceObs();
    boundaryCheck();
    speedCheck();
 
    if (player1.stuck() === false){
      for (var elem = 0; elem < obs.length; elem ++){
        obs[elem].draw();
        obs[elem].move();
      }
    } else {
      for (var elem = 0; elem < obs.length; elem ++){ obs[elem].draw(); } } player1.draw(); player1.checkDir(); player1.headTurn(); pop(); } pop(); } function palceObs(){ if (frameCount % 15 == 0){ if (obs[obs.length - 1].y != -20){ obs.push(new obstacle(width/2, -20, random(15,21), random(dir))); } } } function boundaryCheck(){ if (obs[0].y >= height){
    obs.shift();
  }  
}
 
function speedCheck(){
  var closeness = PoseZero.estimate_scale(local.data.pose);
 
  if (closeness <= 70 && closeness > 40) {
    vel = 8;
  }
 
  if (closeness <= 100 && closeness > 70) {
    vel = 11;
  }
 
  if (closeness <= 120 && closeness > 100) {
    vel = 14;
  }
}
 
function drawPlayground(){
  var road = width/2;
  strokeWeight(4);
  line(road, 0, road, height);
 
}
 
function obstacle(x,y,s,dir){
  this.x = x;
  this.y = y;
  this.dir = dir;
  this.s = s;
  this.r = int(random(240,255));
	this.g = int(random(30,200));
	this.b = int(random(50,69));
 
  this.draw = function(){
    push();
    stroke(0);
		strokeWeight(4);
		fill(this.r,this.g,this.b);
    if (this.dir == 1){
      rect(this.x, this.y, this.s * 4, 20, 30);
      for (var a=0; a<4; a++){
        push();
        stroke(250);
			  line(this.x + 6 + 15*a, this.y + 3, this.x + 15*a + 15, this.y + 17);
        pop();
		  }
    } else {
      rect(this.x - this.s * 4, this.y, this.s * 4, 20, 30);
      for (var b=0; b<4; b++){
        push();
        stroke(250);
			  line(this.x + 6 + 15*b - this.s * 4, this.y + 3, this.x + 15*b + 15 - this.s * 4, this.y + 17);
        pop();
		  }
    }
    pop();
  }
 
  this.move = function(){
    this.y += vel;
  } 
}
 
function player(x,y,dir){
  this.x = x;
  this.y = y;
  this.dir = dir;
  this.h = 50;
  this.w = 30;
  this.leg = 15;
  this.vel = 10;
  var triX;
  var jumpR = false;
  var toppedR = false;
  var jumpL = false;
  var toppedL = false;
 
  this.draw = function(){
    // console.log(this.dir);
    if (this.dir == -1) {
      triX = this.x - this.leg;
    } else {
      triX = this.x + this.leg;
    }
    push();
    strokeJoin(ROUND);
    strokeWeight(4);
    stroke(255);
    fill(255, 209, 124);
    line(triX + this.h*3/4 * this.dir, this.y + this.w/2, this.x + this.dir * 5, this.y + this.w/2);
    triangle(triX, this.y, triX + this.h * this.dir, this.y + this.w/2, triX, this.y + this.w);
    ellipse(triX + this.h*3/4 * this.dir, this.y + this.w/2, this.leg*2 , this.leg*2);
    stroke(0);
    line(triX + (this.h*7/8 - 4) * this.dir, this.y + this.w/2 - 6, triX + this.h*6/8 * this.dir, this.y + this.w/2 - 6);
    line(triX + (this.h*7/8 - 4) * this.dir, this.y + this.w/2 + 6, triX + this.h*6/8 * this.dir, this.y + this.w/2 + 6);
    pop();
  }
 
  this.checkDir = function(){
    var playerPos = PoseZero.nosePosX(local.data.pose);
 
    if (playerPos < width/2) {
      this.dir = -1;
    } else {
      this.dir = 1;
    }
  }
 
  this.headTurn = function(){
    //check for jumps
    if (PoseZero.rightTurn(local.data.pose) && this.dir == 1){
      jumpR = true;
    }
    if (PoseZero.leftTurn(local.data.pose) && this.dir == -1){
      jumpL = true;
    }
 
    if (jumpR === true){
      this.jumpRight();
    } 
    if (jumpL === true){
      this.jumpLeft();
    }
  }
 
  //Right jump animation
  this.jumpRight = function(){
    if (toppedR === false && this.x < width/2 + 100){ this.x += this.vel; if (this.x >= width/2 + 100) {
        toppedR = true;
      }
    } 
    if (toppedR === true && this.x != width/2){
      this.x -= this.vel;
      if (this.x <= width/2) { this.x = width/2; jumpR = false; toppedR = false; } } } //Left jump animation this.jumpLeft = function(){ if (toppedL === false && this.x > width/2 - 100){
      this.x -= this.vel;
      if (this.x <= width/2 - 100) { toppedL = true; } } if (toppedL === true && this.x != width/2){ this.x += this.vel; if (this.x >= width/2) {
        this.x = width/2;
        jumpL = false;
        toppedL = false;
      }
    }
  }
 
  this.stuck = function(){
  //check for obstacles
    for (var elem = 0; elem < obs.length; elem ++){
      var obsTop = obs[elem].y;
      var obsBottom = obs[elem].y + 20;
      var obsOuter = obs[elem].x + obs[elem].s * obs[elem].dir * 4;
      var obsInner = obs[elem].x;
      if (obs[elem].dir == this.dir && obsTop < this.y && obsBottom >= this.y){
        if (this.dir === 1 && this.x <= obsOuter){ return true; } if (this.dir === -1 && this.x >= obsOuter){
          return true;
        }
      }
    }
    return false;
  }
}