A.Dino Jump – Angel Min Chang – Dino Jump
- CONCEPTION AND DESIGN:
Briefly describe your project’s concept and how your previous preparatory research and the essay lead to its formation. In what ways did your understanding of how your users were going to interact with your project inform certain design decisions you made? Account for several such decisions. What happened during the User Testing Session? How did your user testing process influence some of your following design decisions? What kind of adaptations did you make? Were they effective?
My project concept is quite straightforward. It’s intended to provide those who are too busy with finals with move around an opportunity to exercise by jumping in a fun, throwback setting.
My earlier preparation study and essay have helped me build on how I wanted to recreate the classic game chrome dino jump and how I will combine my understanding of interactivity with the knowledge I received in class for this project.
According to my understanding, interactive means that the user makes action and there is an outcome, a reaction. For my design process, I want to create something that can provide users with a quick response and directly affect the game’s outcome.
So, at first, I considered making a jumping game in which when the user taps the space tab, the item jumps, but throughout the user testing process, I discovered that there was very little interaction. So I considered making something that would elicit people’s activity and perhaps allow them to interact with others while engaging with my project.
The ideal approach is to use the Arduino to make some installation that captures the user’s movement and prints the output to process and affect the final actions. At the same time, I didn’t want it to be simply a single-player game, so I added players, making it a team effort game.
After I made the improvements, I discovered that people like the fact that they could play a simple fun game with their friends. There was no lag while using the Arduino with the conductive tape button. which is what I aimed for at the beginning, because I want to achieve a quick input/output response experience.
- FABRICATION AND PRODUCTION:
At first, I attempted to utilize a pressure sensor, and I created the code while testing, but only tested it on my hands. The pressure sensor was extremely sensitive, and data was sent from Arduino to processing in record time. The standard was difficult to establish because the sensor just prints outnumber data and various people have varied weights, resulting in varying pressures being sent out to processing. During user testing, I discovered that the pressure sensor is quite easy to break.
(pressure sensor, and video of its lagging)
Then, inspired by a classmate, I decided to convert to buttons because buttons simply print out 1 and 0, making it simple to use the code because there are only two variables. So it’s either on or off that controls whether or not the dino jumps.
(button picture)
After changing my mind about using buttons, I laser cut out the shape of dinosaur paws from a wood board.
and a circle with a diameter of 30mm, which is exactly how the buttons would fit. Later, I discovered that it was quite difficult to transform it into something that people could step on without destroying the wires of the buttons. In this situation, I’d need to design a sturdy and supporting platform for the buttons, as well as make room for the wiring. Initially, I considered making wood board boxes, but after discussing with Andy, he advised me that it would be unsafe for people to step on and that the box would be easily broken. Finally, I had to come up with a better solution. Later, I sought assistance from Macela, who advised that I build a button out of conductive tape, as we learned in our recitation. (As shown below)
https://images.app.goo.gl/i28GjyEPYT5uRFdc8
Finally, I decided to go with using the conductive tape touchpad and laser cut acrylic 3mm colored material into the shape of dinosaur paws. The acrylic 3mm material would not be too thick, making it unstable or unsafe for people to step up, but it would also be strong enough not to break and handle people’s weight.
I was able to use laser cut after drawing a dinosaur paw on Illustrator with Andy’s assistance.
Later, I stuck the foam I found in the fabrication lab in between the two acrylic paw-shaped boards; I just put the foam on the edge to ensure that when pressure is applied to the board, the central part may still touch each other. I applied conductive tape to the center of each acrylic board. The wires were then soldered to the conductive tape. After that, the wires connect to the Arduino.
- CONCLUSIONS:
Begin your conclusion by restating the goals of your project. Did your project achieve its stated goals? Based on the expectations of your audience’s response, how, ultimately, did your audience interact with your project? How do your project results align with your definition of interaction? How would you improve your project if you had more time? What value have you learned from any setbacks and/or failures? What do you take away from your accomplishments?
My project goal was to provide an entertaining experience for the players while also getting them to exercise on a boring and stressful day during the final week.
My project also keeps some traditional characteristics from the dino jump chrome game, which reminds people of their childhood. For example the press space and the dino character which I used the same picture.
In my project, we learned how to utilize Arduino and simple conductive tape to create a push button that can react instantly and print out “a” and “b” that control separate dino jumps in processing. My project appears to have met its goals. During the in-class presentation, one of the comments I received was that my installation was very efficient and reacted quickly when the player jumped. I was delighted that the code worked so effectively to respond so quickly. I am glad I finally settled with the idea of using conductive tape buttons.
My classmates also loved how I turned the game into a collaborative game with our peers. They say that it is less intense and more enjoyable so that people focus on the game rather than the competition.
This project aligns with my understanding of interaction. This is when the player jumps (an input) and the dino would respond with jumping immediately too (output/reaction). My project successfully shows an instance of reacting.
One thing I would do is use a laser cutter to cut out two extra dino paws, making each color a pair, so the player understands what they are supposed to do, which is stand on the dino paws with both feet. In addition, I would adjust the colors of the two dinosaurs to match the color of the dino paws so the player knows which dinosaur they are controlling.
- TECHNICAL DOCUMENTATION:
The background music I found online is called 2-88 FC 马戏团第2. 3 关BGM.mp3 from a Chinese audio website https://www.aigei.com/
The winning sound effect is winning.mp3
The failing sound effect is fail-trombone-03.mp3 both are from https://orangefreesounds.com/
void display () {
fill(#999999);
stroke(255);
strokeWeight(2);
//ellipse(this.x, this.y, this.radius * 2,this.radius*2);
image(img, this.x, this.y, this.radius*2, this.radius*2);
(The ellipse is what I found online for the original code then I switched it to image so I can change the shape easier)
Adruino code:
boolean CanTrigger1 = true;
int Intensity1 = 0;
int pIntensity1 = 0;
int Intensity2 = 0;
int pIntensity2 = 0;
void setup(void) {
Serial.begin(9600);
pinMode(2, INPUT);
pinMode(4, INPUT);
}
void loop(void) {
Intensity1 = digitalRead(2); //
Intensity2 = digitalRead(4); //
if (Intensity1 == 0 && pIntensity1 == 1) {
Serial.write(‘a’);
}
// if (Intensity2 == 0 && pIntensity2 == 1) {
// Serial.write(‘b’);
// }
pIntensity1 = Intensity1;
pIntensity2 = Intensity2;
}
HTML format:
<pre>
<font color=”#00979c”>boolean</font> <font color=”#000000″>CanTrigger1</font> <font color=”#434f54″>=</font> <font color=”#00979c”>true</font><font color=”#000000″>;</font>
<font color=”#00979c”>int</font> <font color=”#000000″>Intensity1</font> <font color=”#434f54″>=</font> <font color=”#000000″>0</font><font color=”#000000″>;</font>
<font color=”#00979c”>int</font> <font color=”#000000″>pIntensity1</font> <font color=”#434f54″>=</font> <font color=”#000000″>0</font><font color=”#000000″>;</font>
<font color=”#00979c”>int</font> <font color=”#000000″>Intensity2</font> <font color=”#434f54″>=</font> <font color=”#000000″>0</font><font color=”#000000″>;</font>
<font color=”#00979c”>int</font> <font color=”#000000″>pIntensity2</font> <font color=”#434f54″>=</font> <font color=”#000000″>0</font><font color=”#000000″>;</font>
<font color=”#00979c”>void</font> <font color=”#5e6d03″>setup</font><font color=”#000000″>(</font><font color=”#00979c”>void</font><font color=”#000000″>)</font> <font color=”#000000″>{</font>
<b><font color=”#d35400″>Serial</font></b><font color=”#434f54″>.</font><font color=”#d35400″>begin</font><font color=”#000000″>(</font><font color=”#000000″>9600</font><font color=”#000000″>)</font><font color=”#000000″>;</font>
<font color=”#d35400″>pinMode</font><font color=”#000000″>(</font><font color=”#000000″>2</font><font color=”#434f54″>,</font> <font color=”#00979c”>INPUT</font><font color=”#000000″>)</font><font color=”#000000″>;</font>
<font color=”#d35400″>pinMode</font><font color=”#000000″>(</font><font color=”#000000″>4</font><font color=”#434f54″>,</font> <font color=”#00979c”>INPUT</font><font color=”#000000″>)</font><font color=”#000000″>;</font>
<font color=”#000000″>}</font>
<font color=”#00979c”>void</font> <font color=”#5e6d03″>loop</font><font color=”#000000″>(</font><font color=”#00979c”>void</font><font color=”#000000″>)</font> <font color=”#000000″>{</font>
<font color=”#000000″>Intensity1</font> <font color=”#434f54″>=</font> <font color=”#d35400″>digitalRead</font><font color=”#000000″>(</font><font color=”#000000″>2</font><font color=”#000000″>)</font><font color=”#000000″>;</font> <font color=”#434f54″>//</font>
<font color=”#000000″>Intensity2</font> <font color=”#434f54″>=</font> <font color=”#d35400″>digitalRead</font><font color=”#000000″>(</font><font color=”#000000″>4</font><font color=”#000000″>)</font><font color=”#000000″>;</font> <font color=”#434f54″>//</font>
<font color=”#5e6d03″>if</font> <font color=”#000000″>(</font><font color=”#000000″>Intensity1</font> <font color=”#434f54″>==</font> <font color=”#000000″>0</font> <font color=”#434f54″>&&</font> <font color=”#000000″>pIntensity1</font> <font color=”#434f54″>==</font> <font color=”#000000″>1</font><font color=”#000000″>)</font> <font color=”#000000″>{</font>
<b><font color=”#d35400″>Serial</font></b><font color=”#434f54″>.</font><font color=”#d35400″>write</font><font color=”#000000″>(</font><font color=”#00979c”>’a'</font><font color=”#000000″>)</font><font color=”#000000″>;</font>
<font color=”#000000″>}</font>
<font color=”#434f54″>// if (Intensity2 == 0 && pIntensity2 == 1) {</font>
<font color=”#434f54″>// Serial.write(‘b’);</font>
<font color=”#434f54″>// }</font>
<font color=”#000000″>pIntensity1</font> <font color=”#434f54″>=</font> <font color=”#000000″>Intensity1</font><font color=”#000000″>;</font>
<font color=”#000000″>pIntensity2</font> <font color=”#434f54″>=</font> <font color=”#000000″>Intensity2</font><font color=”#000000″>;</font>
<font color=”#000000″>}</font>
</pre>
Processing code:
import ddf.minim.*; Minim minim; AudioSample yx; AudioPlayer bgm2; AudioPlayer bgm; PImage img; PImage img2; boolean flag; boolean start=false; int WIN_SCORE=1500; import processing.serial.*; //int NUM_OF_VALUES_FROM_ARDUINO = 2; /** YOU MUST CHANGE THIS ACCORDING TO YOUR PROJECT **/ //int sensorValues[]; /** this array stores values from Arduino **/ //String myString = null; Serial myPort; // Create object from Serial class char val; char val2; class Obstacle { float x, y, size; boolean onScreen; color col; Obstacle(float x, float size, float horizon, color col) { this.x = x; this.y = horizon - size; this.size = size; this.col = col; this.onScreen = true; } void update(float speed) { /* check if offscreen */ this.onScreen = (this.x > -this.size); /* movement */ this.x -= speed; } void display() { fill(this.col); stroke(255); strokeWeight(2); rect(this.x, this.y, this.size, this.size); } boolean hits(TRex dino) { float halfSize = this.size / 2; float minimumDistance = halfSize + (dino.radius); // closest before collision /* find center coordinates */ float xCenter = this.x + halfSize; float yCenter = this.y + halfSize; float distance = dist(xCenter, yCenter, dino.x, dino.y); // calculate distance from centers return (distance < minimumDistance); // return result } } class TRex { float x, y, yVelocity, speed, radius; boolean onGround; TRex(float x, float y, float radius) { this.x = x; this.y = y; this.yVelocity = 0; this.speed = 1; this.onGround = true; this.radius = radius; // size of circle } void update(float platform) { float bottom = this.y + this.radius; // bottom pixel of circle float nextBottom = bottom + this.yVelocity; // calculate next frame's bottom if (bottom <= platform && nextBottom >= platform) { // next frame will be on platform this.yVelocity = 0; // reset velocity this.y = platform - this.radius; // don't go past platform this.onGround = true; } else if (platform - bottom > 1) { // nowhere near platform this.yVelocity += this.speed; // increase velocity this.onGround = false; } /* movement */ this.y += this.yVelocity; }; void jump () { this.yVelocity = -(this.radius * 0.7); // jump yx.trigger(); }; void display () { fill(#999999); stroke(255); strokeWeight(2); //ellipse(this.x, this.y, this.radius * 2,this.radius*2); image(img, this.x, this.y, this.radius*2, this.radius*2); }; } float horizon; float obstacleSpeed; float score; ArrayList<Obstacle> obstacles; TRex dino; TRex dino2; void setup() { fullScreen(); size(1920, 1080); //setupSerial(); textAlign(CENTER, CENTER); imageMode(CENTER); img2 = loadImage("dino.jpeg"); horizon = height - 40; obstacleSpeed = 6; init(); textSize(30); img=loadImage("kl.png"); minim = new Minim(this); yx=minim.loadSample("yx.wav"); bgm=minim.loadFile("bgm.mp3"); bgm2=minim.loadFile("fail-trombone-03.mp3"); String portName = Serial.list()[0]; myPort = new Serial(this, "/dev/cu.usbserial-1420", 9600); bgm2.loop(); bgm2.pause(); } void init() { float size = 40; dino = new TRex(size * 2, height - horizon, size); dino2 = new TRex(size * 3, height - horizon, size); obstacles=new ArrayList<Obstacle>(); score = 0; flag=true; } void startPage() { if (start)return ; background(190); fill(255); circle(width/2, height/2, 100); fill(0); text("START", width/2, height/2); if (mousePressed&&dist(mouseX, mouseY, width/2, height/2)<100) { start=true; bgm.loop(); } } void draw() { background(190); //getSerialData(); //printArray(sensorValues); image(img2, width/2, height/2); startPage(); if (!start)return ; drawHUD(); if ( myPort.available() > 0) { // If data is available, val = myPort.readChar(); println(val);// read it and store it in val if (val == 'a'&& dino.onGround) { dino.jump(); } if (val == 'b'&& dino2.onGround) { dino2.jump(); } handleLevel(frameCount); dino.update(horizon); dino2.update(horizon); handleObstacles(); noStroke(); endGame(); } } /** * draws horizon & score */ void drawHUD() { /* draw horizon */ stroke(255); strokeWeight(2); line(0, horizon, width, horizon); /* draw score */ noStroke(); text("Score: " + score, width / 2, 30); /* draw T-Rex */ dino.display(); dino2.display(); } /** * updates, draws, and cleans out the obstacles */ void handleObstacles() { for (int i = obstacles.size() - 1; i >= 0; i--) { if (flag) obstacles.get(i).update(obstacleSpeed); obstacles.get(i).display(); if (obstacles.get(i).hits(dino)) // if there's a collision { flag=false; bgm2.play(); } if (obstacles.get(i).hits(dino2)) // if there's a collision { flag=false; bgm2.play(); } if (!obstacles.get(i).onScreen) // if it's no longer showing obstacles.remove(i); // delete from array } } /** * speeds game up, pushes new obstacles, & handles score */ void handleLevel(int nn) { if (!flag)return ; if (nn % 30 == 0) { // every 0.5 seconds float n = noise(nn); // noisey if (n > 0.58) newObstacle(n); // push new obstacle if (nn % 120 == 0) // every 2 seconds obstacleSpeed *= 1.01; // speed up } score++; } /** * pushes random obstacle */ void newObstacle(float n) { color col = color(random(255), random(255), random(255)); float size = random(60) + 40; Obstacle obs = new Obstacle(width + size, size, horizon, col); obstacles.add(obs); } void keyPressed() { if (!flag)return ; if ((keyCode == UP || keyCode == 32) && dino.onGround) // jump if possible dino.jump(); if ((keyCode == UP || keyCode == 32) && dino2.onGround) // jump if possible dino2.jump(); } void endGame() { if (score>=WIN_SCORE)flag=false; if (flag)return ; //noLoop(); noStroke(); textSize(40); if (score>=WIN_SCORE) { text("YOU WIN", width/2, height/2); } else { text("GAME OVER", width / 2, height / 2); textSize(20); text("Press \'space\' to restart", width / 2, height / 2 + 20); bgm2.play(); bgm.pause(); } //bgm.rewind(); } void keyReleased() { if ((keyCode == UP || keyCode == 32)&&!start) { bgm2.pause(); start=true; bgm.loop(); } if ((keyCode == UP || keyCode == 32)&&!flag) { init(); bgm.loop(); } } //void setupSerial() { // printArray(Serial.list()); // myPort = new Serial(this, Serial.list()[ 3 ], 9600); // // WARNING! // // You will definitely get an error here. // // Change the PORT_INDEX to 0 and try running it again. // // And then, check the list of the ports, // // find the port "/dev/cu.usbmodem----" or "/dev/tty.usbmodem----" // // and replace PORT_INDEX above with the index number of the port. // myPort.clear(); // // Throw out the first reading, // // in case we started reading in the middle of a string from the sender. // myString = myPort.readStringUntil( 10 ); // 10 = '\n' Linefeed in ASCII // myString = null; // sensorValues = new int[NUM_OF_VALUES_FROM_ARDUINO]; //} //void getSerialData() { // while (myPort.available() > 0) { // myString = myPort.readStringUntil( 10 ); // 10 = '\n' Linefeed in ASCII // if (myString != null) { // String[] serialInArray = split(trim(myString), ","); // if (serialInArray.length == NUM_OF_VALUES_FROM_ARDUINO) { // for (int i=0; i<serialInArray.length; i++) { // sensorValues[i] = int(serialInArray[i]); // } // } // } // } //}