FINAL INDIVIDUAL REFLECTION: X-Wing by Jiamu Wu, instructed by Rodolfo Cossovich

CONCEPTION AND DESIGN:

  1. My earliest conception was an alarm clock driven by Arduino, 2 Neopixel 8*8 boards and some weird components such as a fan, which arose from those awkward experiences when my own clock woke both my roomates up while I still slept like a dog. I came to realize that noise is not always the most effective way to bring one off bed, and sometimes it makes trouble, so I came up with an idea with lots of prank elements: Just as usual, the Neopixels would be used as the clock display. The difference was that you can adjust the alarm mode according to the sleeping habits of your roommates and your own characters. For example, one of the plans was that when it was the time, the clock would first give out tentative ringing tones, and if the user wakes up in time, by doing 5 full bicep curls in 10 seconds the alarm would be totally turned off. However, if this doesn’t work, a powerful fan attached to the clock would be activated and blow you till you wake and do something. It would repeat every 5 minutes until totally turned off. You can also disable the ringing tones and leave the fan only. With the help of pressure sensors in the beds, the system can also judge the conditions of  your roommates to make judgements whether to forbid some functions. The interactivity lies on that the system can detect the conditions of the residents and automatically make adjustments and the users perform certain tasks to get corresponding results. To achieve this interactivity, I designed several buttons for the device to ease operation. Sadly, they were not accomplished before the user testing. However, I did see something made by the classmates that interested me, such as a tyre pump game about the Disney-Pixar movie Up. So I started to think about adding more animated and interactive effects to my work.
  2. I forgot to bring my kits and other materials back from the shelf before the big clean and I lost them. What’s worse, a large part of my codes were not preserved after I updated Arduino. So I decided to start all over and focused more on software than hardware. Making a video game became a practical choice. After evaluating several conceptions, I chose to make a 2D space shooting game with Star Wars elements.

FABRICATION AND PRODUCTION:

 

The goal of my alarm clock is to bring a customized, comfortable and even a little comical alarm service.

Core materials:

  1. Cardboards
  2. Arduino uno *1
  3. Breadboard *1
  4. Neopixel 8*8 *1
  5. Several cables
  6. 5V motor with fan blades *1
  7. Tilt sensor *1
  8. Yellow LED *1
  9. Tapes
  10. Buzzer *1
  11. Printing paper.

I chose the materials based upon these principles:

  1. Accessibility. —— All materials are accessed either in my toolkit or equipment room in 826 so that it’s easy to fix the broken parts and find alternatives in time.
  2. Machinability. —— I had to make sure the materials are easy to work on because time didn’t allow me to spent too long on processing them. I abandoned the thought of 3D printing or laser cutting but chose cardboards as the main materials.

I chose the form/element based upon these principles:

  1. Durability. —— It’s very important to all interactive works, but especially to a physical game like this, which requires solid devices with simple external form and reliable structure.
  2. Entertaining aspect. —— This is why I chose to build a miniature scene. It strengthened the contrast of the volume and made the alarm clock stick out as the main role. It also reflected the modern people’s fear of unpunctuality in a humorous but ironic way. 

    1. Frame. 
2. Bracket. Make use of the natural tenacity of the cardboards to guarantee the tension among the components and maintain the shape. Later fixed at the corners and the flips. I chose the thin and compact cardboards for this use.
4. Installing the Neopixel. I had intended to get two for it, but finally only got one due to the finiteness of equipments.

 

5.Interior. Abundant space for wires and extra devices.
6. Exterior. On the top are two flaps which can be opened separately for a check. A square hole is preserved for the USB port.
7. Connecting cables.
8. A tilt sensor disassembled from a previous work, hopefully which would’ve been assisting the bicep curls calculator.
9. A fan was added to the device to blow the user awake. The wires stretching from the clock were strapped with tapes. A yellow led was added to the breadboard as an indicator light, which would be telling the state of the sensor. A capacitor was added to guarantee the function of the tilt sensor.
10. Walls were being built to preserve the cables on the breadboard. The bases of the devices were fixed on the cardboard with a group of right triangles which had the same acute angles. 
11. The breadboard was almost fully enclosed, except space left for operating the button. I built a simulative scene of a bedroom but in much smaller size, so I might’ve been able to display the function with less materials. Also, the power of the fan would be more obvious in this way. You can see the following items: a cardboard bed with a pillow and four tiny legs, a striped quilt made by printing paper, a paper Dwayne Johnson, a paper dog, a lamp made by paper, cardboard and a piece of wire, and a cardboard drawer bearing the weight of the wires. According to my several experiments, the fan was strong enough to blow away all the furniture.
12. Partial close-up

