20 April 2025

Team 10: Watermelon Controller

 Jessica Harrison and Chandler Crum


Controller:




Description:




For our project, we created a custom game controller for the game Suika Jelly using the Circuit Playground Express and a potentiometer. To play Suika Jelly, the player must strategically drop different fruits into a jar. Going into this project, we wanted to design a physical interface that helped the player feel more connected to the movement and placement of fruit. We decided to go with a watermelon slice because it is intuitive to hold and its half-circle shape can be manipulated almost like a steering wheel.

To use the controller, the player uses natural gestures that mirror actions that happen on the screen. Using tilt controls, the player can tilt the slice of watermelon left or right to trigger the “A” and “D” keys, positioning their fruit left or right in the game. Turning the potentiometer knob all the way to the right triggers the “space” key, dropping the fruit into place. If the potentiometer is all the way to the left, the “esc” key is triggered, pausing the game. After earning a certain amount of points, the game will enter “shake” mode. Usually, the player would use the WSAD keys to shake the jar up/down or left/right. Using our controller, the player can just shake the watermelon controller to trigger the “ctrl” key that enables shake mode, and continue moving it to shake the jar up/down or left/right.

The affordances of our controller are that the player can hold it how they normally would hold a slice of watermelon, and they can see that there is a knob on top that they can manipulate. A major signifier in our design is that the shape of the controller intuitively implies directional movement. The potentiometer only uses the highest and lowest value readings, so it’s not very easy to accidentally trigger the pause or shake menu. We used serial output to fine tune the input values.

Our controller creates a more immersive experience for Suika Jelly players, because most of the gestures, such as “shaking,” mimic exactly what is happening in-game. Our controller encourages movement and brings a new layer of fun that is concise with the game’s aesthetic and mechanics.

Questions:


1. What would be an interesting cover or replacement for the knob at the top of the controller?

2. Do you feel that this would be more immersive than using a traditional keyboard?


Schematics:




Code:


#include <Adafruit_CircuitPlayground.h>
#include <Keyboard.h>

const int slideSwitch = 7;  // Establish slide switch (D7)
const int potPin = A1;    // Potentiometer to A1
const int potRightMax = 900; // Potentiometer max right value
const int potLeftMax = 0;   // Potentiometer max left value

const float shakeMax = 10.0; // Shake sensitivity, can be adjusted if needed

void setup() {
  Serial.begin(9600); // Initialize serial monitor
  CircuitPlayground.begin(); // Initialize CPE
  pinMode(slideSwitch, INPUT_PULLUP); // Initialize on/off switch
  Keyboard.begin(); // Initialize keyboard
}

void loop() {
  bool switchState = digitalRead(slideSwitch) == LOW; // Check if switch is on/off

  if (switchState) { // If switch is on
    Serial.println("Board is online!"); // Print board status

    float x = CircuitPlayground.motionX(); // Read X-axis motion
    float y = CircuitPlayground.motionY(); // Read Y-axis motion
    float z = CircuitPlayground.motionZ(); // Read Z-axis motion

    Serial.print("X: "); // Print X-axis value
    Serial.println(x);
    Serial.print("Y: "); // Print Y-axis value
    Serial.println(y);
    Serial.print("Z: "); // Print Z-axis value
    Serial.println(z);

    float shakeValue = sqrt(x * x + y * y + z * z);  // Calculate motion values to detect if shaking
    if (shakeValue > shakeMax) { // If current shake value is above the maxium, is shaking
      Serial.println("Shaking!"); // Print when shaking
      Keyboard.press(KEY_LEFT_CTRL); // Press left-ctrl key
    } else { // No longer shaking
      Keyboard.release(KEY_LEFT_CTRL); // Release left-ctrl key
    }

    if (x < -3) {  // Check if tilting left
      Serial.println("Moving left!"); // Print when moving left
      Keyboard.press('a'); // Press a key
    }
    else if (x > 3) { // Check if tilting right
      Serial.println("Moving right!"); // Print when moving right
      Keyboard.press('d'); // Press d key
    }
    else { // Check if neutral position
      Serial.println("No movement!"); // Print when not moving
      Keyboard.release('a'); // Release a key
      Keyboard.release('d'); // Release d key
    }

    if (y < -3) { // Check if tilting up
      Serial.println("Moving up!"); // Print when moving up
      Keyboard.press('w'); // Press w key
    }

    else if (y > 3) { // Check if tilting down
      Serial.println("Moving down!"); // Print when moving down
      Keyboard.press('s'); // Press s key
    }

    else {  // If no axis thresholds are met
      Serial.println("No movement!"); // Print when not moving
      Keyboard.release('w'); // Release w key
      Keyboard.release('s'); // Release s key
    }

    int potValue = analogRead(potPin); // Read potentiometer value
    Serial.print("Potentiometer Value: "); // Print potentiometer value
    Serial.println(potValue);

    if (potValue > potRightMax) { // Drop fruit when turned fully right
      Serial.println("Dropped Fruit!"); // Print when fruit is dropped
      Keyboard.press(' '); // Press spacebar
    }
    else {
      Keyboard.release(' '); // Release spacebar
    }

    if (potValue == potLeftMax) { // Pause game when potentiometer at lowest value
      Serial.println("Paused!"); // Print when paused
      Keyboard.press(KEY_ESC); // Press escape key
    }
    else {
      Keyboard.release(KEY_ESC); // Release escape key
    }

  }
  else {
    Serial.println("Board is offline!"); // Print board status
    Keyboard.releaseAll(); // Release all keys
  }

  delay(50); // Delay for input stability
}

 

Demo:




No comments:

Post a Comment

Note: Only a member of this blog may post a comment.