20 November 2024

Team 5 - Donkey Kong Hat Controller

Controller Description


    The conceptual model for our controller drew inspiration from the hat item that can be found in the game Donkey Kong (1981). In the game, this item served to provide the player extra points to increase their score


    There are two types of input that the controller accepts: Movement from the two ultrasonic range sensors on the sides of the hat, and jumping from the circuit playground's accelerometer. Placing your hands in front of the ultrasonic sensors will move your character in a certain direction, moving your hand closer and farther from the sensor will also influence the character's direction.


    Though it may seem rather unorthodox, the signifiers for the controller are connected to its relation to the game. In order to get the character to move, a player must frantically move their hands up and down, similar to how Donkey Kong moves at the top in order to navigate their way up the tower. Additionally, the player must physically jump like the player character in order to jump over barrels


    These aspects of the controller are able to give the player a unique experience when it comes to controlling a game. Few games see the player control a character without holding something in their hands, and this controller asks them to control a game by (quite literally) using their head.


Question for peer review

How can the movement controls, based on hand distance from the sensors, be improved to make the experience feel more natural and easy for players to use?


Roles


Kel worked on the base code and tested its functionality, ensuring the sensors and controls were working properly. They also fixed any errors and handled the wiring to connect all the sensors. Additionally, Kel recorded and edited the video and provided the voiceover.


Thu contributed by building on Kel’s code and making modifications to accommodate design changes. She wrote the project descriptions, and acted as the demonstrator in the video. She also crafted the hat, including cutting holes and using tape and a glue gun to modify it for caging.


Controller Photo





Controller Schematic





Controller Code


#include <Adafruit_CircuitPlayground.h>
#include <Keyboard.h>
// Define ultrasonic sensor pins for directions and constants
const int trigPinLR = 6; // Trigger pin for left/right movement
const int echoPinLR = 12;  // Echo pin for left/right movement
const int trigPinFB = 9;  // Trigger pin for forward/backward movement
const int echoPinFB = 3; // Echo pin for forward/backward movement            
const int distanceCloseThreshold = 15;    // Distance threshold for closer threshold
const int distanceFartherThreshold = 25;  // Distance threshold for further threshold
const int distanceMaxThreshold = 38; //Maximum distance threshold we want the range sensors to detect
const int shakeThresh = 15;            // Threshold for detecting a shake to jump      


void setup() {
  // set up sensors + microphone
  Serial.begin (9600);
  CircuitPlayground.begin();
  //  Initialize trigger and echo pins as output and input, respectively
 // Initialize trigger and echo pins
  pinMode(trigPinLR, OUTPUT);
  pinMode(echoPinLR, INPUT);
  pinMode(trigPinFB, OUTPUT);
  pinMode(echoPinFB, INPUT);
  pinMode(CPLAY_SLIDESWITCHPIN, INPUT_PULLUP);
}

void loop() {
  if (digitalRead(CPLAY_SLIDESWITCHPIN)) {
    // Measure distances from objects
    long distanceLR = echolocate(trigPinLR, echoPinLR); // For left/right
    long distanceFB = echolocate(trigPinFB, echoPinFB); // For forward/backward

    Serial.print(distanceLR);
    Serial.print("\t");
    Serial.println(distanceFB);

    //Shake detect for jumping//
    float shake = abs(CircuitPlayground.motionX()) +
                  abs(CircuitPlayground.motionY()) +
                  abs(CircuitPlayground.motionZ());
    if(shake > shakeThresh) {
       Keyboard.press(0x20); //press space to jump
      delay(100);            // Short delay to debounce
      Keyboard.release(0x20); // Release key
    }
   
  // Movement logic for up/down based on distance
    if (distanceFB <= distanceCloseThreshold) {
      Keyboard.press(KEY_UP_ARROW); // Press "up" when hand is closer
    } else if (distanceFB > distanceFartherThreshold) {
      Keyboard.press(KEY_DOWN_ARROW); // Press "down" when hand is further away
    }
    // Release arrow keys only if no movement is detected in either sensor
    if (distanceLR <= distanceCloseThreshold) {
      Keyboard.press(KEY_RIGHT_ARROW); // Press "right" when hand is closer
    } else if (distanceLR > distanceFartherThreshold) {
      Keyboard.press(KEY_LEFT_ARROW); // Press "left" when hand is further away
    }

    delay(100); // Add a short delay to debounce key presses
    Keyboard.releaseAll();
  }
}

