Whale, Ocean, Us – Sheldon Chen – Eric

firstBG(Cover)
firstBG

Conception and Design

Our original understanding of the interaction in our project is that in order to create an immersive experience, users need to use their body to control the movement of the whale in the game. The final design decision we made was to use a helmet whose front is red while opening the OpenCV in processing to track the specific kind of red within the view of the webcam. The center of the red area would then be mapped as the head position of the user. We chose red instead of other colors because it could be most easily recognized by the camera, thus the recognition would be the most stable and accurate. The other option we also had was putting numerous infrared LEDs on the head and around the wrists of the user, then use light tracking to track the position of the user. The major problem involves the recognition being disturbed by numerous infrared noises in the environment, which makes the corresponding mapping less accurate.

In order to make the whole experience even more immersive, we decided to make a whale suit to let the user put on. The suit was made from several IKEA shopping bags. We chose them because they first resemble the color of whales, and second are recycled materials, which caters to the theme we set for this game. In addition, the suit is used in case some players dress in red, which might greatly influence the accuracy in this game. There surely were other options, one is to buy retailed whale costume online. We turned this down, for buying new materials wouldn’t cater to the environmental protection theme we set for this game.

Fabrication and Production

The general development process of our project involves two stages, game development, implementation of interaction/costume.

In the first session, I was mainly in charge of coding the game. The game itself was literally developed from scratch. The first success we achieved was prototyping the game. In this version, all the objects, from whales, garbage, to jellyfish, were represented by a series of shapes in different colors. All the garbage and jellyfish would flow from the right of the screen to the left of the screen, while the player needs to use the arrow keys to control the movement of a circle and avoid colliding with other objects. The game would be over when the circle crashes into the rectangle or other garbage. Everything works perfectly until this point. In the next step, I tried to let the amount of garbage and jellyfish increases over time. The first option I had was using arrays. Though I managed to find a way to append new objects to an array through “obs =(Obstacles[])append(obs, newObstacles(width+random(40), random(100, height), random(4, 6)));”, the game would be slowed down when more objects are appended into the array. I then unwillingly switched to the ArrayList. After images of the objects and background were added into the game, the game became incredibly slow. It took me a while to google the answer, which says the image() function would be greatly slowed down when five parameters are passed into. Instead, I should use the resize() function at the beginning of the program to adjust the size at one time.

In the implementation part, it took us a while to find the appropriate object to be tracked. As mentioned above, we considered using Infrared LEDs, but it could be easily influenced by other infrared light within the environment. Then I accidentally discovered the OpenCV library in processing also supports color tracking by choosing a specific color, before finding a helmet which has red in front. After measuring the hue value of the red on the helmet, I was able to track this specific kind of color using OpenCV. However, the position of the recognized dot wasn’t stable, and the whale in the screen might be jumping from here to there. Eric helped me out by implementing an easing function which would ignore changes brought by instability.

During the user testing, lots of people expressed great interest in our project and think highly of the concept. However, most of them also complained that they don’t know the objectives of the game, especially what to do and what not to do. They also think there lacks feedback from the game, either in the form of visual or audio. To address the first problem, we put in a tutorial page at the beginning of the game, labeling which need to avoid eating and which need to eat. However, the tutorial doesn’t seem to be very effective, especially during the IMA Show, as I still have to verbally explain the rules. Most users also don’t know how to correctly control the whale using their head. As for the second feedback, we added two vibration motors to our helmet. When the whale eats garbage, these motors would vibrate and provide physical feedback to the user. This went pretty well during the final presentation. But on the IMA Show, some of the wires went off and the vibration part couldn’t function during that time.

Legendary Helmet
Legendary Helmet

Conclusions

As I mentioned previously, the goal of my project is to create a motion-sensing game, through which the user would feel like a whale struggling to avoid eating garbage in the ocean. It aligns with my definition of interaction, as it allows multiple ways of input and output, where users need to use their body to control the movement of the whale; the user would get output from the game visually, physically(vibration). It doesn’t align with my definition in the way that users sometimes are confused about how to interact with the device. Ultimately, my audience interacts with my device almost in the same way as I anticipated. However, some of them didn’t really know how to move their heads to control the whale in the game, while some other of them were confused about what to do and what not to do. If I were to have more time, I would first, add a tutorial session before the game officially starts, which teaches users how to properly move their heads, as well as what to eat and what not to eat. I would also try to alter the game mechanism by adding more objectives to the game. What I learned through setbacks is that never lose hope, there must be other approaches if one doesn’t work. As for the takeaway from accomplishments, the game mechanism is really the foundation of a game, which needs to be carefully thought of before coding, otherwise, it would be so hard to change later.

So why should anybody care? In terms of the concept and the background of the game, it is set on the plastic pollution issue in the ocean, the user is no longer a bystander as a human, but instead, a whale in the ocean struggling to avoid eating plastic. Being in the shoes of a whale is truly the spirits of the game. The motion sensing interaction also boosts the user’s immersive experience in being a whale. Most importantly, the cute whale suit could not be more appealing to users, especially kids. In other words, the significance of our game is already written in the title of our project, Whale, Ocean, Us.

Appendices

GitHub Repo: https://github.com/nh8157/Whale-Ocean-Us

################PROCESSING CODE######################

PImage bag;
PImage introBG;
PImage firstBG;
PImage endBG1;
PImage endBG2;
PImage [] whales = new PImage [65];
PImage [] garbage = new PImage [4];
PImage [] food = new PImage [2];

import gab.opencv.*;
import processing.video.*;
import java.awt.Rectangle;
import processing.serial.*;
import processing.sound.*;
SoundFile file;

Capture video;
OpenCV opencv;
PImage src, colorFilteredImage;
ArrayList<Contour> contours;
Serial myPort;
int valueFromArduino;
int gameState = 0;
//initiating ball
Ball ball1;
// initializing two arrays\list
ArrayList<Obstacles> obs = new ArrayList<Obstacles>();
ArrayList<Subsidy> subs = new ArrayList<Subsidy>();
ArrayList<Background> bg = new ArrayList <Background>();
ArrayList<PImage> seaFood = new ArrayList<PImage>();
ArrayList<PImage> bgReserve = new ArrayList<PImage>();

float present;
float previous0 = 0;
float previous1 = 0;
float previous2 = 0;
int counter0;
int counter1 = 0;
int counter2 = 0;
int count0;
int count1;
int subCount = 0;
int seaLevel;
float[] brePara = new float[2];
float[] hunPara = new float[2];
int x;
int y;
int vibration;