There were also corresponding codes which were not accomplished. Sadly, this was as far as I went before all these creations as along with my kits were thrown away on Friday because I forgot to take them before the big clean. So later I designed the space shooting game called X-wing as a compensation.

Demonstration:

Codes: 

import ddf.minim.spi.*;
import ddf.minim.signals.*;
import ddf.minim.*;
import ddf.minim.analysis.*;
import ddf.minim.ugens.*;
import ddf.minim.effects.*;
import processing.dxf.*;
import processing.sound.*;
SoundFile sound;
PImage img;

int loopcount;
float life = 100;
float energy = 100;
PVector[] enemy = new PVector[5];
PVector[] direction = new PVector[5];
PVector[] bullet = new PVector[5];
PVector[] direction1 = new PVector[5];
int flag = 0;
int start = 0;
int count;
float time = 0;
float lasting = 0;
int max = 2;
int level = 1;
int invade;
void setup() {
  size(600, 600);
  background(0);
  img = loadImage("xwing3.png");
  for (int index = 0; index < 5; index++ )
  {
    enemy[index] = new PVector(random(width/6, width*5/6), 10);
    direction[index] = new PVector(0, 2);
  }
  for (int index = 0; index < 5; index++ )
  {
    bullet[index] = new PVector(mouseX, mouseY);
    direction1[index] = new PVector(0, 100);
  }
  // minim = new Minim(this);
  //player = minim.loadFile("s.mp3", 2048);
  //player.play();
}