long echolocate(int trigPin, int echoPin){
  //Define function-specific variables
  long distance, duration;
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH); // Measure echo return time
 // Determine the distance from the object (in centimeters, then return that value)
  distance = (duration / 2) / 29.1; // Distance in cm
  return distance;
}

Controller Demonstration


Team 1 ∙ Happy Wheels Arm-mounted Controller

Photos
Schematic



Video

Description
            The conceptual model of the design for our hi-fi controller is to mimic the relation to the chaotic nature of Happy Wheels and the “physical” nature of how the game is played. Thus, the use of a leather gauntlet makes this connection by acting similar to how body stunts are performed with padded protection. Wearing the gauntlet, you are able to control the character by doing the following: Rotating your arm to the Right and Left will have the character lean Forward (Right Arrow Key) and Back respectively (Left Arrow Key), Holding your hand over the Ultrasonic Sensor (US) will drive the character backward (10-15cm away from the US) and hovering your hand closer will drive you forward (0-7cm away), “hopping” your arm upwards like a jump will have the character, if applicable, jump (Spacebar), and last, if you Double Tap your character will dismount the vehicle (Z).

The relationship between signifiers and feedback is that you will literally move your arm in a similar caliber to how the character moves within the game. This also allows the player to use the US as a sort of gas pedal where you “push” down on the US to go forward and lift off to go backward with a bit of room to allow for ease of movement into the opposite motion control. The “empty space” between distances of the US prevents accidental movement that the player did not intend to perform on the character.

Altogether, this connects to the game in the sense that you are controlling the character in ways that mimic the movement seen on screen as the character performs a multitude of actions. Thus, the affordance of the design indicates how the player should use the controller based on the game’s layout for which it is played on screen. The design of the controller is intrinsic to the game's chaotic nature by reflecting on the padded clothing that would be worn in stunt situations.

 

Questions

“What aspects of the design would make it relate more to Happy Wheels if changed?”

“What other external inputs would make the Controller more enjoyable if introduced early on?”

Code

#include <Adafruit_CircuitPlayground.h>
#include <Adafruit_Circuit_Playground.h>

#include <Keyboard.h>
#include <KeyboardLayout.h>
#include <Keyboard_da_DK.h>
#include <Keyboard_de_DE.h>
#include <Keyboard_es_ES.h>
#include <Keyboard_fr_FR.h>
#include <Keyboard_it_IT.h>
#include <Keyboard_sv_SE.h>

// Final Team 1
// Peter Ochoa & Luke Bono

// Controller Description + Mappings:
  // (+ and - vary depending on the switch toggle as we have an Ambidextrous mode for both L and R handed users)

// Accelerometer Y+ = "Tilt Forward" / Right Arrow Key (for L hand, inverse for R hand)
// Accelerometer Y- = "Tilt Backward" / Left Arrow Key (for L hand, inverse for R hand)

// Accelerometer Z+ = "Jump" / Space Bar (for L hand, inverse for R hand)

// Ultrasonic "Close" = "Forward" / Up Arrow Key (0-7cm)
// Ultrasonic "Far" = "Backward" / Down Arrow Key (10-15cm)
  // Distances in cm for 7 and 10 are intentionally left blank to account for misinput by the player and to prevent accidental key inputs=

// Double Tap = "Eject" / Z

