Task:
Create a screen-based interactive game that utilizes “abstract” buttons and poseNet. The sketch needs to demonstrate proper use of object-oriented programming concept as well.
Inspiration:
I wanted to create a space shooter/space invader type game where the player controls the spaceship which shoots bullets to hit targets.
I plan on utilizing Posenet by using face coordinates to control the space ship.
Final Product:
Progress:
I started off by creating a spaceship, as soon as Posenet detects a face it will use the nose coordinates to create a ellipse that fires particles. which is defined as a class named particle()
Then I made it more game like by adding a new class named enemy(). By shooting the enemy with particles, they will be removed from the game and score will go up.
I then added the ability to fire at an angle by tilting your head. I achieved this through calculating the difference between the y value of the left and right eye, then I smooth out the difference value by dividing so that it is not sensitive. The player should be able to shoot straight upwards without keeping their head perfectly still.
The last change I made to the game is adding an “abstract button”, I decided to change the game so that particles would only be fired when the right hand is held upwards.
Reflection:
I am very surprised by how much interaction and immersion posenet can bring to a simple game by setting the controls to human movement as opposed to keyboard/mouse interaction. I ran into a lot of problems when creating this project, I wanted to add sound and sprites to the project to make it look more polished, but my computer/browser does not load things properly. The macbook’s camera also turns off from time to time making debugging difficult. The mechanic of firing with hand position is also very glitchy cause it either gets in the way of face detection, or it goes outside of the frame captured by the camera. Aside from the problems, I think just with what I have right now it is already a game that is fun to play. I believe by adding sound/sprites and more levels/power-ups/types of enemies, this can be a really fun game.
Final Code:
console.log("ml - ",ml5.version);
let particles = [];
let targets = [];
let cam;
let img;
let poses = [];
var timer = 0;
let score = 0;
function setup(){
createCanvas(700,600);
background(0);
cam = createCapture(VIDEO);
//img.resize(10, 10);
//imageMode(CENTER);
//cam.size(1000,800);
//cam.hide();
textSize(32);
poseNet = ml5.poseNet(cam,modelReady);
poseNet.on('pose',function(results){poses = results});
}
function modelReady(){
console.log("model loaded");
}
function draw(){
timer +=1;
if (timer >=100){
timer=0;
targets.push(new enemy());
}
background(0);
fill(255,255,255);
text('score: '+score, width/2-50,50 );
//image(img, 0, 0);
//image(cam,0,0);
//tint(0,0,0,100);
for (let i = 0; i<poses.length;i++ ){
//console.log(poses[i].pose.nose);
//particles.push(new Particle(poses[i].pose.nose.x,poses[i].pose.nose.y));
console.log(poses[i]);
//image(img,width - poses[i].pose.nose.x,height*3/4);
ellipse(width - poses[i].pose.nose.x,height*3/4,10,10);
fill(0,0,255);
//ellipse(width - poses[i].pose.rightEye.x,poses[i].pose.rightEye.y,10,10);
//ellipse(width - poses[i].pose.leftEye.x,poses[i].pose.leftEye.y,10,10);
//ellipse(width - poses[i].pose.rightWrist.x,poses[i].pose.rightWrist.y,10,10);
//ellipse(width - poses[i].pose.leftWrist.x,poses[i].pose.leftWrist.y,10,10);
var angle = poses[i].pose.rightEye.y - poses[i].pose.leftEye.y;
angle = int(angle/10);
console.log(angle);
if (poses[i].pose.rightWrist.y < 350){
particles.push(new Particle(width - poses[i].pose.nose.x,height*3/4,angle));
}
}
//console.log(particles.length);
//particles.push(new Particle(width/2,height/2));
for (let i = 0; i<particles.length;i++ ){
particles[i].move();
for (let i = 0; i<poses.length;i++ ){
//particles[i].checkinteraction(width-poses[i].pose.nose.x,height*3/4);
}
particles[i].display();
}
for (let i = particles.length-1; i>=0;i-- ){
particles[i].checkedge();
if (particles[i].isDone){
particles.splice(i,1);
}
}
//console.log(targets);
for (let i = targets.length-1; i>=0;i-- ){
targets[i].checkedge();
targets[i].move();
targets[i].display();
if (targets[i].isDone){
targets.splice(i,1);
}
}
//check collision
for (let i = targets.length-1; i>=0;i-- ){
for (let b = particles.length-1; b>=0;b-- ){
check(targets[i],particles[b])
}
}
while (particles.length >500){
particles.splice(0,1); //index,num of element
}
}
function check(target,bullet){
let distance = dist(target.x,target.y,bullet.x,bullet.y);
if (distance <= 17){
target.isDone = true;
bullet.isDone = true;
score += 100;
}
}
function mousePressed(){
//particles.push(new Particle(random(width),height-10));
}
class enemy{
constructor(){
this.x = random(10,width-10);
this.y = 5;
this.xspd = 0;
this.yspd = 2;
this.rad = 20;
this.isDone = false;
}
move(){
this.x += this.xspd;
this.y += this.yspd;
}
checkedge(){
if (this.x < 0 || this.x > width){
this.isDone = true;
}
if (this.y < 0 || this.y > height){
this.isDone = true;
}
}
display(){
push();
strokeWeight(0);
fill(0,0,255);
ellipse(this.x,this.y,this.rad*2,this.rad*2);
pop();
}
}
class Particle {
constructor(x,y,angle) {
this.x = x;
this.y = y;
this.xspd = angle;
this.yspd = -5;
this.rad = 2;
this.color = [random(200,255),random(50,200),random(10),random(100,300)];
this.isDone = false;
}
checkinteraction(x,y){
let distance = dist(this.x,this.y,x,y);
if (distance < this.rad + 25){
this.color = [0,0,255];
}
else{
this.color = [distance,(distance/4)+200,255];
}
}
move(){
this.x += this.xspd;
this.y += this.yspd;
}
checkedge(){
if (this.x < 0 || this.x > width){
this.isDone = true;
}
if (this.y < 0 || this.y > height){
this.isDone = true;
}
}
display(){
push();
strokeWeight(0);
fill(this.color[0],this.color[1],this.color[2]);
ellipse(this.x,this.y,this.rad*2,this.rad*2);
pop();
}
}