void draw() {

  if (start == 0) {
    background(0);
    fill(#E3E3E3);
    textAlign(CENTER);
    textSize(44);
    fill(#EE6AA7);
    text("START", 0.5 * width, 0.5 *  height);
    fill(#E3E3E3);
    start = 0;
    time = 0;
    life = 100;
    count = 0;
    flag = 0;
    level = 1;
    energy = 100;
    invade = 0;
  }

  if (start == 1) {
    if (lasting == 1) {
      start = 5;
    }
    if (count <= 50) {
      max = 1;
      level = 1;
    }
    if (count <= 180  && count > 50) {
      max = 2;
      level = 2;
    }
    if (count <= 400  && count > 180 ) {
      max = 3;
      level = 3;
    }
    if (count  > 400  ) {
      if (max < 5) {
        max = 4 + (int)time;
      } else {
        max = 12;
      }
      level = 5;
    }
    time += 0.01;
    if (life <= 0) {
      start = 2;
    }
    if (invade >= 10) {
      start = 2;
    }

    if (life < 100 && life > 0)
    {
      life += 0.03;
    } else {
      life = 100;
    }
    for (int index = 0; index < 5; index++) {
      if (direction[index].y < max)
        direction[index].y *= 1.005;
    }

    background(0);
    noStroke();
    fill(#9932CC);
    fill(  #F8F8FF);
    fill(#E3E3E3);
    noStroke();
    for (int index = 0; index < 5; index++) {
      float dis = sqrt((mouseX - enemy[index].x)*(mouseX - enemy[index].x)+(mouseY - enemy[index].y)*(mouseY - enemy[index].y));
      if (dis <= 30) {
        life-= 20;
        ellipse(mouseX, mouseY, 70, 70);
        enemy[index].y = 10;
        enemy[index].x = random(width/6, width*5/6);
      }
    }

    for (int index = 0; index < 5; index++)
      if (enemy[index].y >= 569 && enemy[index].y <= 570) {
        if (count > 0) {
          count --;
        }
        if (invade <= 10) {
          invade++;
        }
      }

    textAlign(LEFT);
    fill(255);
    textSize(0.03*width);
    text("SCORE: "+count, 0.8*width, 0.1*height);
    text("TIME: "+time, 0.8*width, 0.05*height);
    text("LEVEL: "+level, 0.8*width, 0.15*height);
    if (0<= invade && invade <= 3) {
      fill(255);
    }
    if (4<= invade && invade <= 6) {
      fill(255, 240, 0);
    }
    if (7<= invade && invade <= 8) {
      fill(255, 200, 0);
    }
    if (invade >= 9) {
      fill(255, 0, 0);
    }

    text("INVASION: "+invade, 0.8*width, 0.2*height);
    fill(255);
    text("POSITION:"+mouseX+","+mouseY, 20, 60);

    fill(#F8F8FF);
    for (int index = 0; index < 5; index++)
      ellipse(enemy[index].x, enemy[index].y, 30, 30);

    fill(  #F8F8FF);
    for (int index = 0; index < 5; index++)
      enemy[index].y += direction[index].y;
    for (int index = 0; index < 5; index++)
    {
      if (enemy[index].y >= 580 )
      {
        enemy[index].y = 10;
        enemy[index].x = random(100, 500);
      }
    }
    if (mousePressed)
    {
      if (energy > 0) {
        flag = 1;
        fill(255, random(20, 60), 0);
        stroke(255, random(20, 60), 0);
        strokeWeight(3);
        for (int index = 0; index < 5; index++)
          line(bullet[index].x-52, bullet[index].y+10, bullet[index].x-52, bullet[index].y-10);
        for (int index = 0; index < 5; index++)
          line(bullet[index].x+52, bullet[index].y+10, bullet[index].x+52, bullet[index].y-10);
        for (int index = 0; index < 5; index++)
          line(bullet[index].x-48, bullet[index].y+10, bullet[index].x-48, bullet[index].y-10);
        for (int index = 0; index < 5; index++)
          line(bullet[index].x+48, bullet[index].y+10, bullet[index].x+48, bullet[index].y-10);
        //for (int index = 0; index < 5; index++)
        //  line(bullet[index].x-5, bullet[index].y+10, bullet[index].x-5, bullet[index].y-10);
        //for (int index = 0; index < 5; index++)
        //  line(bullet[index].x+5, bullet[index].y+10, bullet[index].x+5, bullet[index].y-10);

        fill(  #F8F8FF);
        for (int index = 0; index < 5; index++)
          bullet[index].y -= direction1[index].y;
        for (int index = 0; index < 5; index++)
        {
          if (bullet[index].y <= 0)
          {
            bullet[index].y = mouseY;
            bullet[index].x = mouseX;
          }
        }
        energy -= 0.3;
        if (energy <= 0) {
          flag = 0;
        }
        for (int index = 0; index < 5; index++) {
          if (enemy[index].x - mouseX <= 65 && enemy[index].x - mouseX >= 35 && enemy[index].y - bullet[index].y <= 30 && enemy[index].y - bullet[index].y >= -30) {
            ellipse(enemy[index].x, enemy[index].y, 30, 30 );
            count++;
            enemy[index].y = -300;
            enemy[index].x = random(100, 500);
            if (energy <= 90) {
              energy = energy + 10;
            } else if (energy > 90) {
              energy = 100;
            }
          }
          if (enemy[index].x - bullet[index].x <= -35 && enemy[index].x - bullet[index].x >= -65 && enemy[index].y - bullet[index].y <= 30 && enemy[index].y - bullet[index].y >= -30) {
            ellipse(enemy[index].x, enemy[index].y, 30, 30 );
            count++;
            enemy[index].y = -300;
            enemy[index].x = random(100, 500);
            if (energy <= 90) {
              energy = energy + 10;
            } else if (energy > 90) {
              energy = 100;
            }
          }
        }
      }
    }
    stroke(255);
    strokeWeight(2);
    line(mouseX-10, mouseY, mouseX+10, mouseY);
    line(mouseX, mouseY-10, mouseX, mouseY+10);
    noStroke();
    fill(255, 0, 0);
    rect(10, 30, 30 * 0.1 * life, 5);
    fill(20-0.2*energy, 20+2*energy, 200+0.5*energy);
    rect(10, 20, 3 * energy, 5);
    image(img, mouseX-62, mouseY-75);
  }

  if (start == 2) {
    background(0);
    fill(#E3E3E3);
    textAlign(CENTER);
    textSize(24);
    fill(#EE6AA7);
    text("YOU LOSE.", 0.5 * width, 0.3 *  height);
    text("SURVIVAL TIME: "+time+" seconds", 0.5 * width, 0.5 *  height);
    text("SCORE:"+count, 0.5 * width, 0.7 *  height);
    fill(#E3E3E3);
  }

  if (start == 3) {
    background(0);
    fill(255);
    textSize(24);
    textAlign(LEFT);
    text("SCORE: "+count, 450, 50);
    text("TIME: "+time, 450, 20);
    text("LEVEL: "+level, 450, 80);
    text("INVASION: "+invade, 450, 110);
    time = 0;
    life = 100;
    count = 0;
    flag = 0;
    level = 1;
    energy = 100;
    invade = 0;

    fill(#9932CC);
    fill(#F8F8FF);
    fill(#E3E3E3);
    ellipse(mouseX, 580, 30, 30);
    textAlign(CENTER);
    textSize(14);
    fill( #EE6AA7);
    stroke(#EE6AA7);
    textSize(22);
    //if (start == 5) {
    text("RULE", 300, 150);
    textAlign(LEFT);
    text("1. Move your mouse to control the ship", 10, 190);
    text("2. Press the mouse to open fire ", 10, 230);
    text("3, Dodge the enemies to avoid harm", 10, 270);
    text("4. Ammo and HP are shown on the top left", 10, 310);
    text("5. Press s to stop during the process", 10, 350);
    text("6. Do not let in >= 10 enemies", 10, 390);
    textAlign(CENTER);
    text("[CLICK ANYWHERE TO CONTINUE]", 300, 450);
    stroke(#EE6AA7);
    fill(#E3E3E3);
  } 
}

void mousePressed() {

  if (start == 3) {
    //if (mousePressed && mouseX >= 200 && mouseX <= 500 && mouseY >= 400 && mouseY <= 500)
    start = 1 ;
  }
  if (start == 2) {
    start = 0;
  }
  if (start == 0 && mouseX > (width * 0.4) && mouseX < (width * 0.6) && mouseY > (height * 0.4) && mouseY < (height * 0.6)) {
    start = 3;   }
}

//pause in the process
void keyPressed() {
  if (key == 's') {
    lasting = 1 - lasting;
    if (lasting == 0)
      start = 1;
  }
}

CONCLUSIONS:

Though my task changed in the midway, the goal didn’t change. As is mentioned above, my goal is to design something that is smart, utilitarian and relaxing with a little surprise. Below is aimed at the second work which is relatively more accomplished.

From my perspective, my project aligns with the definition of interaction in these ways:

  1. Offering necessary tips and reminders to the players through interactive screen display.
  2. Reading the electronic signals of the player’s state.
  3. Playable, restartable and fair with proper game rules.  

My project doesn’t align with my definition of interaction enough in these ways: 

  1. Failing to adding hardware to the project to complicate and enrich the user experience.
  2. Primitive screen display with no proper background or cool enemy appearance
  3. Lack a better game level mechanism.
  4. Improper difficulty settings.

Possible solutions:

 If there were enough time. Of course I understand where they should be going.

What I learnt from my accomplishments are that:

  1. it is really hard to tell the principle of making the people feel some interactive designs complicated, interesting or simply worth treating well.
  2. My time management skills had no improvement compared with midterm. 
  3. More attention should be paid to the daily schedule and school calendar.
  4. Consult instructors in time and learn from tutorials.

ANNEX

  1. Original Processing game code: https://blog.csdn.net/ralphfjy/article/details/70186787
  2. RGB Large Digital Clock: https://create.arduino.cc/projecthub/makiko/rgb-large-digital-clock-579e80?ref=tag&ref_id=led&offset=23

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *