- A. PROJECT TITLE – YOUR NAME – YOUR INSTRUCTOR’S NAME
Saloon Bar Shoot Out – Lya – Andy
2. CONTEXT AND SIGNIFICANCE
My previous research was mostly about projects that worked like small games, and it makes me want to also make a small game. The Reading & Analysis II assignment I did helped me understand how the Gulf of Execution and Evaluation efficiently guide users to accomplish the project. My teammate Irene and I decided to merge and re-create some classic shooting games. The project is targeted at all people who would like to kill some time by playing short little games, and considering the American West art style, people who are interested in its culture might be more associated (one of the users said that’s probably a stimulator of what his ancestors do every day).
3. CONCEPTION AND DESIGN
The game itself is quite straightforward because most of our audiences have the experience of playing a shooting game. Users would see three targets come up from 3 sides of the machine, and the targets in each play stay in different positions. Users would use a “gun” with a button and a laser. The users would press the button, and if the laser activates one of the three sensors, it would activate the associated servo and the target would go back behind the machine. If users hit all the targets within 20 seconds, they win. The whole interface is designed similarly to common shooting games so it would be easy for the audiences to use. Although this seems enough, there is surprisingly still a lot of necessary information to be provided in this project, and it turns out that a buzzer is really helpful for this. Different from some other projects, our project is to create a game machine. Therefore it creates a natural need for an exciting atmosphere, and a starting melody played by a buzzer could be really useful for this. Besides, creating a game also means that there must be wins and losses. The buzzer is also used to display 2 different melodies at the end of the playthrough, so the win or loss results can be effectively conveyed.
4. FABRICATION AND PRODUCTION
We thought seeing the target coming down as a result of success was quite clear for the user, so we did not design any other things to stress it. However, during the user test, we realized that the target is hard to hit because it is moving and the sensor itself is small, and the players might be confused about whether the machine was working because they could not see whether they successfully hit it. We decided to add a hint about it that is not visual, so we used the buzzer that plays sound in different pitches when the button is pushed, and the sound difference would make players more sure that the action they just did can/cannot activate the sensor and lead to further changes.
The players in the user testing session also told us that the game was too easy if the target kept still, so we adjusted the code to make the targets move back and forth. This is the part where we spend most time and meet most of the difficulties. We realized a code based on for loops could not work well because we need three loops to make the three servos move, but the system could only execute one for loop at a time so it’s impossible to make the three servos work together. Thanks to Prof. Andy’s help, we used an advanced data type to track the time changes and execute further actions during a specific amount of time:
static unsigned long timestamp = millis() ; unsigned long now = millis() ; PERIOD = 25 ; ... if( now - timestamp > PERIOD_MS ) { timestamp = now ; // do something every PERIOD_MS here ... }
Then there came a new problem: the targets wouldn’t get down even after we hit it. So, when we hit a target, it stays up, and we can continuously hit it until our score is 3 and we “win”, which is not what we wanted. Eventually, we made a different boolean for each servo that defines if they are weeping or not.
if (stage == 1) { if(servo1sweep == true){ if (now - timestamp > 25) { timestamp = now; degree = degree + inc; if (degree >= 180 || degree <= 90) { inc *= -1; } servo1.write(degree); } }
5. CONCLUSIONS
In my previous reading respond assignment, I was saying that a good interactive project should offer abundant context and materials for users to create their unique work. So I think that we did pretty good in this project because we went through nearly every situation that might broke the experience and found ways to save them.
However, what doesn’t align with my definition of interaction is that there are not enough possibilities for the plot to go in diverse directions. There’s only one way to experience the whole project and the results are binary, so it would only leave users with a very simple impression. Next time I would consider more about this from the start of the project: I should brainstorm more constructive and creative ideas at first. But for just this project, the way of making the process more interesting it to add multiple levels (fixed targets, slowing targets, fast targets. etc.) or add a restart button to make repeat the play through experience.
A lot of people also suggested that the decoration was too simple at first, so we brainstormed a theme for it and got the inspiration from the old Western American cowboy movies.
6. DISASSEMBLY
We sorted the cables and returned most of the cardboard to recycle:DDDD
7. APPENDIX
These are the visual documentations of our final results!
Full code:
#include <Servo.h> int degree1 = 45; int inc1 = 1; int degree2 = 45; int inc2 = 1; int degree3 = 90; int inc3 = 1; static unsigned long timestamp1 = millis(); unsigned long now1 = millis(); static unsigned long timestamp2 = millis(); unsigned long now2 = millis(); static unsigned long timestamp3 = millis(); unsigned long now3 = millis(); Servo servo1; Servo servo2; Servo servo3; bool servo1sweep = true; bool servo2sweep = true; bool servo3sweep = true; int score = 0; long time; long seconds; int prebuttonval; int buttonval; bool tonePlay = false; int stage = 0; long lastChange; int losemelody[] = { 220, 262, 247, 220, 247 }; int losenoteDurations[] = { 1, 1, 2, 2, 1 }; int winmelody[] = { 440, 440, 440, 440, 440, 440, 392, 392, 440 }; int winnoteDurations[] = { 1, 3, 3, 3, 1, 1, 1, 1, 1 }; void setup() { Serial.begin(9600); pinMode(4, INPUT); seconds = 30000; Serial.println("initializing"); } void loop() { servo1.attach(10); servo2.attach(11); servo3.attach(9); now1 = millis(); now2 = millis(); now3 = millis(); buttonval = digitalRead(4); if (stage == 0) { tone(6, 262, 400); delay(800); tone(6, 262, 400); delay(800); tone(6, 262, 400); delay(800); tone(6, 524, 400); Serial.println("game start"); stage = 1; } if (stage == 1) { Serial.print(score); if (servo1sweep == true) { if (now1 - timestamp1 > 25) { timestamp1 = now1; degree1 = degree1 + inc1; if (degree1 >= 135 || degree1 <= 45) { inc1 *= -1; } servo1.write(degree1); } } if (servo2sweep == true) { if (now2 - timestamp2 > 25) { timestamp2 = now2; degree2 = degree2 + inc2; if (degree2 >= 135 || degree2 <= 45) { inc2 *= -1; } servo2.write(degree2); } } if (servo3sweep == true) { if (now3 - timestamp3 > 25) { timestamp3 = now3; degree3 = degree3 + inc3; if (degree3 >= 180 || degree3 <= 90) { inc3 *= -1; } servo3.write(degree3); } } if (buttonval != prebuttonval && millis() - lastChange > 20) { // button just pushed tone(6, 392, 100); int sensor1 = analogRead(A0); int sensor2 = analogRead(A1); int sensor3 = analogRead(A2); if (sensor1 >= 800) { tone(6, 524, 100); servo1sweep=false; degree1 = 0; servo1.write(degree1); score++; } if (sensor2 >= 1000) { tone(6, 524, 100); servo2sweep=false; degree2 = 0; servo2.write(degree2); score++; } if (sensor3 >= 970) { tone(6, 524, 100); servo3sweep=false; degree3 = 0; servo3.write(degree3); score++; } lastChange = millis(); prebuttonval = buttonval; } if (millis() <= seconds && score >= 3) { degree1 = 0; degree2 = 0; degree3 = 0; servo1.write(degree1); servo2.write(degree2); servo3.write(degree3); stage = 2; Serial.println("you win"); } if (millis() >= seconds) { degree1 = 0; degree2 = 0; degree3 = 0; servo1.write(degree1); servo2.write(degree2); servo3.write(degree3); stage = 3; Serial.println("you lose"); } } if (stage == 2) { if (tonePlay == false) { for (int winNote = 0; winNote < 9; winNote++) { int noteDuration = 400 / winnoteDurations[winNote]; tone(6, winmelody[winNote], noteDuration); int pauseBetweenNotes = noteDuration * 1.10; delay(pauseBetweenNotes); noTone(6); tonePlay = true; } } } if (stage == 3) { if (tonePlay == false) { for (int loseNote = 0; loseNote < 5; loseNote++) { int noteDuration = 800 / losenoteDurations[loseNote]; tone(6, losemelody[loseNote], noteDuration); int pauseBetweenNotes = noteDuration * 1.10; delay(pauseBetweenNotes); noTone(6); tonePlay = true; } } } }
Material List:
• 3 Light sensors
• Arduino
• breadboard
• Wires
• 3 servos and corresponding screws
• 1 laser
• 1 button
• 1 buzzer
• 3 resistors
• cardboard
• soldering equipment
• pens, paper, market
• knife and scissors
• computer and wire to connect
Reference For Poster Art:
https://www.rodeohire.com/category/all-products/83/saloon-bar-shoot-out