// pin numbers
const int trigPin = A2;
const int echoPin = A3;
const int btnA = 4; // Menu Button for pausing or restarting
const int btnB = 5; // Button for pressing 'R' to restart during Menu Button press
const int flipper = 7; // Determines if the Code runs in Left or right-handed mode for the accessibility of all users! :)

// Tap Variables
const int click = 120;

// Accelerometer Variables
float accelX;
float accelY;
float accelZ;
float flat;
float threshold = 5; // minimum amount of movement to trigger input from accelerometer
int jumpTimer = -1; // ensures that after a jump input is triggered, a tap or another jump can't be triggered for half a second

// Ultrasonic Variables
bool trig; // send message to ultrasound sensor, or not
float echo;
float distanceCM;
float closeMinCM = 0; float closeMaxCM = 7;
float farMinCM = 10; float farMaxCM = 15;

// Misc. Variables
int debounce = 100; // TEMP
bool test = false;
bool killcode = false;
bool isLeft = false;

// put your setup code here, to run once:
void setup() {
  CircuitPlayground.begin();

  // set in and out pins
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(btnA, INPUT_PULLDOWN);
  pinMode(btnB, INPUT_PULLDOWN);
  pinMode(flipper, INPUT_PULLUP);

  // Begin
  Keyboard.begin();
  Serial.begin(9600);

  // Initialize
  calibrate();
}

// Runs at the start & reset of the CPE
void calibrate() {
  // Release all keys
  Keyboard.releaseAll();
  // Stop voltage in the Trigger Pin
  digitalWrite(trigPin, LOW);

  // Determine if inputs should be interpreted for the left arm or right arm
  if (digitalRead(flipper) == HIGH) {
    isLeft = true;
  }
  else {
    isLeft = false;
  }

  // Sets the current orientation of the CPE as "flat", and the accelerometer inputs are adjusted based on this
  // (If the controller is on the left hand, usually the CPE isn't flat)
  flat = accelY = CircuitPlayground.motionY();

  // Sets up the booleans for the kill function
  test = false;
  killcode = false;

  // Allow double taps to trigger the tapTime function
  CircuitPlayground.setAccelTap(2, click);
  attachInterrupt(digitalPinToInterrupt(CPLAY_LIS3DH_INTERRUPT), tapTime, FALLING);

  // Audio signifier of calibration
  CircuitPlayground.playTone(50, 100, true);
  delay(10);
  CircuitPlayground.playTone(50, 100, true);
  delay(debounce);
}

// Triggers when the player taps, triggers kill
void tapTime(void) {
  // Ensures the player isn't jumping
  if (jumpTimer <= 0) {
    killcode = true;
  }
}

// Triggers after tapTime, prevents any inputs, except menu buttons
// (This is so tapping doesn't overlap with jumping. When you eject you are rendered useless anyways in game)
void kill(void) {
  Keyboard.releaseAll();
  Keyboard.press('z'); // press Z [EJECT]
  delay(2 * debounce);
  Keyboard.release('z');
  delay(debounce);
  // Stop double tap triggers
  CircuitPlayground.setAccelTap(0, click);
  // Stop the input code & prevent this code from running again
  test = true;
  killcode = false;
  // Turn off all keys
  Keyboard.releaseAll();
}

