Last active
March 14, 2018 17:45
-
-
Save tjthejuggler/61dddba6d67d44cfe4055841d70e233c to your computer and use it in GitHub Desktop.
tobii eyetracker game
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| //YOU NEED AN IMAGE OF A CURSOR IN ORDER TO RUN THIS CODE: | |
| //https://cdn.pixabay.com/photo/2012/04/01/12/39/cursor-23231_960_720.png | |
| import gazetrack.*; | |
| import java.awt.Toolkit; | |
| PImage cursor; | |
| GazeTrack gazeTrack; | |
| void setup() | |
| { | |
| fullScreen(); | |
| // Gaze cursor param. | |
| noFill(); | |
| stroke(50, 100); | |
| strokeWeight(4); | |
| rectMode(CENTER); | |
| cursor = loadImage("cursor.png"); | |
| cursor.resize(0,30); | |
| // Create an empty ArrayList (will store Ball objects) | |
| balls = new ArrayList<Ball>(); | |
| // Start by adding one element | |
| //balls.add(new Ball(width/2, 0, ballWidth)); | |
| gazeTrack = new GazeTrack(this, "1"); | |
| } | |
| float score = 1; | |
| float scoreExt = 0; | |
| float scorePosX = width; | |
| int scorePosY = 200; | |
| //float easing = 0; | |
| Boolean currentlyPlaying = true; | |
| Boolean mustLookBack = false; | |
| Boolean yellowUnlocked = false; | |
| int lookingAwayCounter = 0; | |
| Boolean minusExists = false; | |
| int stillnessCounter = 0; | |
| Boolean becameStill = false; | |
| ArrayList<Ball> balls; | |
| int ballWidth = 48; | |
| int fadingScoreFill = 255; | |
| int ballCount = 0; | |
| ArrayList<Float> plusX = new ArrayList<Float>(); | |
| ArrayList<Float> plusY = new ArrayList<Float>(); | |
| ArrayList<Float> minusX = new ArrayList<Float>(); | |
| ArrayList<Float> minusY = new ArrayList<Float>(); | |
| ArrayList<Integer> minusB = new ArrayList<Integer>(); | |
| void mousePressed() { | |
| if(yellowUnlocked){ | |
| // A new ball object is added to the ArrayList (by default to the end) | |
| if (ballCount<600){ | |
| balls.add(new Ball(mouseX, mouseY, ballWidth)); | |
| ballCount++; | |
| } | |
| } | |
| } | |
| Boolean almostWon = false; | |
| Boolean reallyWon = false; | |
| Boolean seenGreen = false; | |
| void draw() | |
| { | |
| if(reallyWon){ | |
| background(0); | |
| //print("You won."); | |
| fill(0,0,255); | |
| textAlign(CENTER,CENTER); | |
| textSize(50); | |
| text("Actually, you won.", 800, 370); | |
| }else{ | |
| if(almostWon){ | |
| //print("almost won"); | |
| fill(0,255,0); | |
| textAlign(CENTER,CENTER); | |
| textSize(50); | |
| text("You almost won!", 800, 370); | |
| text("Turn head to play", 800, 450); | |
| stroke(0,255,0); | |
| line(600, 455,1000,455); | |
| text("look rapidly from side to side.", 800, 530); | |
| if(eyeShake()){//this checks to see if they have looked back and forth rapidly | |
| print("eyeShook"); | |
| clear(); | |
| balls.clear(); | |
| currentlyPlaying = true; | |
| stillnessCounter = 0; | |
| becameStill = false; | |
| fadingScoreFill = 255; | |
| ballCount = 0; | |
| score = 1; | |
| scoreExt = 0; | |
| almostWon = false; | |
| seenGreen = true; | |
| } | |
| }else{ | |
| if(fadingScoreFill < 2){ | |
| //if(wtf){ | |
| score = 5; | |
| if(!becameStill){ | |
| if (random(100)>70){ | |
| if (ballCount<600){ | |
| balls.add(new Ball(random(width), random(height), ballWidth)); | |
| ballCount++; | |
| } | |
| } | |
| }else{ | |
| if(ballCount<3){ | |
| almostWon = true; | |
| } | |
| } | |
| //rectMode(CENTER); | |
| textAlign(RIGHT,TOP); | |
| background(0); | |
| textSize(50); | |
| //easing = 0; | |
| updateBalls(); | |
| }else{ | |
| if (currentlyPlaying){ | |
| if (!gazeTrack.gazePresent()) {//if the player looks away for too long then they lose | |
| lookingAwayCounter++; | |
| if (lookingAwayCounter > 50 && !mustLookBack){ | |
| if (score >1){ | |
| mustLookBack = true; | |
| print("inhere"); | |
| lookingAwayCounter = 0; | |
| youlose(); | |
| } | |
| } | |
| } | |
| //if gazetrack is present | |
| else{ | |
| lookingAwayCounter = 0; | |
| //rectMode(CENTER); | |
| textAlign(RIGHT,TOP); | |
| background(0); | |
| textSize(50); | |
| //easing = 0; | |
| updateBalls(); | |
| //draws the eyes | |
| //fill(255); | |
| //ellipse(gazeTrack.getGazeX(),gazeTrack.getGazeY(),10,10); | |
| if(score>0){ | |
| score = score + .02; | |
| if (score>5){ | |
| if (random(100)>98){ | |
| if (ballCount<600){ | |
| balls.add(new Ball(random(width), random(height), ballWidth)); | |
| ballCount++; | |
| } | |
| } | |
| } | |
| if(score > 9){ | |
| score = score + .08; | |
| //textSize(60); | |
| //easing = .001; | |
| //createPlusAndMinusPositions(); | |
| }else{//if score is less than 9 | |
| scorePosX = width; | |
| scorePosY = 0; | |
| } | |
| if(score > 99){ | |
| score = score+2; | |
| //textSize(70); | |
| //easing = .002; | |
| } | |
| if(score > 999){ | |
| //textSize(150); | |
| //easing = .003; | |
| } | |
| //float dx = gazeTrack.getGazeX() - scorePosX; | |
| //scorePosX += dx * easing; | |
| //float dy = gazeTrack.getGazeY() - scorePosY; | |
| //scorePosY += dy * easing; | |
| //print("width =" + width); | |
| //print("scorePosX ="+scorePosX); | |
| //IDEA: | |
| // once the score fades away the new circles made could just start going to random corners when | |
| // looked at, but once none have been looked at for awhile, that is when they quit being made | |
| fill(255,0,0); | |
| }else{//if the score is less than 0 | |
| score = score + .02; | |
| if (random(100)>90){ | |
| if(fadingScoreFill>1){ | |
| if (ballCount<600){ | |
| balls.add(new Ball(random(width), random(height), ballWidth)); | |
| ballCount++; | |
| } | |
| } | |
| } | |
| fill(255); | |
| } | |
| if(fadingScoreFill<255){ | |
| fill(fadingScoreFill); | |
| fadingScoreFill= max(0,fadingScoreFill-3); | |
| } | |
| textAlign(RIGHT,TOP); | |
| textSize(50); | |
| if(scoreExt>0){ | |
| text("Score: " + str(int(score))+ str(int(scoreExt)), scorePosX, scorePosY); | |
| }else{ | |
| text("Score: " + str(int(score)), scorePosX, scorePosY); | |
| } | |
| if (dist(gazeTrack.getGazeX(), gazeTrack.getGazeY(),scorePosX, scorePosY) < 200){ | |
| if (score > 0){ | |
| youlose(); | |
| }else{ | |
| if(fadingScoreFill>254){ | |
| print("fadingScoreFill"); | |
| fadingScoreFill = 254; | |
| } | |
| } | |
| } | |
| // Print the tracker's timestamp for the gaze cursor above | |
| //println("Latest gaze data at: " + gazeTrack.getTimestamp()); | |
| } | |
| //if not currently playing | |
| }else{ | |
| if(gazeTrack.gazePresent()){ | |
| mustLookBack = false; | |
| if(eyeShake()){ | |
| reallyWon = true; | |
| } | |
| }else{ | |
| if (!mustLookBack){ | |
| clear(); | |
| currentlyPlaying = true; | |
| //print("dointhis"); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| int framesSinceRight = 200; | |
| int framesSinceRightLeft = 200; | |
| int framesSinceRightLeftRight= 200; | |
| int framesSinceRightLeftRightLeft =200; | |
| int framesSinceRightLeftRightLeftRight =200; | |
| int framesSinceRightLeftRightLeftRightLeft = 200; | |
| Boolean eyeShake(){ | |
| if (gazeTrack.getGazeX()>width*.75 && | |
| framesSinceRightLeft > 200 && | |
| framesSinceRightLeftRight > 200 && | |
| framesSinceRightLeftRightLeft > 200 && | |
| framesSinceRightLeftRightLeftRight > 200){ | |
| framesSinceRight=0; | |
| }else{ | |
| framesSinceRight++; | |
| } | |
| if (gazeTrack.getGazeX()<width*.25 && | |
| framesSinceRight < 200){ | |
| framesSinceRightLeft = 0; | |
| }else{ | |
| framesSinceRightLeft++; | |
| } | |
| if (gazeTrack.getGazeX()>width*.75 && | |
| framesSinceRight < 200 && | |
| framesSinceRightLeft < 200){ | |
| framesSinceRightLeftRight = 0; | |
| }else{ | |
| framesSinceRightLeftRight++; | |
| } | |
| if (gazeTrack.getGazeX()<width*.25 && | |
| framesSinceRight < 200 && | |
| framesSinceRightLeft < 200 && | |
| framesSinceRightLeftRight < 200){ | |
| framesSinceRightLeftRightLeft = 0; | |
| }else{ | |
| framesSinceRightLeftRightLeft++; | |
| } | |
| if (gazeTrack.getGazeX()>width*.75 && | |
| framesSinceRight < 200 && | |
| framesSinceRightLeft < 200 && | |
| framesSinceRightLeftRight < 200 && | |
| framesSinceRightLeftRightLeft < 200){ | |
| framesSinceRightLeftRightLeftRight = 0; | |
| }else{ | |
| framesSinceRightLeftRightLeftRight++; | |
| } | |
| if (gazeTrack.getGazeX()<width*.25 && | |
| framesSinceRight < 200 && | |
| framesSinceRightLeft < 200 && | |
| framesSinceRightLeftRight < 200 && | |
| framesSinceRightLeftRightLeft < 200 && | |
| framesSinceRightLeftRightLeftRight < 200){ | |
| return true; | |
| }else{ | |
| return false; | |
| } | |
| } | |
| void updateBalls(){ | |
| //print("updat"); | |
| // With an array, we say balls.length, with an ArrayList, we say balls.size() | |
| // The length of an ArrayList is dynamic | |
| // Notice how we are looping through the ArrayList backwards | |
| // This is because we are deleting elements from the list | |
| for (int i = balls.size()-1; i >= 0; i--) { | |
| // An ArrayList doesn't know what it is storing so we have to cast the object coming out | |
| Ball ball = balls.get(i); | |
| //ball.move(); | |
| ball.display(); | |
| if (ball.seen){ | |
| ball.move(); | |
| }else{ | |
| ball.checkIfSeen(); | |
| } | |
| if (ball.finished()) { | |
| // Items can be deleted with remove() | |
| balls.remove(i); | |
| ballCount--; | |
| } | |
| } | |
| } | |
| void youlose(){ | |
| clear(); | |
| balls.clear(); | |
| currentlyPlaying = false; | |
| yellowUnlocked = false; | |
| stillnessCounter = 0; | |
| becameStill = false; | |
| fadingScoreFill = 255; | |
| ballCount = 0; | |
| fill(255,0,0); | |
| textAlign(CENTER,CENTER); | |
| textSize(50); | |
| text("You win!", 800, 370); | |
| stroke(255,0,0); | |
| line(700, 380,900,380); | |
| stroke(0); | |
| text("You lose!", 800, 450); | |
| if (scoreExt>0){ | |
| text("Score: "+str(int(score))+str(int(scoreExt)), 800, 530); | |
| }else{ | |
| text("Score: "+str(int(score)), 800, 530); | |
| } | |
| text("Turn head to play.", 800, 610); | |
| score = 1; | |
| scoreExt = 0; | |
| framesSinceRight = 200; | |
| framesSinceRightLeft = 200; | |
| framesSinceRightLeftRight= 200; | |
| framesSinceRightLeftRightLeft =200; | |
| framesSinceRightLeftRightLeftRight =200; | |
| framesSinceRightLeftRightLeftRightLeft = 200; | |
| } | |
| class Ball { | |
| float x; | |
| float y; | |
| float speed; | |
| float gravity; | |
| float w; | |
| float life = 255; | |
| boolean seen = false; | |
| boolean minus = false; | |
| boolean isYellow = false; | |
| int age = 0; | |
| Ball(float tempX, float tempY, float tempW) { | |
| x = tempX; | |
| y = tempY; | |
| w = tempW; | |
| speed = 0; | |
| //print(random(2)); | |
| gravity = 0.1; | |
| if(yellowUnlocked && random(10)>8){ | |
| isYellow = true; | |
| } | |
| if(random(2)>1){ | |
| minus = true; | |
| } | |
| } | |
| void move() { | |
| if(!isYellow){ | |
| // Add gravity to speed | |
| speed = speed + gravity; | |
| // Add speed to y location | |
| if(fadingScoreFill>5){ | |
| if (y>0){ | |
| y = y - speed; | |
| } | |
| if (x<width+1){ | |
| x = x + speed; | |
| } | |
| }else{//this is how the balls move if the score is currently faded | |
| if(x<3 || y<3 || x>width-3 || y>height-3){ | |
| life = -1;//this will get it finished, if i put finished in here it breaks | |
| } | |
| if(y<height/2){ | |
| if (y>0){ | |
| y = y - speed; | |
| } | |
| }else{ | |
| if (y<height+1){ | |
| y = y + speed; | |
| } | |
| } | |
| if(x<width/2){ | |
| if (x>0){ | |
| x = x - speed; | |
| } | |
| }else{ | |
| if (x<width+1){ | |
| x = x + speed; | |
| } | |
| } | |
| } | |
| } | |
| //after we move it, we check to see if it is in the corner, | |
| // if it isthen we do the points and make it finished | |
| if(dist(x, y,scorePosX, scorePosY) < 200){ | |
| if (age<100){ | |
| if (score>9){ | |
| score = score/2; | |
| }else if(score<10 && score>0){ | |
| score = score - .5; | |
| }else if(score < 1 && score > -100000){ | |
| score = score - (-score); | |
| } | |
| }else{ | |
| //print("x"+score); | |
| if (score>1000){ | |
| yellowUnlocked = true; | |
| } | |
| if (score<4843672 && score>0){ | |
| score = score+(score/10); | |
| }else if(score>4843672){ | |
| scoreExt++; | |
| scoreExt = scoreExt+(scoreExt/10); | |
| }else if(score<1){ | |
| score = (score/2)+1; | |
| } | |
| //print("z"+score); | |
| } | |
| life = -1;//this means it will be finished | |
| } | |
| } | |
| void checkIfSeen(){ | |
| age++; | |
| //life = 255; | |
| if (dist(gazeTrack.getGazeX(),gazeTrack.getGazeY(), x,y)<80){ | |
| seen = true; | |
| if(fadingScoreFill<5){ | |
| stillnessCounter= 0; | |
| becameStill= false; | |
| } | |
| }else{ | |
| seen = false; | |
| if(fadingScoreFill<5){ | |
| stillnessCounter++; | |
| if (stillnessCounter>300){ | |
| becameStill= true; | |
| } | |
| } | |
| } | |
| } | |
| boolean finished() { | |
| // Balls fade out | |
| if (isYellow){ | |
| life=life-2; | |
| }else{ | |
| life=life-.3; | |
| } | |
| if (life < 0) { | |
| return true; | |
| } else { | |
| return false; | |
| } | |
| } | |
| void display() { | |
| if(fadingScoreFill < 2){ | |
| fill(int(random(255)),int(random(255)),int(random(255))); | |
| ellipse(x,y,w,w); | |
| }else{ | |
| if (isYellow){ | |
| fill(255,255,0); | |
| ellipse(x,y,w,w); | |
| imageMode(CENTER); | |
| image(cursor,x,y); | |
| }else{ | |
| // Display the circle | |
| if (age<100){ | |
| fill(255,life); | |
| }else{ | |
| fill(255,0,0,life); | |
| } | |
| //stroke(0,life); | |
| ellipse(x,y,w,w); | |
| fill(0); | |
| textAlign(CENTER,BOTTOM); | |
| textSize(60); | |
| if (age<100){ | |
| text("-",x,y+30); | |
| }else{ | |
| text("+",x,y+30); | |
| } | |
| } | |
| } | |
| if(seenGreen){ | |
| if(random(50)>48){ | |
| fill(0,255,0); | |
| ellipse(x,y,w,w); | |
| } | |
| } | |
| } | |
| } | |
| //score should slowly become more and more inviting to look at, then it should start moving slowly, | |
| // once it is moving fast enough to actually be a threat it should no longer be deadly, | |
| // once it touches you it goes away, maybe it would be best to make it so that as soon as a certain | |
| // new badguy shows up it no longer is dangerous. YES! The deadliness moves from the score to | |
| // something that is obviously bad, a red X, over time the red X fades white and has a number | |
| // beside it, this number makes your score go crazy high(At this point the score has returned to its | |
| // purch) | |
| //when the score is getting higher and higher it should also get bigger and bigger and eventually snuff out the player | |
| //as your score gets bigger it could start moving, maybe even chasing you down. Score size | |
| // could be directly related to score | |
| //it would be cool if the score got more and more snakelike as it got longer as it chases your | |
| // eyes around screen | |
| //after a certain score it is ok that the score gets you, maybe shortly after that the score could totaly | |
| // fade away. maybe everything could eventually fade away and you just have to keep doing | |
| // stuff on a blank screen, maybe then eventually things start coming back. | |
| //maybe we want to have really old balls fade away so they dont just stay there reminding us of bad | |
| // calibration | |
| //maybe we want to have some thing that you only get if you go high, like a new color ball, | |
| // you must have unlocked the new color ball before going negative and looking at the score to | |
| // go to the next round |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment