Final Project Review
My final project was meant to be a very loosely based game on collecting water and watching a plant grow and having a real life replica of the plant mimicking this movement.
Initial screen:
The first stage:
The second stage:
Final screen:
The layout at the showcase:
After the user-testing I did in class and outside of it, I realized some fundamental problems with the game. Firstly, the motive of the game was not really clear to the people interacting with it until after they started the game; however, by that point it was pretty intuitive that they had to move the plant in real life to see the change on screen. Also, I felt as if labelling the project a ‘game’ implied that there was a way to win (getting a certain number of drops within a certain number of time); therefore, when there was no real indication if people won or loss, they kind of didn’t know what to do. This was an error on my part as I should’ve made a very clear winning/losing situation or just a win-win situation but with a more obvious ending. For this, I wanted a flower to grow to portray the final stage of growth but I didn’t know how I could implement this in the short amount of time I had considering I would have to change a lot of the code.
I think what did work was the implementation of handles on the pot, this was a clear indicator that people had to hold it from both sides. The arrows on the board it rested on, also helped. Moreover, once people did start, a lot of them appreciated the calmness they felt in doing the act and a lot go gasps of excitement were heard when the plant did grow on screen. A few people commented on the good color palette/’clean’ look of the whole experiment and I felt very proud of that because neatness is pretty important to me personally. Another viewer also commented how the movement of this game closely resembled activities that are used with patients that are exercising mobility of body parts and how this could extend to that application which I found very, very cool.
Personally, although a few aspects of the project did not end up looking like I had hoped they would, I have never felt more proud being present around people looking at my work and smiling/laughing because of it — it felt amazing. It especially felt great when Craig and Sarah told me I should be proud of myself and I was! — I worked on this code for 2 weeks straight (with help) but also did most of it by myself which I never thought I would be able to say about something that looked like this. I think that’s something that this course taught me, there’s a lot of stuff I CAN do, I just need to stop telling myself that I can’t. So overall, I know there’s a lot to be improved upon but I think I’m still pretty happy with the result. With special thanks to Aaron, Jack, Ali, Yousra, the UNIX lab and Daniel Shiffman.
Code:
Game
import processing.video.*; import jp.nyatla.nyar4psg.*; Capture cam; MultiMarker nya; Catcher catcher; Timer timer; Drop[] drops; //End[] ends = new End[10];; int totalDrops = 0; int numCaught = 0; PImage flowers; PImage bFlowers; PImage background; PImage black; //PImage end; int level; // 1: First plant stage // 2: Second plant stage int time; String timeString = "00"; //String counter = "00"; int initialTime; int interval = 1; int totalTime = 60000; float x=0; int value = 32; int intTimeString; int gameScreen; // 0: Initial Screen // 1: Game Screen // 2: Game-over Screen void setup() { fullScreen(P3D); //size(640,480,P3D); fill(0); background = loadImage("background.jpg"); catcher = new Catcher(60); // Create the catcher with a radius of __ drops = new Drop[2500]; timer = new Timer(300); flowers = loadImage("flowers.png"); bFlowers = loadImage("bFlowers.png"); //end = loadImage("end.png"); initialTime = millis(); //for (int = i; i < ends.length; i++) { // ends[i] = new End(100+i*100, 300, random(32,72)); //} cam=new Capture(this, 1440, 900); nya=new MultiMarker(this, 1440, 900, "camera_para.dat", NyAR4PsgConfig.CONFIG_PSG); nya.addNyIdMarker(0, 80); cam.start(); } void draw() { background(0); if (gameScreen == 0) { initScreen(); } else if (gameScreen == 1) { if (cam.available() !=true) { } gameScreen(); cam.read(); nya.detect(cam); pushStyle(); imageMode(CORNER); //nya.drawBackground(cam); popStyle(); if ((!nya.isExist(0))) { } else { x += (nya.object2ScreenCoordSystem(0, 0, 0, 0).x-x)*.1; //println(x); } catcher.setLocation(width-x); catcher.display(); } else if (gameScreen == 2) { gameOverScreen(); } } void initScreen() { background(255); image(bFlowers, width/2, height/3); imageMode(CENTER); fill(50, 100, 150); textSize(18); textAlign(CENTER); text("MOVE THE PLANT SLOWLY TO COLLECT AS MANY WATER DROPS AS YOU CAN", width/2, height/2); text("PRESS SPACEBAR TO START", width/2, height/1.7); } void keyPressed() { if (value == 32) { startGame(); time = 0; } } void startGame() { gameScreen=1; } void gameScreen() { imageMode(CORNER); image(background, 0, 0); catcher.display(); if (timer.isFinished()) { drops[totalDrops] = new Drop(); totalDrops ++ ; if (totalDrops >= drops.length) { totalDrops = 0; } timer.start(); } for (int i = 0; i < totalDrops; i++ ) { drops[i].move(); drops[i].display(); if (catcher.intersect(drops[i])) { drops[i].caught(); numCaught++; } } if (numCaught==15) { level = 1; } else if (numCaught==25) { level = 2; } if (millis() - initialTime > interval) { time += 1; timeString = nf(time, 2); initialTime = millis(); } intTimeString = parseInt(timeString)/60; timeString = Integer.toString(intTimeString); text("TIME: " + timeString, width/9, height/8); textSize(22); if ((time>=totalTime) || (numCaught>=30)) { gameOverScreen(); } } void gameOverScreen() { cam.stop(); background(255); fill(50, 100, 150); textAlign(CENTER); textSize(22); text("GAME OVER", width/2, height/2.3); textSize(20); text("PRESS THE SCREEN TO REPLAY", width/2, height/2); imageMode(CORNER); //or (int = i; i < ends.length; i++) //ends[i].ascend(); //ends[i].display(); //ends[i].top(); } void mousePressed() { gameScreen = 1; //loop();
Catcher class
class Catcher { float r; // radius color col; // color float x, y; // location int w = 200; int h = 580 ; Catcher(float tempR) { r = tempR; col = color(50, 10, 10, 150); x = 0; y = height - 200; } void setLocation(float tempX) { x = tempX; } void display() { stroke(0); fill(col); int startPoint = 200*level; PImage flower = flowers.get(startPoint, - height/3, w, h); image(flower, x, y); imageMode(CENTER); } // A function that returns true or false based on if the catcher intersects a raindrop boolean intersect(Drop d) { // Calculate distance float distance = dist(x, y + 120, d.x, d.y); if (distance < r + d.r) { return true; } else { return false; } } }
Drops class
class Drop { float x, y; // Variables for location of raindrop float speed; // Speed of raindrop color c; float r; // Radius of raindrop Drop() { r = 8; // All raindrops are the same size x = random(width); // Start with a random x location y = -r*4; // Start a little above the window speed = random(3, 6); // Pick a random speed c = color(50, 100, 150); // Color } // Move the raindrop down void move() { // Increment by speed y += speed; } // Check if it hits the bottom boolean reachedBottom() { // If we go a little beyond the bottom if (y > height + r*4) { return true; } else { return false; } } // Display the raindrop void display() { // Display the drop fill(c); noStroke(); for (int i = 2; i < r; i++ ) { ellipse(x, y + i*4, i*2, i*2); } } // If the drop is caught void caught() { // Stop it from moving by setting speed equal to zero speed = 0; // Set the location to somewhere way off-screen y = -1000; } }
Timer class
class Timer { int savedTime; // When Timer started int totalTime; // How long Timer should last Timer(int tempTotalTime) { totalTime = tempTotalTime; } // Starting the timer void start() { // When the timer starts it stores the current time in milliseconds. savedTime = millis(); } boolean isFinished() { // Check how much time has passed int passedTime = millis()- savedTime; if (passedTime > totalTime) { return true; } else { return false; } } int getTime() { return millis()/600; } }
A class of flowers I was considering ending at the end screen:
//class End { // float x, y; // location // float diameter; // Bubble (float tempX, float tempY, float tempD) { // x = tempX; // y = tempY; // diameter = tempD; // } // void ascend() { // y--; // x = x+random(-2, 2); // } // void display() { // imageMode(CENTER); // image(end, x, y, diameter, diameter); // } // void top() { // if (y < diameter/2) { // y = diameter/2; // } // } //}
Fin.