// put your main code here, to run  repeatedly:
void loop() {
  // PAUSE
  if (digitalRead(btnA) == HIGH) {
    Serial.println("tab");
    Keyboard.press(KEY_TAB);
    delay(debounce * 2);
    Keyboard.release(KEY_TAB);
  }

  // RESTART (if paused)
  if (digitalRead(btnB) == HIGH) {
    Serial.println("r");
    Keyboard.press('r');
    delay(debounce * 2);
    Keyboard.release('r');
    calibrate();
  }

  // Triggers kill() after a tapTime
  if(killcode){
    kill();
  }

  // Will run until kill() is triggered
  if (!test) {
    // GET INPUTS
    // send message to distance sensor for 10 milliseconds
    digitalWrite(trigPin, LOW);
    delayMicroseconds(2);
    digitalWrite(trigPin, HIGH);
    delayMicroseconds(10);
    digitalWrite(trigPin, LOW);
    echo = pulseIn(echoPin, HIGH);
    distanceCM = (echo/2) / 29.1;

    // get values from the accelerometer
    accelX = CircuitPlayground.motionX();
    accelY = CircuitPlayground.motionY();
    accelZ = CircuitPlayground.motionZ();

    // Adjusts values so we can determine rotation 180 degrees left and right from the current position
    if (accelZ < 0) { // if the CPE is upside down
      if (accelY >= 0) {
        accelY = accelY + 10;
      }
      else {
         accelY = accelY - 10;
      }
    }

    // INTERPRET INPUTS
    if (isLeft) {
      // if the accelerometer Y is positive (if tilting right)
      if (accelY > (flat + threshold)) {
        Keyboard.press(KEY_RIGHT_ARROW); // release RIGHT ARROW [TILT BACKWARDS]
        Keyboard.release(KEY_LEFT_ARROW); // press LEFT ARROW [TILT FORWARDS]
      }

      // if the accelerometer Y is negative (if tilting left)
      else if (accelY < (flat - threshold)) {
        Keyboard.press(KEY_LEFT_ARROW); // release LEFT ARROW [TILT BACKWARDS]
        Keyboard.release(KEY_RIGHT_ARROW); // press RIGHT ARROW [TILT FORWARDS]
      }

      // if little to no accelerometer input (if no tilt)
      else { // release both ARROW keys
        Keyboard.release(KEY_LEFT_ARROW);
        Keyboard.release(KEY_RIGHT_ARROW);
      }
    }
                                       
    else { //isRight, inputs are inverse of isLeft
      // (if tilting right)                                                                                                                        
      if (accelY < (flat - threshold)) {
        Keyboard.press(KEY_RIGHT_ARROW); // release RIGHT ARROW [TILT BACKWARDS]
        Keyboard.release(KEY_LEFT_ARROW); // press LEFT ARROW [TILT FORWARDS]
      }                    

      // (if tiliting left)
      else if (accelY > (flat + threshold)) {
        Keyboard.press(KEY_LEFT_ARROW); // release LEFT ARROW [TILT BACKWARDS]
        Keyboard.release(KEY_RIGHT_ARROW); // press RIGHT ARROW [TILT FORWARDS]
      }

      // (if no tilt)
      else { // release both ARROW keys
        Keyboard.release(KEY_LEFT_ARROW);
        Keyboard.release(KEY_RIGHT_ARROW);
      }
    }

    // if accelerometer Z is high (if hand raises up)
    if (isLeft && accelZ > 11 && jumpTimer <= 0) {
      Keyboard.press(' ');
      jumpTimer = 500;
    }

    // isRight, inputs are inverse of isLeft (if hand raises up)
    else if (!isLeft && accelZ < -11 && jumpTimer <= 0) {
      Keyboard.press(' ');
      jumpTimer = 500;
    }

    // if little to no accelerometer Z input (steady hand)
    else {
      Keyboard.release(' ');
    }

    // if ultrasonic senses something close to the accelerometer (0cm - 7cm)
    if (distanceCM >= closeMinCM && distanceCM < closeMaxCM) {
      Keyboard.press(KEY_UP_ARROW); // press UP ARROW [MOVE FORWARD]
      Keyboard.release(KEY_DOWN_ARROW);
      Serial.print(" forward");
    }

    // if ultrasonic senses something far from the accelerometer (10cm - 15cm)
    else if (distanceCM >= farMinCM && distanceCM < farMaxCM) {
      Keyboard.press(KEY_DOWN_ARROW); // press DOWN ARROW [MOVE BACKWARD]
      Keyboard.release(KEY_UP_ARROW);
      Serial.print(" backward");
    }

    // if ultrasonic senses something very far from the accelerometer or in the deadzone (7cm - 10cm && > 15cm)
    else {
      // release both ARROW keys
      Keyboard.release(KEY_UP_ARROW);
      Keyboard.release(KEY_DOWN_ARROW);
    }

    delay(debounce);

    // if jumpTimer is on, jumpTimer decreases by the debounce time
    if (jumpTimer > 0) {
      jumpTimer = jumpTimer - debounce;
    }
    Serial.println("");
  }
}  

Group 11 Controller - Touhou Broom

Controller Description

    The conceptual model for our design is to look like the broom ridden by Marisa in Touhou 4: Lotus Land Story. To achieve this, the controller has a roughly cone-shaped yellow bottom to imitate bristles, with a long brown handle like a wooden broom.


    There are three types of input that the controller accepts. The first is rotation, using the accelerometer. Rotating the controller will cause the character to move in the same direction. The second input is sound. Making a loud sound, such as a shout, will cause the character to use their Bomb ability. The final type of input is distance. Gripping the broom by the top of the handle, covering the controller’s distance sensor, will cause the character to move more slowly.


    The signifiers for the controller are connected to its relation to the game. In order to get the character to move, a player must move the controller in the same way. This makes the controls intuitive, by letting the player feel that they are directly moving the character. The controller itself does not offer much feedback outside of the character’s movements in the game. Real-world feedback on the controller is limited to the controller rotating when the player moves it (most easily seen by watching the ‘bristles’ part move).


    These aspects of the controller are able to make the player feel more immersed in the game. They move their broom like the character does to move, grip the broom at the top to make precise movements, and can call out the name of their Spell Card to use the Bomb in the same way the characters do.

 

Controller Photo

 

 

Controller Schematic

Controller Code

 
#include <Keyboard.h>
#include <KeyboardLayout.h>
#include <Keyboard_da_DK.h>
#include <Keyboard_de_DE.h>
#include <Keyboard_es_ES.h>
#include <Keyboard_fr_FR.h>
#include <Keyboard_hu_HU.h>
#include <Keyboard_it_IT.h>
#include <Keyboard_pt_PT.h>
#include <Keyboard_sv_SE.h>
#include <Adafruit_CircuitPlayground.h>
#include <Adafruit_Circuit_Playground.h>

// Variables
int trigPin = A1;
int echoPin = A2;

int rawDistance;
int duration;
int rawSound;
int rawX;
int rawY;

int mappedX;
int mappedY;
int mappedSound;
int mappedDistance;

int soundThreshold = 5;
int distanceThreshold = -5;
int xThreshold = 2;
int yThreshold = 1;

void setup() {
  // put your setup code here, to run once:
  CircuitPlayground.begin();
  Keyboard.begin();
  Serial.begin(9600);

  // Trig Pin - A1
  pinMode(trigPin, OUTPUT);
  // Echo Pin - A2
  pinMode(echoPin, INPUT);

  delay(1000);
}

void loop() {
  // put your main code here, to run repeatedly:
  if (digitalRead(CPLAY_SLIDESWITCHPIN))
  {
    AcceptInput();
    MapInput();
    AutoFire();
    ControlMovement();
    ButtonEvents();

    delay(50);
  }
}

void AcceptInput()
{
  // Motion input
  rawX = CircuitPlayground.motionX();
  rawY = CircuitPlayground.motionY();
  // Sound input
  rawSound = CircuitPlayground.mic.soundPressureLevel(10);
  // Distance input
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  rawDistance = (duration / 2) / 29.1;
}

void MapInput()
{
  mappedX = map(rawX, -10, 5, -5, 5);
  mappedY = map(rawY, -10, 5, -5, 5);
  mappedY = mappedY * -1;

  mappedSound = map(rawSound, 50, 100, 0, 10);

  mappedDistance = map(rawDistance, 0, 200, -10, 40);
}

void AutoFire()
{
  // Spam z to shoot
  Keyboard.press('z');
  delayMicroseconds(5);
  Keyboard.release('z');
}

