*victorious trumpet sounds* Wow! We made it. Because this was such a massive project, this is going to be a pretty long post, so buckle up and get ready to learn about how we created the Interactive Dartboard/Hangman Game…HangDarts!!!
During our brainstorm session we agreed on a couple of things right away.
- We want our finished product to incorporate both physical and digital elements (meaning we would somehow create an input using Arduino, then send it into Processing to make something happen).
- We want the interaction to be highly physical and almost visceral in nature. This would serve to draw participants into the interaction.
- We wanted to find a way to make it more meaningful to each individual user than something that just displayed shapes on a screen. In other words, we wanted to create some sort of game.
After some deliberation, we decided that the action of a person playing game of darts would be a great way to incorporate a physical interaction. After discussion about how to make a dartboard that was able to create a digital output, we decided that the most “genuine” way to create a dartboard was to incorporate several switches into the board itself. Each panel of the board would need to be covered in a permeable conductive material, so that when a conductive dart pierced it, it could connect the two layers, turning on the switch.
Having the project roughly planned like this was very encouraging. We seemed to have a really clear idea of what we wanted to do and it seemed like we weren’t taking on too much. Actually, there was no point in the process did we think that we were taking on too much for our given two-week time frame.
The problem with making an interactive dartboard was trying to create something more meaningful than the board itself. We needed to add another layer of meaning to our product. After discussing what we thought the board could actually do, we settled on making each panel of our board represent a different letter, then using those letters to play a game of hangman. At first, we planned on making a panel for each of the 26 letters, but realized that each letter would not be used the same amount. We also wanted to minimize the risk of failure by limiting the number of switches we would need to create. Eventually, he design that we settled on was a 1 meter wide grid split into ten panels. The top five panels would be associated with the letters: a, e, i, o, u, as vowels are the first letters you guess in a game of hangman. On the bottom row, we had sets of several consonants (bcdf, ghjk, lmnp, qrst, and vwxyz) in order to both condense our board, and make the game play slightly different from a traditional game of hangman.
The grouping of the consonants also helped to make the game both shorter and slightly easier for the people playing, considering that one of the hard parts of the game would already be successfully hitting each target. During user testing at the IM showcase our theory was supported as we found that participants began to use statistics to try to win the game (“If I hit the bcdf panel, I can make three words, and if I hit the lmnp panel I can only make one word so I’m going for the bcdf”). This was really interesting to see, not only because it was unexpected, but it also added an interesting cerebral aspect to the game. It made people think. This also made it fun for others to watch the participant play.
Once we had the design completed, we split up in order to actually make it (even though we worked at the same time in the same room). Tori began to work on coding the actual interface of the game, which would be displayed above the dartboard, while Kyle began working on the physical dartboard itself. Thus fed into our strengths and led to us having a stronger project overall. Because we were working next to each other, we could consult the other if we had a problem. After getting to a point where we could begin to incorporate our two parts together, we began working more closely on each other’s parts.
Our prototype was one of the main aspects of this project that gave us hope to create the full product. After testing out a dozen or so different combinations of materials, we decided that the most durable, reliable, and available solution would be to create the switches by gluing a piece of conductive fabric to each side of a piece of foam board. Each cell is individually connected to a breadboard where it serves as a switch: if there is a dart connecting the two sides, it would read as ON, and it it was removed, it would read as OFF. In addition to the actual switch, We had to design effective housing, to minimize the size and weight of the board, while also supporting the grid structure and effectively separate each switch, so that we wouldn’t get any errors. In addition, we needed to make it sturdy enough to withstand being hit by a stray dart.
In addition to the board prototype, We made a small button prototype with a set of 10 labeled buttons in order to start building the code that would send data over from arduino into the Processing program. Ideally, using this we would have been able to build the code and then just plug the board in once it was finished.
In order to bring our prototype to full scale, Kyle spent a lot of time at the laser cutter (booking 9 cutting sessions in total, because of errors with the cutter, and working around limited acrylic supplies). The base of the board was made out of two large pieces of 6 mm thick acrylic, which were bolted together with foam board and thinner acrylic to provide protection for the panels.
Once everything was cut, We took about two full tables in the IM lab with all of the fabric and foam spread out and just spent an hour or two drawing an outline, cutting, and wiring up all of the panels. Once everything was assembled, we went to activate everything, we found our first mistake: three of the wires connecting the panels to the arduino were too short. Luckily this was a quick fix. We just had to solder a little more wire onto what was already there. Last minute, we also added a small wooden board which we glued the arduino to, and a support arm, to make the entire system more maneuverable. We worked around this well, moving the angle of the arm so that Tori could solder the wires while Kyle worked on hand-drawing the letters onto the panels.
Now, back to the code! This bitch was a whole lot to write (about 300 lines in total, including classes and functions). Luckily though, most of it was logical. The basics of what we needed was: Recognize when the switch is turned on, check to see if the randomized word contains that letter. If it does, write the letter, if it doesn’t, draw the stick figure. Then there would be a reset button that clears the drawn stick figure and re-randomizes the word.
Up until then, Tori had handled the code rather well. However, there were a few things that just wouldn’t work. Luckily, Jack helped Tori figure that out. One such was the communication between Arduino and Processing.
Tori’s Comments on writing the code:
However, for the life of me, I could not figure out how to get my processing sketch to communicate with the arduino. And then Jack came in and fixed it. My issue? In a moment of complete student stress and exhaustion, we had began counting with 1 instead of 0. Cue an outraged cry of “THAT WAS IT???” as Jack pointed it out, we changed it, and it instantly worked. So. Frustrating.
He also helped me at the very end when I couldn’t figure out how to put in a reset button, which was another very easy fix. “Tori you’re calling this class to do all of the stuff. Just call the class again every time you push the button”. “Oooooohhhh”. Overall, Jack is a lifesaver and I thank him heavily for his help with this project.
At this point, I’m going to put the code.
Processing:
import processing.serial.*; Serial myPort; int buttonA; int buttonE; int buttonI; int buttonO; int buttonU; int buttonBCDF; int buttonGHJK; int buttonLMNP; int buttonQRST; int buttonVWXYZ; //int numWords = 17; //int number = int(random(0, numWords)); //to add the randomize word right into the reset button. Text text = new Text(); PFont f; PImage paper; //background for hangman PImage pin; //detail PImage hangman; //hangman drawing PImage sticky; //aesthetic sticky notes PImage cork; //cork background PImage dart; // for animation of the wrong letters PImage sadBoi; //sadBoi hours PImage torn; //gameover boolean reset = false; //for reset button int values[]= new int[10]; void setup() { fullScreen(); f = createFont("Comic Sans MS Bold Italic", 50); printArray(Serial.list()); //setup for send to Ardy String portname=Serial.list()[0]; println(portname); myPort = new Serial(this, portname, 9600); myPort.clear(); myPort.bufferUntil('\n'); cork = loadImage("cork.jpg"); paper = loadImage("paper.png"); pin = loadImage("pin.png"); hangman = loadImage("hangman.gif"); sticky = loadImage("sticky.png"); textFont(f); } void draw() { if (reset == true) { //setting the fail and pass counters back to 0 for reset button image(cork, 0, 0, width, height); //draw the basic background image(paper, 0, 0, 1000, 1000); image(pin, 440, 100, 80, 70); image(hangman, 170, 200, 600, 600); image(sticky, 1300, 70, 600, 400); text.display(); //text.fail = 0; //text.pass = 0; alphabet(); text.run(values); } //connected to line 64 } void serialEvent(Serial myPort) { //send to Ardy String s=myPort.readStringUntil('\n'); s=trim(s); if (s!=null) { //println(s); //to check the connections values = int (split(s, ',')); //I don't think we need this but whatever? if (values.length == 10) { buttonA = values[0]; buttonE = values[1]; buttonI = values[2]; buttonO = values[3]; buttonU = values[4]; buttonBCDF = values[5]; buttonGHJK = values[6]; buttonLMNP = values[7]; buttonQRST = values[8]; buttonVWXYZ = values[9]; } } myPort.write(buttonA); } void keyPressed() { //assign the reset button to the space bar if (key == ' ') { reset = true; text = new Text(); } }
class Text { boolean textAppearA = false; //so many booleans. there's gotta be a better way to do this. boolean textAppearE = false; boolean textAppearI = false; boolean textAppearO = false; boolean textAppearU = false; boolean textAppearB = false; boolean textAppearG = false; boolean textAppearL = false; boolean textAppearQ = false; boolean textAppearV = false; int fail = 0; //for drawing the stick figure based on errors int pass = 0; //for "You win" int numWords = 54; //how many words in the doc, could use message.length but I don't feel like it. int number = floor(random(0, numWords)); //randomize the words Text() { } void display() { for (int i = 0; i < 4; i++) { image(sticky, 850+(250*i), 600, 250, 250); } } void run(int[] _values) { sadBoi = loadImage("sad.png"); dart = loadImage("dart.png"); torn = loadImage("torn.png"); String[] message = loadStrings("words.txt"); fill(0); //setting the font color to black if (_values[0] == 1) { image(dart, 1255, 30, 150, 150); if (textAppearA == false) { if ((message[number].charAt(0) != 'a') && (message[number].charAt(1) != 'a') && (message[number].charAt(2) != 'a') && (message[number].charAt(3) != 'a')) { fail++; } if ((message[number].charAt(0) == 'a') || (message[number].charAt(1) == 'a') || (message[number].charAt(2) == 'a') || (message[number].charAt(3) == 'a')) { pass++; } textAppearA = true; } } if (textAppearA == true) { for (int s = 0; s < 4; s++) { if (message[number].charAt(s) == 'a') { text(message[number].charAt(s), 955 + (250*s), 730); } } } if (_values[1] == 1) { image(dart, 1355, 30, 150, 150); if (textAppearE == false) { //NOTE: MAKE ALL OF THIS INTO A FUNCTION SO THE CODE ISN'T AS LONG? if ((message[number].charAt(0) != 'e') && (message[number].charAt(1) != 'e') && (message[number].charAt(2) != 'e') && (message[number].charAt(3) != 'e')) { fail++; } if ((message[number].charAt(0) == 'e') || (message[number].charAt(1) == 'e') || (message[number].charAt(2) == 'e') || (message[number].charAt(3) == 'e')) { pass++; } textAppearE = true; } } if (textAppearE==true) { for (int s = 0; s < 4; s++) { if (message[number].charAt(s) == 'e') { text(message[number].charAt(s), 955 + (250*s), 730); } } } if ( _values[2] ==1) { image(dart, 1455, 30, 150, 150); if (textAppearI == false) { if ((message[number].charAt(0) != 'i') && (message[number].charAt(1) != 'i') && (message[number].charAt(2) != 'i') && (message[number].charAt(3) != 'i')) { fail++; } if ((message[number].charAt(0) == 'i') && (message[number].charAt(1) == 'i') || (message[number].charAt(2) == 'i') || (message[number].charAt(3) == 'i')) { pass++; } textAppearI = true; } } if (textAppearI==true) { for (int s = 0; s < 4; s++) { if (message[number].charAt(s) == 'i') { text(message[number].charAt(s), 955 + (250*s), 730); } } } if (_values[3] == 1) { image(dart, 1555, 30, 150, 150); if (textAppearO == false) { if ((message[number].charAt(0) != 'o') && (message[number].charAt(1) != 'o') && (message[number].charAt(2) != 'o') && (message[number].charAt(3) != 'o')) { fail++; } if ((message[number].charAt(0) == 'o') || (message[number].charAt(1) == 'o') || (message[number].charAt(2) == 'o') || (message[number].charAt(3) == 'o')) { pass++; } textAppearO = true; } } if (textAppearO==true) { for (int s = 0; s < 4; s++) { if (message[number].charAt(s) == 'o') { text(message[number].charAt(s), 955 + (250*s), 730); } } } if (_values[4] == 1) { image(dart, 1655, 30, 150, 150); if (textAppearU == false) { if ((message[number].charAt(0) != 'u') && (message[number].charAt(1) != 'u') && (message[number].charAt(2) != 'u') && (message[number].charAt(3) != 'u')) { fail++; } if ((message[number].charAt(0) == 'u') || (message[number].charAt(1) == 'u') || (message[number].charAt(2) == 'u') || (message[number].charAt(3) == 'u')) { pass++; } textAppearU = true; } } if (textAppearU ==true) { for (int s = 0; s < 4; s++) { if (message[number].charAt(s) == 'u') { text(message[number].charAt(s), 955 + (250*s), 730); } } } if (_values[5] == 1) { image(dart, 1335, 125, 150, 150); if (textAppearB == false) { if ((message[number].charAt(0) != 'b') && (message[number].charAt(1) != 'b') && (message[number].charAt(2) != 'b') && (message[number].charAt(3) != 'b') && (message[number].charAt(0) != 'c') && (message[number].charAt(1) != 'c') && (message[number].charAt(2) != 'c') && (message[number].charAt(3) != 'c') && (message[number].charAt(0) != 'd') && (message[number].charAt(1) != 'd') && (message[number].charAt(2) != 'd') && (message[number].charAt(3) != 'd') && (message[number].charAt(0) != 'f') && (message[number].charAt(1) != 'f') && (message[number].charAt(2) != 'f') && (message[number].charAt(3) != 'f')) { fail++; } if ((message[number].charAt(0) == 'b') || (message[number].charAt(1) == 'b') || (message[number].charAt(2) == 'b') || (message[number].charAt(3) == 'b') || (message[number].charAt(0) == 'c') || (message[number].charAt(1) == 'c') || (message[number].charAt(2) == 'c') || (message[number].charAt(3) == 'c') || (message[number].charAt(0) == 'd') || (message[number].charAt(1) == 'd') || (message[number].charAt(2) == 'd') || (message[number].charAt(3) == 'd') || (message[number].charAt(0) == 'f') || (message[number].charAt(1) == 'f') || (message[number].charAt(2) == 'f') || (message[number].charAt(3) == 'f')) { pass++; } textAppearB = true; } } if (textAppearB == true) { for (int s = 0; s < 4; s++) { if ((message[number].charAt(s) == 'b') || (message[number].charAt(s) == 'c') || (message[number].charAt(s) == 'd') || (message[number].charAt(s) == 'f')) text(message[number].charAt(s), 955 + (250*s), 730); } } if (_values[6] == 1) { image(dart, 1555, 125, 150, 150); if (textAppearG == false) { if ((message[number].charAt(0) != 'g') && (message[number].charAt(1) != 'j') && (message[number].charAt(2) != 'j') && (message[number].charAt(3) != 'j') && (message[number].charAt(0) != 'h') && (message[number].charAt(1) != 'h') && (message[number].charAt(2) != 'h') && (message[number].charAt(3) != 'h') && (message[number].charAt(0) != 'j') && (message[number].charAt(1) != 'j') && (message[number].charAt(2) != 'j') && (message[number].charAt(3) != 'j') && (message[number].charAt(0) != 'k') && (message[number].charAt(1) != 'k') && (message[number].charAt(2) != 'k') && (message[number].charAt(3) != 'k')) { fail++; } if ((message[number].charAt(0) == 'g') || (message[number].charAt(1) == 'j') || (message[number].charAt(2) == 'j') || (message[number].charAt(3) == 'j') || (message[number].charAt(0) == 'h') || (message[number].charAt(1) == 'h') || (message[number].charAt(2) == 'h') || (message[number].charAt(3) == 'h') || (message[number].charAt(0) == 'j') || (message[number].charAt(1) == 'j') || (message[number].charAt(2) == 'j') || (message[number].charAt(3) == 'j') || (message[number].charAt(0) == 'k') || (message[number].charAt(1) == 'k') || (message[number].charAt(2) == 'k') || (message[number].charAt(3) == 'k')) { pass++; } textAppearG = true; } } if (textAppearG == true) { for (int s = 0; s < 4; s++) { if ((message[number].charAt(s) == 'g') || (message[number].charAt(s) == 'h') || (message[number].charAt(s) == 'j') || (message[number].charAt(s) == 'k')) text(message[number].charAt(s), 955 + (250*s), 730); } } if ( _values[7] == 1) { image(dart, 1435, 180, 150, 150); if (textAppearL == false) { if ((message[number].charAt(0) != 'l') && (message[number].charAt(1) != 'l') && (message[number].charAt(2) != 'l') && (message[number].charAt(3) != 'l') && (message[number].charAt(0) != 'm') && (message[number].charAt(1) != 'm') && (message[number].charAt(2) != 'm') && (message[number].charAt(3) != 'm') && (message[number].charAt(0) != 'n') && (message[number].charAt(1) != 'n') && (message[number].charAt(2) != 'n') && (message[number].charAt(3) != 'n') && (message[number].charAt(0) != 'p') && (message[number].charAt(1) != 'p') && (message[number].charAt(2) != 'p') && (message[number].charAt(3) != 'p')) { fail++; } if ((message[number].charAt(0) == 'l') || (message[number].charAt(1) == 'l') || (message[number].charAt(2) == 'l') || (message[number].charAt(3) == 'l') || (message[number].charAt(0) == 'm') || (message[number].charAt(1) == 'm') || (message[number].charAt(2) == 'm') || (message[number].charAt(3) == 'm') || (message[number].charAt(0) == 'n') || (message[number].charAt(1) == 'n') || (message[number].charAt(2) == 'n') || (message[number].charAt(3) == 'n') || (message[number].charAt(0) == 'p') || (message[number].charAt(1) == 'p') || (message[number].charAt(2) == 'p') || (message[number].charAt(3) == 'p')) { pass++; } textAppearL = true; } } if (textAppearL == true) { for (int s = 0; s < 4; s++) { if ((message[number].charAt(s) == 'l') || (message[number].charAt(s) == 'm') || (message[number].charAt(s) == 'n') || (message[number].charAt(s) == 'p')) text(message[number].charAt(s), 955 + (250*s), 730); } } if (_values[8] == 1) { image(dart, 1335, 250, 150, 150); if (textAppearQ == false) { if ((message[number].charAt(0) != 'q') && (message[number].charAt(1) != 'q') && (message[number].charAt(2) != 'q') && (message[number].charAt(3) != 'q') && (message[number].charAt(0) != 'r') && (message[number].charAt(1) != 'r') && (message[number].charAt(2) != 'r') && (message[number].charAt(3) != 'r') && (message[number].charAt(0) != 's') && (message[number].charAt(1) != 's') && (message[number].charAt(2) != 's') && (message[number].charAt(3) != 's') && (message[number].charAt(0) != 't') && (message[number].charAt(1) != 't') && (message[number].charAt(2) != 't') && (message[number].charAt(3) != 't')) { fail++; } if ((message[number].charAt(0) == 'q') || (message[number].charAt(1) == 'q') || (message[number].charAt(2) == 'q') || (message[number].charAt(3) == 'q') || (message[number].charAt(0) == 'r') || (message[number].charAt(1) == 'r') || (message[number].charAt(2) == 'r') || (message[number].charAt(3) == 'r') || (message[number].charAt(0) == 's') || (message[number].charAt(1) == 's') || (message[number].charAt(2) == 's') || (message[number].charAt(3) == 's') || (message[number].charAt(0) == 't') || (message[number].charAt(1) == 't') || (message[number].charAt(2) == 't') || (message[number].charAt(3) == 't')) { pass++; } textAppearQ = true; } } if (textAppearQ == true) { for (int s = 0; s < 4; s++) { if ((message[number].charAt(s) == 'q') || (message[number].charAt(s) == 'r') || (message[number].charAt(s) == 's') || (message[number].charAt(s) == 't')) text(message[number].charAt(s), 955 + (250*s), 730); } } if (_values[9] ==1) { image(dart, 1590, 250, 150, 150); if (textAppearV == false) { if ((message[number].charAt(0) != 'v') && (message[number].charAt(1) != 'v') && (message[number].charAt(2) != 'v') && (message[number].charAt(3) != 'v') && (message[number].charAt(0) != 'w') && (message[number].charAt(1) != 'w') && (message[number].charAt(2) != 'w') && (message[number].charAt(3) != 'w') && (message[number].charAt(0) != 'x') && (message[number].charAt(1) != 'x') && (message[number].charAt(2) != 'x') && (message[number].charAt(3) != 'x') && (message[number].charAt(0) != 'y') && (message[number].charAt(1) != 'y') && (message[number].charAt(2) != 'y') && (message[number].charAt(3) != 'y') && (message[number].charAt(0) != 'z') && (message[number].charAt(1) != 'z') && (message[number].charAt(2) != 'z') && (message[number].charAt(3) != 'z')) { fail++; } if ((message[number].charAt(0) == 'v') || (message[number].charAt(1) == 'v') || (message[number].charAt(2) == 'v') || (message[number].charAt(3) == 'v') || (message[number].charAt(0) == 'w') || (message[number].charAt(1) == 'w') || (message[number].charAt(2) == 'w') || (message[number].charAt(3) == 'w') || (message[number].charAt(0) == 'x') || (message[number].charAt(1) == 'x') || (message[number].charAt(2) == 'x') || (message[number].charAt(3) == 'x') || (message[number].charAt(0) == 'y') || (message[number].charAt(1) == 'y') || (message[number].charAt(2) == 'y') || (message[number].charAt(3) == 'y') || (message[number].charAt(0) == 'z') || (message[number].charAt(1) == 'z') || (message[number].charAt(2) == 'z') || (message[number].charAt(3) == 'z')) { pass++; } textAppearV = true; } } if (textAppearV == true) { for (int s = 0; s < 4; s++) { if ((message[number].charAt(s) == 'v') || (message[number].charAt(s) == 'w') || (message[number].charAt(s) == 'x') || (message[number].charAt(s) == 'y') || (message[number].charAt(s) == 'z')) { text(message[number].charAt(s), 955 + (250*s), 730); } } } pushStyle(); noFill(); //make stick figure "transparent" strokeWeight(10); if (fail >= 1) { ellipse(580, 360, 100, 100); } if (fail >= 2) { line(580, 420, 580, 580); } if (fail >= 3) { line(580, 580, 550, 640); line(580, 580, 610, 640); } if (fail >= 4) { line(580, 440, 550, 520); line(580, 440, 610, 520); } if (fail >= 4) { //game over pushMatrix(); pushStyle(); textSize(90); rotate(-.4); fill(255, 0, 0); image(torn, 175, height/2+100, 556*1.75, 215*1.75); text("GAME OVER", 420, 850); popStyle(); popMatrix(); for (int s = 0; s < 4; s++) { text(message[number].charAt(s), 955 + (250*s), 730); } image(sadBoi, 550, 327, 60, 60); //dartSize = 0; } if (pass >= 4) { pushMatrix(); pushStyle(); textSize(90); rotate(-.4); fill(0, 150, 0); image(torn, 175, height/2+100, 556*1.75, 215*1.75); text("YOU WIN!", 420, 850); popStyle(); popMatrix(); } //if (keyPressed && (key == 'k')) { //work this into the reset button // number = int(random(0, numWords)); //} } }
void alphabet() { pushStyle(); fill(0); text("a", 1385, 175); text("e", 1485, 175); text("i", 1585, 175); text("o", 1685, 175); text("u", 1785, 175); text("bcdf", 1420, 255); text("ghjk", 1640, 255); text("lmnp", 1530, 325); text("qrst", 1420, 395); text("vwxyz", 1640, 395); popStyle(); }
Arduino:
int a = 11; //pin numbers don't worry about this int e = 2; int i = 3; int o = 4; int u = 5; int bcdf = 6; int ghjk = 7; int lmnp = 8; int qrst = 9; int vwxyz = 10; void setup() { Serial.begin(9600); // Serial.println("0,0,0,0"); establishContact(); } void loop() { if (Serial.available() > 0) { int inByte = Serial.read(); int aRead = digitalRead(a); int eRead = digitalRead(e); int iRead = digitalRead(i); int oRead = digitalRead(o); int uRead = digitalRead(u); int bcdfRead = digitalRead(bcdf); int ghjkRead = digitalRead(ghjk); int lmnpRead = digitalRead(lmnp); int qrstRead = digitalRead(qrst); int vwxyzRead = digitalRead(vwxyz); Serial.print(aRead); Serial.print(','); delay(1); Serial.print(eRead); Serial.print(','); delay(1); Serial.print(iRead); Serial.print(','); delay(1); Serial.print(oRead); Serial.print(','); delay(1); Serial.print(uRead); Serial.print(','); delay(1); Serial.print(bcdfRead); Serial.print(','); delay(1); Serial.print(ghjkRead); Serial.print(','); delay(1); Serial.print(lmnpRead); Serial.print(','); delay(1); Serial.print(qrstRead); Serial.print(','); delay(1); Serial.println(vwxyzRead); // Serial.println(','); } } void establishContact() { while (Serial.available() <= 0) { Serial.println("0,0,0,0,0,0,0,0,0,0"); // send an initial string delay(300); } }
Now, comes the time for the IM showcase. The big night. We were nervous, honestly. What if something went wrong? What if it didn’t work? What if the people who user tested it were just being nice? We had done user testing and had so much great feedback…oh right…User testing..
Before we had everything totally done, we asked some friends to participate in some User Testing. Here are the videos.
The users gave us a lot of really solid feedback. For example, one user said it would be cool to try and find a way to make the game multiplayer, have one person enter the word and the other person guess it. While we agreed that would be really cool, we thought it might get too crazy and be unfair if people could just add things that weren’t words.
Also, we learned that it is super fun and really satisfying to play. Watching the drawings come up right when the dart goes into the board really signifies that there is an interaction taking place between the user and the game. We received this feedback from multiple people. Every time people saw one person testing it, others would ask to play as well, even when it wasn’t completely finished.
When we moved into our final showcase space, we got some more user testing and feedback. It was suggested that we shine a spotlight on the board so people can see the letters better. we also decided on a set throwing distance as a way of controlling the space more and making it safer to use in the crowded Showcase space. We also did this because many users tried to throw from too close to the board, which would mean their dart wouldn’t have enough momentum to effectively pierce both layers of the board.
Overall, All of our user testers were really encouraging.
Okay back to the IM showcase. We were nervous as hell. But as soon as the show started, and the public began interacting with our game, it was impossible not to become overcome with a sense of pride. Throughout the entire two-hour-long event, there was nearly always a line of people waiting to play, while others gathered around watching. Bystanders would help to guess the word, and often take pictures and videos of the game as it was played. We believe this was the most delightful surprising discovery of the entire experience. Once the room was full, people began interacting with our board in an entirely new way. It was no longer a game of person vs. board, but of everybody trying to guess the word. People would even switch off who threw darts. The game became so multiplayer without us even trying. One person would throw the darts and four others would yell suggestions for letters. Or two friends would come and throw darts together while their other friends looked on. There was never just one person playing this game. It was incredible to watch so many people have fun with something that we made.
Another thing that we didn’t really think about was the replayability of the game. Throughout the showcase, the same people kept coming back to play again and, bringing their friends with them. Each time they played, they still had fun! Even we, the creators remained entertained the entire night, watching people throw darts over and over.
All in all, it was so much fun and so rewarding to see everyone have such a good experience with our project. Thank you for such a great semester!
Here are some pictures and videos of the IM showcase.