void setup() {
size(1280, 720);
// initializing two arrays
//video = new Capture(this, 1280, 720);
video = new Capture(this, 640, 360);
video.start();
opencv = new OpenCV(this, video.width, video.height);
contours = new ArrayList<Contour>();
seaLevel = 230;
background(0);
count0 = 0;
myPort = new Serial(this, Serial.list()[ 1 ], 9600);
whales [0]= loadImage(“0.png”);
whales [1]= loadImage(“0.png”);
whales [2]= loadImage(“0.png”);
whales [3]= loadImage(“0.png”);
whales [4]= loadImage(“0.png”);
whales [5]= loadImage(“1.png”);
whales [6]= loadImage(“1.png”);
whales [7]= loadImage(“1.png”);
whales [8]= loadImage(“1.png”);
whales [9]= loadImage(“1.png”);
whales [10]= loadImage(“2.png”);
whales [11]= loadImage (“2.png”);
whales [12]= loadImage (“2.png”);
whales [13]= loadImage (“2.png”);
whales [14]= loadImage(“2.png”);
whales [15]= loadImage(“3.png”);
whales [16]= loadImage(“3.png”);
whales [17]= loadImage(“3.png”);
whales [18]= loadImage(“3.png”);
whales [19]= loadImage(“3.png”);
whales [20]= loadImage(“4.png”);
whales [21]= loadImage (“4.png”);
whales [22]= loadImage (“4.png”);
whales [23]= loadImage (“4.png”);
whales [24]= loadImage(“4.png”);
whales [25]= loadImage(“5.png”);
whales [26]= loadImage(“5.png”);
whales [27]= loadImage(“5.png”);
whales [28]= loadImage(“5.png”);
whales [29]= loadImage(“5.png”);
whales [30]= loadImage(“6.png”);
whales [31]= loadImage(“6.png”);
whales [32]= loadImage(“6.png”);
whales [33]= loadImage(“6.png”);
whales [34]= loadImage(“6.png”);
whales [35]= loadImage(“5.png”);
whales [36]= loadImage(“5.png”);
whales [37] =loadImage(“5.png”);
whales [38] =loadImage(“5.png”);
whales [39] =loadImage(“5.png”);
whales [40] =loadImage(“4.png”);
whales [41] =loadImage(“4.png”);
whales [42] =loadImage(“4.png”);
whales [43] =loadImage(“4.png”);
whales [44] =loadImage(“4.png”);
whales [45] =loadImage(“3.png”);
whales [46] =loadImage(“3.png”);
whales [47] =loadImage(“3.png”);
whales [48] =loadImage(“3.png”);
whales [49] =loadImage(“3.png”);
whales [50] =loadImage(“2.png”);
whales [51] =loadImage(“2.png”);
whales [52] =loadImage(“2.png”);
whales [53] =loadImage(“2.png”);
whales [54] =loadImage(“2.png”);
whales [55] =loadImage(“1.png”);
whales [56] =loadImage(“1.png”);
whales [57] =loadImage(“1.png”);
whales [58] =loadImage(“1.png”);
whales [59] =loadImage(“1.png”);
whales [60] =loadImage(“0.png”);
whales [61] =loadImage(“0.png”);
whales [62] =loadImage(“0.png”);
whales [63] =loadImage(“0.png”);
whales [64] =loadImage(“0.png”);
firstBG = loadImage(“firstBG.JPG”);
firstBG.resize(width, height);
introBG = loadImage(“Instruction.png”);
introBG.resize(width, height);
endBG1 = loadImage(“endBG1.JPG”);
endBG1.resize(width, height);
endBG2 = loadImage(“endBG2.JPG”);
endBG2.resize(width, height);
for (int i = 0; i < 2; i ++) {
food[i] = loadImage(“C” + str(i + 1) + “.png”);
food[i].resize(50, 60);
}
for (int i = 0; i < 4; i ++) {
garbage[i] = loadImage(“G” + str(i + 1) + “.png”);
if (i == 0) {
garbage[i].resize(54, 58);
} else if (i == 1) {
garbage[i].resize(55, 35);
} else if (i == 2) {
garbage[i].resize(50, 52);
} else {
garbage[i].resize(64, 37);
}
}
for (int i = 0; i < whales.length; i ++) {
whales[i].resize(200, 115);
}
count0 ++;
myPort.write(‘L’);
//file = new SoundFile(this, “bgm.mp3”);
}

void draw() {

// the state of the game stays at the first
// when the user clicks
// the state will change again
//image(img2, width / 2, height / 2);
present = millis();
if (gameState == 0) {
counter0 = 0;
imageMode(CORNER);
image(firstBG, 0, 0);
fill(255);
textSize(26);
if (keyPressed && key == ‘s’) {
gameState ++;
delay(100);
}
} else if (gameState == 1) {
imageMode(CORNER);
image(introBG, 0, 0);
fill(255);
text(“Press B to continue”, width – 300, height – 100);
if (keyPressed && key == ‘b’) {
previous0 = present;
previous1 = present;
previous2 = present;
brePara[0] = previous1;
brePara[1] = counter1;
hunPara[0] = previous2;
hunPara[1] = counter2;
gameState ++;
ball1 = new Ball(0, 450, 7);
imageMode(CENTER);
if (count0 != 0) {
obs.clear();
subs.clear();
bg.clear();
bgReserve.clear();
seaFood.clear();
}
seaFood.add(loadImage(“C1.png”));
seaFood.add(loadImage(“C2.png”));
bgReserve.add(loadImage(“BG1.jpg”));
bgReserve.add(loadImage(“BG2.jpg”));
bgReserve.add(loadImage(“BG1.jpg”));
bgReserve.add(loadImage(“BG2.jpg”));
bgReserve.add(loadImage(“BG1.jpg”));
bgReserve.add(loadImage(“BG2.jpg”));
bgReserve.add(loadImage(“BG4.jpg”));
bgReserve.add(loadImage(“BG3.jpg”));
bgReserve.add(loadImage(“BG4.jpg”));
bgReserve.add(loadImage(“BG3.jpg”));
bgReserve.add(loadImage(“BG4.jpg”));
bgReserve.add(loadImage(“BG3.jpg”));
bgReserve.add(loadImage(“BG4.jpg”));
bgReserve.add(loadImage(“BG3.jpg”));
bgReserve.add(loadImage(“BG5.jpg”));
bgReserve.add(loadImage(“BG6.jpg”));
bgReserve.add(loadImage(“BG5.jpg”));
bgReserve.add(loadImage(“BG6.jpg”));
bgReserve.add(loadImage(“BG5.jpg”));
bgReserve.add(loadImage(“BG6.jpg”));
bgReserve.add(loadImage(“BG5.jpg”));
bgReserve.add(loadImage(“BG6.jpg”));
bgReserve.add(loadImage(“BG5.jpg”));
bgReserve.add(loadImage(“BG6.jpg”));
for (PImage bgR : bgReserve) {
bgR.resize(width, height);
}
for (int i = 0; i < 2; i ++) {
PImage img = bgReserve.get(0);
if (i == 0) {
bg.add(new Background(img, width / 2));
} else {
bg.add(new Background(img, width * 3 / 2));
}
}
// adding class objects into arrays
for (int i = 0; i < 2; i ++) {
int[] classifier = classifier();
int obIn = classifier[0];
int subIn = classifier[1];
obs.add(new Obstacles(random(40) + width, random(seaLevel, height), random(5, 10), obIn));
subs.add(new Subsidy(random(40) + width, random(seaLevel, height), random(5, 10), subIn));
}
}
} else if (gameState == 2) {
imageMode(CENTER);
if (video.available()) {
video.read();
}
// <2> Load the new frame of our movie in to OpenCV
opencv.loadImage(video);
//opencv.flip(OpenCV.HORIZONTAL);
// Tell OpenCV to use color information
opencv.useColor();
//src = opencv.getSnapshot();
// <3> Tell OpenCV to work in HSV color space.
opencv.useColor(HSB);
// <4> Copy the Hue channel of our image into
// the gray channel, which we process.
opencv.setGray(opencv.getH().clone());
// <5> Filter the image based on the range of
// hue values that match the object we want to track.
opencv.inRange(176, 180);
// <6> Get the processed image for reference.
//colorFilteredImage = opencv.getSnapshot();
// <7> Find contours in our range image.
// Passing ‘true’ sorts them by descending area.
contours = opencv.findContours(true, true);
if (contours.size() > 0) {
// <9> Get the first contour, which will be the largest one
Contour biggestContour = contours.get(0);

// <10> Find the bounding box of the largest contour,
// and hence our object.
Rectangle r = biggestContour.getBoundingBox();

float easing = 0.05;
float targetX = width – ((r.x + r.width/2)*2);
float dx = targetX – x;
x += dx * easing;

float targetY = (r.y + r.height/2)*2;
float dy = targetY – y;
y += dy * easing;

//x = r.x + r.width/2;
//y = r.y + r.height/2;
}
// background management
for (int i = 0; i < 2; i ++) {
Background back = bg.get(i);
back.display();
back.move();
if (back.xpos == -width / 2) {
bg.remove(i);
if (bgReserve.size() > 0) {
PImage new_img = bgReserve.get(0);
bgReserve.remove(i);
bg.add(new Background(new_img, width * 3 / 2));
} else {
PImage new_img = back.reimg();
bg.add(new Background(new_img, width * 3 / 2));
}
}
}
// need to use graphics to show the demonstrate the blood left
ball1.move(x, y, seaLevel);
// attempting to introduce a rising difficulty
// use the millis()
// when the program executes to a point
// the objects in the obs array will increase
// the objects in the subs array will decrease
previous1 = moreBlocks(present, previous1, seaLevel);
// display ball, obstacles, subsidy
subCount = displayMove(counter0, subCount);
noStroke();
fill(0, 200, 20, 220);
rect(width / 4, height * 15 / 16, 6.4 * ball1.hp, 100, 7);
// generate new obstacles and subsidy
// once out of the screen
generate(seaLevel);
// user control the ball through keyboard
// collision determination
vibration = collision(previous2, seaLevel);
fill(0);
textSize(26);
if (counter0 < 64) {
counter0 ++;
} else {
counter0 = 0;
}
} else if (gameState == 3){
imageMode(CORNER);
image(endBG1, 0, 0);
fill(255);

textSize(26);
text(“press S to continue”, width/2, height – 20);
myPort.write(‘L’);
if (keyPressed) {
if (key == ‘s’ || key == ‘S’) {
gameState ++;
}
}
} else {
imageMode(CORNER);
image(endBG2, 0, 0);
if (keyPressed){
if (key == ‘b’ || key == ‘B’){
gameState = 0;
}
}
}
}