void ControlMovement()
{
  // Y - Up / Down movement
  if (mappedY > yThreshold)
  {
    // Move up
    Keyboard.release(KEY_ARROW_DOWN);
    Keyboard.press(KEY_ARROW_UP);
  } else if (mappedY < (yThreshold * -1))
  {
    // Move down
    Keyboard.release(KEY_ARROW_UP);
    Keyboard.press(KEY_ARROW_DOWN);
  } else
  {
    Keyboard.release(KEY_ARROW_DOWN);
    Keyboard.release(KEY_ARROW_UP);
  }
  // X - Left / Right movement
  if (mappedX > xThreshold)
  {
    // Move left
    Keyboard.release(KEY_ARROW_RIGHT);
    Keyboard.press(KEY_ARROW_LEFT);
  } else if (mappedX < (xThreshold * -1))
  {
    // Move right
    Keyboard.release(KEY_ARROW_LEFT);
    Keyboard.press(KEY_ARROW_RIGHT);
  } else
  {
    Keyboard.release(KEY_ARROW_RIGHT);
    Keyboard.release(KEY_ARROW_LEFT);
  }
}

void ButtonEvents()
{
  // Sound - bomb
  if (mappedSound > soundThreshold)
  {
    Keyboard.write('x');
  }

  // Distance - focus
  if (mappedDistance < distanceThreshold)
  {
    Keyboard.press(KEY_LEFT_SHIFT);
  } else
  {
    Keyboard.release(KEY_LEFT_SHIFT);
  }
}


 

Controller Video


 

Question:


Considering the aim of player immersion, are there better ways to approach the use of specific controls, such as the bomb ability or shooting?

 

19 November 2024

Team 12 Game Controller

 Alec Jerard Prestoza and Chris Medina
Team 12 Game Controller
Mortal Cage Fighter Glove



This is our alternative controller for the game Mortal Cage Fighter, which comes in the form of a glove. The conceptual model includes a workout glove in between some knitted gloves, to simulate the feeling of fighting or getting your hands dirty. In the game, the player will utilize multiple inputs in order to win a Best of 3 fight. Built for one’s right hand, flexing the thumb on the glove will cause the player to move left, and flexing the pinky will move the player right (the player also blocks when moving back from the direction they are facing). In terms of combat, flex the index finger to punch and the middle finger to kick. All of the inputs have been mapped onto flex sensors, with the only other input being the CPE’s shake function to jump. Like in other fighting games, Mortal Cage Fighter has Specials that can be executed with a sequence of inputs (in this game, they are: back -> forward -> punch/kick). Every fighter has their own unique Specials. The controller’s design incorporates signifiers by mapping specific finger movements to in-game actions. For example, flexing the index finger to punch or the middle finger to kick provides a clear signifier that guides the player’s movements. The feedback of the controller is visual (the character’s movements and combat actions). This helps players understand the results of their actions, providing a rewarding sense of cause and effect. In a simple game such as this one, the glove can afford to do everything that can be done on a keyboard, and it connects the use of handwear to a fighting theme that requires one to use their hands.  Here is a question we have:

How can this controller be optimized further, in terms of the circuitry, coding, or design?

List of Contributions:
Alec -> coding, schematic
Chris -> supplies, sketching concept ideas
Both -> building glove and circuit, soldering, playtesting

Schematic:


Code: 
#include <Keyboard.h>
#include <KeyboardLayout.h>
#include <Keyboard_da_DK.h>
#include <Keyboard_de_DE.h>
#include <Keyboard_es_ES.h>
#include <Keyboard_fr_FR.h>
#include <Keyboard_hu_HU.h>
#include <Keyboard_it_IT.h>
#include <Keyboard_pt_PT.h>
#include <Keyboard_sv_SE.h>

#include <Adafruit_CircuitPlayground.h>
#include <Adafruit_Circuit_Playground.h>

//Alec Prestoza and Chris Medina (Team 12)
//Final Project
//Game: Mortal Cage Fighter

