Midterm Assignment – A Blast to the Past!

My Midterm Assignment can be described in the following way: “A computer geeks dream”. Jokes aside, this is an Idea I have had on mind for a long time and I decided that this is the right time for me to make it reality. Let’s dive deep into it:

Ideation:

As the midterm assignment was approaching I was a little bit scared of what I should do. I heard people around me all say they are going to make a game or some visual artistic piece but I wanted to do something different. Then I realized, what is my first experience with computers and technology? The answer was clear and simple: WINDOWS XP (My first computer with a Pentium 3 and 1GB of ram Is one I will always remember)

Concept

The concept was pretty simple. Make a small Windows XP emulator that will include the original icons and sounds as well as display the infamous windows errors which don’t make sense (for example: Keyboard not found: Press some button – like how am I supposed to press a button on the keyboard if it’s disconnected???). Before Explaining the technical side, I will let you explore the project a little bit.

Execution

This assignment was done in a way that was very thought of and self reflective based on the readings we have done for the class in the past month. It is focused on human centered design as well as it incorporates many techniques like the obviousness of the design and the “lack of need for instructions”. It starts of simple with a power button which is familiar to everyone as well as the whole windows ecosystem which is easy to figure out. The icons have been made draggable, blue when clicked and with the original click sound, just like a real windows XP. For organization purposes they have been divided in different classes, as shown below:

class Icon {
  constructor(image, label, x, y, width, height) {
    this.image = image;
    this.label = label;
    this.x = x;
    this.y = y;
    this.width = width;
    this.height = height;
    this.isHighlighted = false;
    this.isDragging = false; // New property to track dragging state
    this.offsetX = 0; // Offset between mouse and icon x position during drag
    this.offsetY = 0; // Offset between mouse and icon y position during drag
    this.clickCount = 0;
  }

  draw() {
    push();
    if (this.isHighlighted || this.isDragging) {
      tint(0, 0, 255); // Tint for highlight
      fill("blue"); // Color for highlighted text
    } else {
      noTint();
      fill(255); // Default text color
    }

    image(this.image, this.x, this.y, this.width, this.height);
    text(this.label, this.x, this.y + this.height + 10); // Adjust text position below the icon
    pop();
  }

  contains(px, py) {
    return (
      px >= this.x &&
      px <= this.x + this.width &&
      py >= this.y &&
      py <= this.y + this.height
    );
  }

  click() {
    if (this.contains(mouseX, mouseY)) {
      this.isHighlighted = true;
      clickSound.play();

      // Check if the current icon is the last clicked icon
      if (lastIconClicked === this.label) {
        this.clickCount++; // Increment only if the same icon is clicked consecutively
      } else {
        // Reset all icons' click counts if a different icon is clicked
        icons.forEach((icon) => (icon.clickCount = 0));
        this.clickCount = 1;
        lastIconClicked = this.label; // Update the last clicked icon label
      }

      console.log(
        `Clicked on Icon: ${this.label}, Click Count: ${this.clickCount}`
      );

      // Check if the icon is clicked two times in a row
      if (this.clickCount % 2 == 0 && this.label === "midterm.exe") {
        errorImageLogic();
        this.clickCount = 0; // Reset click count after opening the icon
      } else if (this.clickCount % 2 == 0 && this.label === "My Computer") {
        myComputerLogic();
        this.clickCount = 0; // Reset click count after opening the icon
      } else if (this.clickCount % 2 == 0 && this.label === "Recycle Bin") {
        recycleBinLogic();
        this.clickCount = 0; // Reset click count after opening the icon
      } else if (this.clickCount == 1 && this.label === "errorImage") {
        spawnErrorImages();
        this.clickCount = 0; // Reset click count after spawning error images
      }
    } else {
      this.isHighlighted = false;
    }
  }

  mousePressed() {
    if (this.contains(mouseX, mouseY)) {
      this.isDragging = true;
      this.offsetX = this.x - mouseX;
      this.offsetY = this.y - mouseY;
    }
  }

  mouseReleased() {
    this.isDragging = false;
  }

  mouseDragged() {
    if (this.isDragging) {
      this.x = mouseX + this.offsetX;
      this.y = mouseY + this.offsetY;
    }
  }
}

Shown above is the class for the Icons which makes it easy to add them or take them away.

class Window {
  constructor(image, width, height) {
    this.image = image;
    this.width = width;
    this.height = height;
    this.x = 50;
    this.y = 50;
    this.closeButtonSize = 50; // Size of the close button
  }

  draw() {
    image(this.image, this.x, this.y, this.width, this.height);
  }

  clicked(mx, my) {
    // Check if close button is clicked
    if (
      mx > this.x + this.width - this.closeButtonSize &&
      mx < this.x + this.width &&
      my > this.y &&
      my < this.y + this.closeButtonSize
    ) {
      clickSound.play();
      specialWindow = null; // Close the window
    }

    // Check if the bottom half of the window is clicked
    if (
      this.image === errorImage &&
      mx >= this.x &&
      mx <= this.x + this.width &&
      my >= this.y + this.height / 2 &&
      my <= this.y + this.height
    ) {
      errorShouldSpawn = true;
      // Logic for clicking the bottom half of the error window
      for (let i = 0; i < 40; i++) {
        setTimeout(() => {
          spawnErrorImages();
        }, i * 100); // spawn more error windows over time
      }

      // Transition to blue screen after 2 seconds
      setTimeout(() => {
        loop();
        currentState = State.BLUE_SCREEN;
      }, 4000);
    }
  }
}

Shown above is the code for the Window class which displays the windows where the icons are clicked and also controls the behavior of the error prompts.

Challenges and closing statement

The main challenges included the clicking of the buttons and dragging them around as well as the behavior of the error messages shown.

Special thanks to Pi and Professor Aaron Sherwood for the help throughout the whole execution of the project. You guys really motivated me to make my childhood dream come true. If you showed this to 5 year old Darko and said he made that he would literally be so excited.

At the same time, thank YOU as a reader for “wasting” 5 minutes of your day to appreciate my work. Remember to put a smile on your face and appreciate very day as much as you can. Spread love with your family, friends, professors and even strangers cause you never know what tomorrow brings.

Darko Loves You <3

Stay Safe!

Leave a Reply