////////////////////////////BACKGROUND////////////////////////////
class Background {
PImage img;
int xpos;
int speed;
Background(PImage image, int x) {
img = image;
xpos = x;
speed = 5;
}
PImage reimg() {
return img;
}
void move() {
xpos -= speed;
}
void display() {
image(img, xpos, height / 2);
}
}

////////////////////////////BALL////////////////////////////

class Ball {
// initializing the ball
// if the player hit the block for once
// its hp will decrease by 25%
int xpos;
int ypos;
int speed;
int r;
float hp;
int G1;
int G2;
int G3;
int G4;
Ball(int x, int y, int spe) {
xpos = x;
ypos = y;
speed = spe;
r = 100;
hp = 100;
G1 = 0;
G2 = 0;
G3 = 0;
G4 = 0;
}

void move(int x, int y, int seaLevel) {
xpos = x;
//ypos = y;
if (y >= seaLevel){
ypos = y;
}
}
// if the player hit the block for once
// its hp will decrease by 25%
// the number of each type of garbage eaten
void garbageUp(int i){
if (i == 0){
G1 ++;
} else if (i == 1){
G2 ++;
} else if (i == 2){
G3 ++;
} else if (i == 3){
G4 ++;
}

}
void hpDownC() {
hp -= 5;
}
void hpUpC() {
if (hp <= 95) {
hp += 5;
} else if (hp < 100) {
hp = 100;
}
}

int liveOrDie(int gameState) {
if (hp <= 0) {
gameState ++;
}
return gameState;
}
void display(PImage i) {
image(i, xpos – 55, ypos +10);
}
}

////////////////////////////OBSTACLES////////////////////////////

class Obstacles {
float xpos;
float ypos;
float speed;
int r;
int obClass;
int displayCount;
Obstacles(float x, float y, float spe, int obIn) {
xpos = x;
ypos = y;
speed = spe;
obClass = obIn;
r = 35;
displayCount = 0;
}
void move() {
xpos -= speed;
}
int reClass(){
return obClass;
}
void display() {
if (displayCount == 0) {
if (obClass == 2) {
ypos = random(seaLevel – 40, seaLevel);
speed = random(3, 5);
displayCount ++;
} else if (obClass == 0) {
speed = random(8, 10);
}
}
image (garbage[obClass], xpos, ypos);
}
}

////////////////////////////SUBSIDY////////////////////////////

class Subsidy {
float xpos;
float ypos;
float a;
float speed;
Subsidy(float x, float y, float spd, int sub) {
xpos = x;
ypos = y;
a = 20;
speed = spd / 2;
}
void move() {
xpos -= speed;
}
void display(PImage i) {
image(i, xpos, ypos);
}
}

////////////////////////////FUNCTIONS////////////////////////////
int displayMove(int counter, int subCount) {
for (Obstacles ob : obs) {
ob.display();
ob.move();
}
for (Subsidy sub : subs) {
sub.display(food[subCount]);
sub.move();
}
if (subCount == 0) {
subCount = 1;
} else {
subCount = 0;
}
ball1.display(whales[counter]);
return subCount;
}

void generate(int seaLevel) {
for (int i = 0; i < obs.size(); i ++) {
Obstacles ob = obs.get(i);
int[] classifier = classifier();
int obIn = classifier[0];
if (ob.xpos < 0) {
obs.remove(i);
obs.add(new Obstacles(width + random(40), random(seaLevel, height), random(5, 10), obIn));
}
}
for (int i = 0; i < subs.size(); i ++) {
Subsidy sub = subs.get(i);
int[] classifier = classifier();
int subIn = classifier[1];
if (sub.xpos < 0) {
subs.remove(i);
subs.add(new Subsidy(width + random(40), random(seaLevel, height), random(5, 10), subIn));
}
}
}
// differnet gargage might be generated
// at this moment
// it will generate different kinds of garbages
int collision(float previous2, int seaLevel) {
vibration = 0;
int time = 0;
for (int i = 0; i < subs.size(); i++) {
Obstacles ob = obs.get(i);
Subsidy sub = subs.get(i);
float ob1 = dist(ob.xpos + 26, ob.ypos, ball1.xpos, ball1.ypos);
float ob2 = dist(ob.xpos – 26, ob.ypos, ball1.xpos, ball1.ypos);
int[] classifier = classifier();
int obIn = classifier[0];
int subIn = classifier[1];
if (ob1 + ob2 <= 60 + ob.r) {
// still necessary to keep this function?
myPort.write(‘H’);
ball1.garbageUp(ob.reClass());
for (int m = 0; m < 2 * (4 – ob.obClass); m ++) {
ball1.hpDownC();
myPort.write(‘H’);
}
myPort.write(‘H’);
obs.remove(i);
obs.add(new Obstacles(width + random(40), random(seaLevel, height), random(4, 6), obIn));
} else {
myPort.write(‘L’);
}
if (dist(ball1.xpos, ball1.ypos, sub.xpos, sub.ypos) <= 30) {
ball1.hpUpC();
subs.remove(i);
subs.add(new Subsidy(width + random(40), random(seaLevel, height), random(4, 6), subIn));
}
gameState = ball1.liveOrDie(gameState);
}
return vibration;
}

// garbage is according to the random number generated
// the obstacles will be generated more
// the subsidy will be fewer and fewer
float moreBlocks(float present, float previous, int seaLevel) {
if (present – previous > 10000) {
for (int i = 0; i < 2; i ++) {
int[] classifier = classifier();
int obIn = classifier[0];

obs.add(new Obstacles(width + random(40), random(seaLevel, height), random(4, 6), obIn));
}
int[] classifier = classifier();
int subIn = classifier[1];
subs.add(new Subsidy(width + random(40), random(seaLevel, height), random(4, 6), subIn));
println(subs.size());
previous = present;
}
return previous;
}

float[] hunger(float present, float[] Para) {
float count = Para[1];
float previous = Para[0];
int[] intervals = {5000, 4000, 2000, 1000};
if (present – previous >= intervals[int(count)]) {
ball1.hpDownC();
}
Para[0] = present;
Para[1] = count;
return Para;
}

void breathe(int seaLevel) {
if (ball1.ypos <= seaLevel + 5) {
ball1.hp += 0.05;
}
}

// random generator for the determination of garbage type
int[] classifier() {
float obRandom = random(10);
float subRandom = random(10);
int obIn;
int subIn;
if (obRandom <= 10 && obRandom > 8) {
obIn = 0;
} else if (obRandom <= 8 && obRandom > 6) {
obIn = 1;
} else if (obRandom <= 6 && obRandom > 4) {
obIn = 2;
} else {
obIn = 3;
}
if (subRandom <= 10 && subRandom > 9) {
subIn = 0;
} else if (subRandom <= 9 && subRandom > 7) {
subIn = 1;
} else if (subRandom <= 7 && subRandom > 4) {
subIn = 2;
} else {
subIn = 3;
}
int[] classifier = {obIn, subIn};
return classifier;
}

################ARDUINO CODE######################

// IMA NYU Shanghai
// Interaction Lab
// This code receives one value from Processing to Arduino

char valueFromProcessing;
int ledPin = 3;

void setup() {
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
}

void loop() {
// to receive a value from Processing
while (Serial.available()) {
valueFromProcessing = Serial.read();
}

if (valueFromProcessing == ‘H’) {
digitalWrite(ledPin, HIGH);
delay(1000);
} else {
digitalWrite(ledPin, LOW);
}

// too fast communication might cause some latency in Processing
// this delay resolves the issue.
delay(10);
}

Recitation 11: Workshops by Sheldon Chen

The workshop I attended in this recitation is the Object Oriented Programming workshop. 

What the exercise required us to accomplish in the end was class objects with certain level of interactivity. In this exercise, I tried to create a design that enables users to use the mouse to avoid the incoming blocks. 

Specifically, I first created a Ball class, where they have a set of default value for X and Y coordinates. Then, I created the display function in order to draw an ellipse and indicate the position of the point. 

In the next class Obstacles, I’ve also created the X and Y coordinates in the constructor. In this class, I added another parameter speed, which would be used in the move function and let it move according to the preset speed value. In the display function, I used the rect() function to show a 20 * 20 rectangle drew on the X and Y coordinates. 

In the main code, I first declared the ArrayList obs, which would hold the obstacles objects. In the main draw loop, I used mouseX and mouseY as parameters passing into the Ball class, which would make the mouse’s position as the position of the ellipse. The obstacles, then, will be generated at the right side of the screen with random height and speed. The obstacles then would move leftwards, and the user need to avoid being hit by the obstacles by carefully manipulating the position of the mouse.

Recitation 10: Media Controller by Sheldon Chen

The first media controller I created was to control RGB in a picture through three potentiometers, which control red, green, blue respectively. The template I used was the Arduino to Processing one. In the Arduino file, after receiving analog values from the potentiometer, the I first attempted to use pixel manipulation, to control each pixel through nested for loops. However, instead of the picture, what loaded on the screen was a bunch of pixels. Though the potentiometers could perfectly control the RGB in the picture. Then I turned to use the tint() function, which seem to be the right function for changing RGB in a picture.

What I tried next was using potentiometer to control the speed of the video, which also uses the Arduino to Processing template file. For this design, I used one potentiometer only, and I mapped it to the value from 0 to 255 to 0 to 10. On the receiving side, the program would insert the number received to the function speed(). In the processing file, I also need to import the video library, initiate the video we are editing on.

At the start of the essay, the author mentions “”Computer vision” refers to a broad class of algorithms that allow computers to make intelligent assertions about digital images and video.” The vision of computer would first, enable users to interact with computer in new and creative ways, such as waving arms, even dancing, which would create a more engaging, immersive experience. What’s more, because computer vision can accept all kinds of images and videos, the output of the program would also vary accordingly. Consequently, diverse output of the interaction could be presented.

Recitation Blog Post by Sheldon Chen

The first project was a design helping people with negative mental state. It attempts to do so by asking users to wave their arms in the air to “touch” certain shapes in the image. Though it is an interesting idea, I think our computers don’t have the capacity of capturing real time images and processing them. In other words, the program will be very slow to run, which would negatively affect users’ experience interacting with the device. For other group members, they doubt whether waving the arm in the air could really improve their mental state. The project is interesting because of its background, which aims to help people mentally. It could create meaningful experience, because it has changed how users interact with a simple game, which makes the effect of the game not simple anymore.

The second project was a digitalized version of the battleship game. It is mainly about using the cannonball shot from the enemy to predict the position of the enemy’s boats. I haven’t played the physical battleship game before, but I think it might make everything easier through digitalization. My other group members think it would be too hard to digitalize the position of the boat. The most interesting part of this project is how it digitalize the whole design. Also because of the digitalization, the project could create significance.

The third project was a room escape game. Players would use the clues in the room to decrypt the key or password to go to the next room. I think it would be hard for them to achieve this project in the limited time, as it is a game involving complicated logic design, while remaining its playability. Other group members consider the interaction is not creative enough, for users would simply use joystick to control the character. This project is interesting for it narrowing the complicated, real-life game to a computer game. It could create meaningful experience, because it would enable users to experience room escape without going to a physical room.

The similarity among these projects is they are all using physical interaction to replace the usual way of interacting through keyboard and mouse, which would make a usual interaction new and special. It is somehow similar to my prior definition of interaction, which also considers interaction as a process not limited to keyboard input.

For my project, my group member, Nick first suggested me researching more on ocean debris and whales dying from debris. He also thinks the two-player mode could be cut down to one player only, because “we can’t understand what whales are thinking”. Nick also suggested we should think more in terms of how users interact. According to my group members, the most successful part of this project is the background setting, while the least successful part is the way users interact with my project. I do agree with their comments, for we indeed spent a lot of time thinking about the background of this game, while neglecting the way users would interact with. After receiving these feedbacks, I would, for sure, research more, think more about the game mechanism. In terms of improvements, instead of removing the whale, we would remove the human and make it a game about how the whale escapes the ocean debris. We would also consider other creative ways for users to interact with the project.

Final Project Essay by Sheldon Chen

Project title: Ocean, Whale, Us

Project Statement of Purpose:

The focus of this project is the marine debris. In numerous recent reports, a number of marine creatures, such as whales, dolphins, are documented to have dead from marine debris. The debris usually come from people dumping waste from coast, on beaches, from boats, even from the air. When the density of the marine debris reaches a certain point, the marine creatures would easily suck the debris in, which would result in suffocating easily. Therefore, my partner and I would like to design a game, where human, the player 1, would help whale, the player 2, to escape its situation being trapped by the debris, unable to breathe. The greatest challenge is about the general logic of the game, through which the user has to feel pleased, enjoyable. The game is intended for every human-being, as the ocean is the shared assets of the entire human race. Humans would also be seriously affected by the pollution in the ocean. Through playing our game, we are hoping to establish the awareness of not polluting the ocean among the users, otherwise their friend (the second player) would die.

Project Plan:

April 26- April 27:

Basic design for the whole game and detailed compositions

Research on how to write the code for the game

Basic design for the animation

Decide and start to prepare necessary materials

Decide the ways of interaction and console for the two players (adjustable later)

April 28-May 9:

Finishing the code

Finishing the animation

Finishing the circuits

May 10-13:

User testing

Make final adjustments according to the feedbacks

(the sensitivity of interaction for the audience, debugging the circuit and codes, thinking about whether the informative significance of the game is clear enough for the audience, ways of displaying the game for presentation)

May 14-17:

Presentation

Context and Significance:

My definition of interactivity in the preparatory research, which emphasizes the emotional, mental take away for the audience after the interaction, has reminded us to set the topic under a broader background. It also aligns with my project in terms of the way user would interact, this is also a unique part of our project. As the human player would use an oar to control the forward and backward of the boat. The whale player would probably use another bodily sensing part to interact. The project is significant because it could educate people the harm of dumping waste into the ocean.