//initializing variables for each of the inputs
int shakeThresh = 30;
const int FLEX1_PIN1 = A1;
const int FLEX2_PIN2 = A2;
const int FLEX3_PIN3 = A3;
const int FLEX4_PIN4 = A4;

void setup() {
  // put your setup code here, to run once:
  CircuitPlayground.begin();
  CircuitPlayground.setBrightness(50);

  Serial.begin(9600);
  delay(1000);
}

void loop() {
  // put your main code here, to run repeatedly:
  float x = CircuitPlayground.motionX();
  //variable to read how hard the CPE is shaken
  float shake = abs(CircuitPlayground.motionX()) + abs(CircuitPlayground.motionY()) + abs(CircuitPlayground.motionZ());

  //reading each flex sensor onto its respective pin on the CPE
  int flex1 = analogRead(FLEX1_PIN1);
  int flex2 = analogRead(FLEX2_PIN2);
  int flex3 = analogRead(FLEX3_PIN3);
  int flex4 = analogRead(FLEX4_PIN4);

  // Map flex sensor values to character movement (Left, Right arrow keys)
  int flex1Movement = map(flex1, 0, 1023, 0, 10);
  int flex2Movement = map(flex2, 0, 1023, 0, 10);
  int flex3Movement = map(flex3, 0, 1023, 0, 10);
  int flex4Movement = map(flex4, 0, 1023, 0, 10);

  //print values of each flex sensor to serial monitor below
  Serial.print("\nFlex1: ");
  Serial.print(flex1);
  Serial.print(" | Flex2: ");
  Serial.print(flex2);
  Serial.print(" | Flex3: ");
  Serial.print(flex3);
  Serial.print(" | Flex4: ");
  Serial.print(flex4);

  //shake to jump
  if (shake > shakeThresh) {
    CircuitPlayground.setPixelColor(1, 255, 0, 0);
    Keyboard.write(KEY_UP_ARROW);
  }

  //***bending a finger will peform corresponding action
  //flex index finger to punch
  if (flex1Movement > 7) {
    CircuitPlayground.setPixelColor(4, 255, 255, 0);
    Keyboard.write('j');
  }
  //flex middle finger to kick
  if (flex2Movement > 6) {
    CircuitPlayground.setPixelColor(5, 0, 255, 255);
    Keyboard.write('k');
  }
  //flex thumb to move left
  if (flex3Movement > 5) {
    CircuitPlayground.setPixelColor(2, 0, 255, 0);
    Keyboard.press(KEY_LEFT_ARROW);
  } else {
    Keyboard.release(KEY_LEFT_ARROW);  // Release left arrow key
  }
  //flex pinky to move right
  if (flex4Movement > 6) {
    CircuitPlayground.setPixelColor(3, 0, 0, 255);
    Keyboard.press(KEY_RIGHT_ARROW);
  } else {
    Keyboard.release(KEY_RIGHT_ARROW);  // Release right arrow key
  }
  //The Special Moves in the game can be executed using a sequence of the above if statements (left -> right -> punch/kick)

  CircuitPlayground.clearPixels();
}

Video: Click here for the demonstration of our controller in-game.

04 November 2024

  Team 13 - Toy Ship


Our chosen prototype is a model ship with controls relating to the ship's in-game functions. X-axis control is performed by tilting the controller left and right, while Y-axis control is through a top-mounted potentiometer located where the engines would be. The firing control is situated where the pilot hatch would be and consists of a simple button that activates when the hatch is closed. The thought behind it was to imitate the feeling of a kid playing with their toy planes and spaceships, except with actual effects on the game being played.

Feedback Questions: 

what are your thoughts as a basic concept, does this make sense or does it seem unrelated to the game? 

how does the layout feel, due to wiring constraints we put the thrust on the top. Is that comfortable or should it be moved?

Prototype Video:

https://youtu.be/nJQGg7BNC9U

Prototype Photos






LoFi circuitry: