22 April 2025

Final Team 12 : The SpeedRunner's Suitcase

We created a custom controller for the fast-paced competitive platformer, SpeedRunners. The controller is housed withing a custom 3D-printed box designed to resemble the suitcase obstacle that shows up frequently in the game. Our conceptual model focuses on taking this harmful game element and making it the main way for the player to interact with the game. Instead of being an obstacle, the suitcase becomes a tool for the player to physically interact and manipulate from the game world to control their character. This increases immersion and creates a unique gameplay experience based on the game’s own iconography.

The input to output mapping involves interactions with the controller components to make game actions. A potentiometer is used as the directional control, turning the knob is mapped directly to the character’s left and right movement. The accelerometer is used to make the player jump or slide. A toggle switch is used to control the grappling hook, flipping the switch on and off activates and deactivates the hook, very similar to how it works in the game. The ultrasonic distance sensor is connected to boost activation and item use, putting your hand over the sensor at different distances leads to different actions.

The controller’s design has simple signifiers to show how to use it. The suitcase links it to the game, the knob is the only input that fits direction, the switch is to activate and deactivate (the grapple is the obvious one but can also see this applied to the boost), and the motion sensor shows that there is an element of interaction with movement in that area. The player knows these actions worked by seeing the character in the game perform the actions and hearing the switch flipping or the knob turning.

All these elements combine to use the player’s familiarity to the game and common input devices such as a knob or switch, while introducing uncommon interactions such as the distance sensor that can make gameplay more rewarding for the player.

Question:

Do you think the use of the ultrasonic sensor for potentially fast actions like boosting and item use is effective? Can the player maintain precise control over distance while in a fast-paced match of SpeedRunners?


Contributions:

Concept- Rodrigo C & Ralfo M

Wiring – Rodrigo C

Initial Code – Ralfo M

Updated Code + bug testing – Rodrigo C

Final Code – Ralfo M

Description – Rodrigo C

Prototype Enclosure – Rodrigo C

3D Print Enclosure – Ralfo M

Video and Photograph – Ralfo M

Schematics – Rodrigo C


Code:

#include <Adafruit_CircuitPlayground.h>

#include <Keyboard.h>

#include <NewPing.h>


// Map pins for Ultrasonic sensors

#define trigPin 9

#define echoPin 6


// Map pins for Potentiometer, Toggle Switch & Kill Switch

#define POT_PIN A5

#define SWITCH_PIN A6

#define MASTER_SWITCH_PIN A4


void setup() 

{

    CircuitPlayground.begin();

    Keyboard.begin();


    // Initialize Serial Monitor

    Serial.begin(9600);


    // Map Potentiometer

    pinMode(POT_PIN, INPUT);


    // Map Toggle switch & Kill switch with pull-up resistor

    pinMode(SWITCH_PIN, INPUT_PULLUP);

    pinMode(MASTER_SWITCH_PIN, INPUT_PULLUP);


    // Map Ultrasonic sensor pins as inputs

    pinMode(trigPin, OUTPUT);

    pinMode(echoPin, INPUT);


    // CPX initialization buffer

    delay(1000);

}


void loop() 

{

    // Check if master switch is OFF

    if (digitalRead(MASTER_SWITCH_PIN) == HIGH) 

    {

        Serial.println("Controller disabled");

        Keyboard.releaseAll();

        delay(100);

        return;

    }


    int potValue = analogRead(POT_PIN);

    float accelY = CircuitPlayground.motionY();

    int switchState = digitalRead(SWITCH_PIN);


   //Debugging: Print sensor values to Serial Monitor

   //Serial.print("Boost Sensor: "); Serial.println(boostDistance);

   //Serial.print("Item Sensor: "); Serial.println(itemDistance);

   //Serial.print("Potentiometer: "); Serial.println(potValue);

   //Serial.print("Accelerometer Z: "); Serial.println(accelZ);

   //Serial.print("Switch State: "); Serial.println(switchState);

    Serial.println(accelY);


    //Declaring variables for Ultrasonic sensor use

    long duration, distance;

    digitalWrite(trigPin, LOW);

    delayMicroseconds(2);

    digitalWrite(trigPin, HIGH);

    delayMicroseconds(10);

    digitalWrite(trigPin, LOW);

    duration = pulseIn(echoPin, HIGH);

    distance = (duration/2) / 29.1;


    Serial.print(distance);

    Serial.println(" cm");


    //If hand detected close to sensor, use boost

    if (distance <= 7)

    {

      Keyboard.press(0X20);

      Serial.println("Boost used!");

    }

    else

    {

      Keyboard.release(0X20);

    }


    //If hand detected far from sensor, use item

    if (distance >= 8 && distance <= 100)

    {

      Keyboard.press('c');

      Serial.println("Item used!");

    }

    else

    {

      Keyboard.release('c');

    }


    delay(100);


    // Potentiometer for left/right movement

    if (potValue > 500) 

    {

        Keyboard.press(KEY_LEFT_ARROW);

        Keyboard.release(KEY_RIGHT_ARROW);

        Serial.println("Moving Left!");

    }

    else if (potValue < 500) 

    {

        Keyboard.press(KEY_RIGHT_ARROW);

        Keyboard.release(KEY_LEFT_ARROW);

        Serial.println("Moving Right!");

    }


    // CPX Accelerometer for jump & slide

    if (accelY > 2.00)

    {

       Keyboard.press('z');

       Serial.println("Jump used!");

    } 

    else 

    {

        Keyboard.release('z');

    }


    if (accelY < -2.00)

    { 

        Keyboard.press(KEY_DOWN_ARROW);

        Serial.println("Slide used!");

    } 

    else 

    {

        Keyboard.release(KEY_DOWN_ARROW);

    }


    // Toggle Switch for grappling hook

    if (switchState == LOW) 

    {

        Keyboard.press('x');

        Serial.println("Grappling hook used!");

    } 

    else 

    {

        Keyboard.release('x');

    }


    // Small delay to prevent excessive key presses

    //delay(50);

}


Image:



           Schematic:


            Video:



21 April 2025

Project: Game Controller: Frogger - Team 17

 Our Frogger controller transforms the classic arcade gameplay into a physical, hands-on experience by replacing traditional keyboard inputs with interactive, pressure-sensitive lily pads. Rather than tapping arrow keys, players move a small frog figurine to one of four large lily pads—each corresponding to a direction: up, down, left, or right. When the frog is placed on a lily pad, a pressure sensor detects the weight and sends the appropriate signal through the Circuit Playground, moving the frog in-game. This one-to-one input-to-output mapping allows players to intuitively understand how their actions influence the game. The conceptual model draws directly from Frogger’s core mechanics: precision, timing, and spatial awareness. In the original game, players must carefully navigate hazards by choosing when and where to move. Our controller mirrors this concept by encouraging players to physically mimic that movement, moving across pads as if the frog were hopping from lily pad to lily pad. This embodied interaction creates a deeper connection to the game and adds a new layer of engagement. It also transforms a passive seated experience into one that is more active and involved. The lily pads serve as clear signifiers. Each pad’s position in a cross-shaped arrangement makes its purpose obvious and directly reflects its directional function. These affordances support the game’s theme and create an experience rooted in movement, timing, and playful risk-taking.


Open Question:

Do you feel as though it would be difficult to hit the lily pad due to it's size with the frog while also watching the game?

Team contributions:

Caio: Painted box, 3D printed frog and lily pads, brought and used most of the components for the controller.

Logan: Coded, soldered, brought boxes,  bought pressure sensors, and wired the circuit board.

Code:#include <Keyboard.h>

#include <KeyboardLayout.h> #include <Adafruit_CircuitPlayground.h> #include <Adafruit_Circuit_Playground.h> #define THRESHOLD 600 void setup() { Serial.begin(9600); while (!Serial); // Wait for serial to be ready CircuitPlayground.begin(); Keyboard.begin(); Serial.println("Pressure sensor readings:"); } void loop() { int sensor1 = analogRead(1); // Pin 1 int sensor2 = analogRead(3); // Pin 3 int sensor3 = analogRead(4); // Pin 4 int sensor4 = analogRead(7); // Pin 7 // Print sensor readings to the Serial Monitor Serial.print("Sensor 1: "); Serial.print(sensor1); Serial.print(" | Sensor 2: "); Serial.print(sensor2); Serial.print(" | Sensor 3: "); Serial.print(sensor3); Serial.print(" | Sensor 4: "); Serial.println(sensor4); if (sensor1 < 950) { Keyboard.press(KEY_UP_ARROW); // Forward } else { Keyboard.release(KEY_UP_ARROW); } if (sensor2 < 950) { Keyboard.press(KEY_LEFT_ARROW); // Left } else { Keyboard.release(KEY_LEFT_ARROW); } if (sensor3 < 950) { Keyboard.press(KEY_DOWN_ARROW); // Backward } else { Keyboard.release(KEY_DOWN_ARROW); } if (sensor4 < 950) { Keyboard.press(KEY_RIGHT_ARROW); // Right } else { Keyboard.release(KEY_RIGHT_ARROW); } delay(50); }

Image: 


Schematic:


Video:



WEBFISHING Hat Controller: Team 21

 WEBFISHING Hat: Team 21

Our Bucket Hat Controller for the game WEBFISHING is designed to be an extension of the self, where the player can truly feel a part of this world where they can socialize and fish. The most apparent part of this design is the Bucket Hat wearable component.

We have mapped the tilting direction of your head to the movement of either your in-game character, or with a toggle of the light sensor, the movement of your mouse for menu-navigation. We chose to use a light sensor instead of a standard button, as this input will be on top of the users head and no longer visible. The light sensor required users to be less precise than they needed to with a button, making it significantly more reliable when worn on top of your head.

For camera control, WEBFISHING has an orbiting camera with a third-person view of the player. In order to create an input for this, we chose to use a rotary encoder, with the rotation of the knob being directly mapped to the mouse when not in a menu.

The most important mechanic in WEBFISHING however, is undoubtedly the fishing. Now, when fishing in real life, you truly do have to pour your all into casting your reel. It takes a semblance of effort built up from deep inside, expelling out of you in one sudden burst in order for you to succeed. For this crucial task, our priority was having the player feel this sense of urgency and personal connection when they cast their reel.

It is for this reason we chose to go with a microphone as our trigger for casting in WEBFISHING. While it does require a little humility the first time, as you yell into the microphone, you simulate the same emotional build-up that you do as you when you fish in real life!

In what way could we make this controller more absurd to use?



//libraries
#include <Adafruit_CircuitPlayground.h>
#include <Adafruit_Circuit_Playground.h>
#include <Keyboard.h>
#include <KeyboardLayout.h>
#include <Mouse.h>
#include <Rotary.h>

//Pin Names
#define RotaryOutputA A2
#define RotaryOutputB A3
#define MicInput A1

float accelX, accelY;
float accelSensitivity = 5;
unsigned long startMillis;
unsigned long rotMillis;
unsigned long menuMillis;
int xMouse = 0;
int yMouse = 0;
int peakToPeak, signalMin, signalMax, sample;
int currentRotA, lastRotA, mouseGo;
bool menuActive = false;
bool mouseDown = false;
Rotary r = Rotary(RotaryOutputA, RotaryOutputB);

void setup() {
  //buttons for testing if needed
  //pinMode(CPLAY_RIGHTBUTTON, INPUT);
  //pinMode(CPLAY_LEFTBUTTON, INPUT);
 

  CircuitPlayground.begin();
  CircuitPlayground.setAccelRange(LIS3DH_RANGE_2_G);
  Serial.begin(9600);
  Mouse.begin();

    //Testing pins
  pinMode(A2, INPUT);
  pinMode(A3, INPUT);
  pinMode(A1, INPUT);
  pinMode(CPLAY_LIGHTSENSOR, INPUT);

  r.setChangedHandler(rotate);
  r.setLeftRotationHandler(showDirection);
  r.setRightRotationHandler(showDirection);
  lastRotA = r.getPosition();
  rotMillis = millis();
}

void loop() {
  // put your main code here, to run repeatedly:
  if(CircuitPlayground.slideSwitch()){
    //set up accelerometer data
    accelX = CircuitPlayground.motionX();
    accelY = CircuitPlayground.motionY();

    if (menuActive == false){
      //uses accel to control WASD if menus inactive
      accelX = map(accelX, 10, -10, -2,3);
      accelY = map(accelY, 10, -10, -2,3);

      if (accelX < 1 && accelX > -1){
        Keyboard.release('a');
        Keyboard.release('d');
      }
      else if (accelX >= 1){
        Keyboard.press('d');
      }
      else if (accelX <= -1){
        Keyboard.press('a');
      }

      if (accelY < 1 && accelY > -1){
        Keyboard.release('w');
        Keyboard.release('s');
      }
      else if (accelY >= 1){
        Keyboard.press('w');
      }
      else if (accelY <= -1){
        Keyboard.press('s');
      }
    }
    else{
      //uses accel to control mouse if menus active
      accelX = map(accelX, 10, -10, -100, 101);
      accelY = map(accelY, 10, -10, -100, 101);

      Mouse.move(accelX, accelY);
    }
     
    //set up sound data
    startMillis = millis();
    peakToPeak = 0;
    signalMax = 0;
    signalMin = 1024;

    //interpret sound data for 50 millis
    while (millis()-startMillis < 50){
      sample = analogRead(MicInput);
      if (sample > signalMax){
        signalMax = sample;
      }
      if (sample < signalMin){
        signalMin = sample;
      }
    }
    peakToPeak = signalMax - signalMin;

    //control left mouse button with sound data
    if (peakToPeak >= 570){
      Mouse.press();
      mouseDown = true;
      //Serial.print(peakToPeak);
      //Serial.print(" ");
      //Serial.print(sample);
      //Serial.println(" Clicked Mouse with Mic");
    }
    else if (peakToPeak < 570 && mouseDown == true){
      Mouse.release();
      mouseDown = false;
      //Serial.print(peakToPeak);
      //Serial.print(" ");
      //Serial.print(sample);
      //Serial.println(" Released Mouse");
    }

    //control cursor and right mouse button with rotary encoder
    r.loop();
    currentRotA = r.getPosition();
    if (currentRotA != lastRotA && (millis()-rotMillis > 250)){
      rotMillis = millis();
      lastRotA = currentRotA;
      if(r.directionToString(r.getDirection()) == "LEFT"){
        mouseGo = -40;
      }
      else{
        mouseGo = 40;
      }

      Mouse.press(MOUSE_RIGHT);
      Mouse.move(mouseGo, 0);
      Mouse.release(MOUSE_RIGHT);
      Serial.print("Mouse goes: ");
      Serial.println(r.directionToString(r.getDirection()));
    }

    while (millis()-rotMillis < 250){
      currentRotA = r.getPosition();
      lastRotA = currentRotA;
    }

   
    //toggles menus and tab key with low light sensor value
    if (analogRead(CPLAY_LIGHTSENSOR) < 15 && (millis()-menuMillis > 1000)){
      menuMillis = millis();
     
      menuActive = !menuActive;
      //Serial.println(menuActive);

      Keyboard.press(KEY_TAB);
      Keyboard.release(KEY_TAB);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
    }  
                                                                                                                                             
  }
  else{
    Keyboard.releaseAll();
    Mouse.release();
  }
}

// on change
void rotate(Rotary& r) {
   Serial.println(r.getPosition());
}

// on left or right rotattion
void showDirection(Rotary& r) {
  Serial.println(r.directionToString(r.getDirection()));
}

Team 5: Fish Controller


Description 

Our controller takes the playful, unexpected form of a fish—transforming the caught object into the control mechanism itself. This inversion lies at the heart of our conceptual model: instead of wielding a tool to catch a fish, the player interacts with the fish to control the act of fishing. This ironic, self-aware design ties directly into the game's humorous tone.

Inputs are gathered through flex sensors embedded along the fish’s body and light sensors positioned in its eyes. Flex sensors capture pressure and bending from player touches, squeezes, or twists—allowing the system to detect where and how the fish is being held or manipulated that is then mapped into the four cardinal directions. Meral detectors in the mouth act as a unique form of interaction detection: if the player taps them with a provided hook, the controller interprets that as a distinct command, as two contect buttons. There's also a tail linked to a potentiometer that's required to be constantly moving in order to keep reading inputs. Outputs, then, are actions within the game—casting the line, reeling in, and even interacting with in-game menus—mapped creatively to these gestures.

Feedback is primarily visual and in-game, with exaggerated animations or haptic pulses when certain thresholds are hit. This closed loop—physical input yielding immediate, meaningful feedback—reinforces the affordance of the fish-shaped controller as a usable, learnable interface.

The absurdity of the form is balanced by the consistency of the interaction logic, and despite lacking traditional buttons, the tactile and spatial input model helps make the experience cohesive.

Open-ended question for peer feedback: Does the form of the controller lend itself well to prolonged use, or does its novelty risk overshadowing ergonomic function?

Contributions

Chris:
- Created casing
- Drew schematic
- Soldered sensors
- Programmed most code

Gavin:
- Secondary coder
- Soldered wires and CPE

Schematic

Code

//Keyboard layouts for various languages
#include <Keyboard.h>
#include <KeyboardLayout.h>
#include <Keyboard_da_DK.h> //Danish
#include <Keyboard_de_DE.h> //German
#include <Keyboard_es_ES.h> //Spanish
#include <Keyboard_fr_FR.h> //French
#include <Keyboard_hu_HU.h> //Hungarian
#include <Keyboard_it_IT.h> //Italian
#include <Keyboard_pt_PT.h> //Portuguese
#include <Keyboard_sv_SE.h> //Swedish

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

// Variables
int rawPot;
int lastPot;

// Raw Data Of Flex Sensors
int flexUp;
int flexDown;
int flexLeft;
int flexRight;

// Mapped Data of Flex Sensors
int goUp;
int goDown;
int goLeft;
int goRight;

// Is the tail moving?
bool swimming = false;
byte potPercentage;
byte oldPercentage;

// Detects if Hook Circuit is Complete
int leftHook;
int rightHook;

void setup() 
{
  pinMode(CPLAY_SLIDESWITCHPIN, INPUT_PULLUP); // Detects if CPE Switch is turned on
  CircuitPlayground.begin();
  Serial.begin(9600);

  pinMode(10, INPUT_PULLDOWN); // Read for Left Hook (Pin A3/D10)
  pinMode(3, INPUT_PULLDOWN); // Read for Right Hook (Pin A4/D3)
}

void loop() {
  if(digitalRead(CPLAY_SLIDESWITCHPIN)) 
  {
    //Reads if Potentiometer is moving, double read pot
    rawPot = analogRead(A0);
    rawPot = analogRead(A0);
    rawPot = constrain(rawPot, 16, 1008); //Prevents most bounce
    
    if(rawPot < (lastPot - 4) || rawPot > (lastPot + 4))
    {
      lastPot = rawPot;
      potPercentage = map(lastPot, 16, 1000, 1, 50);

      if(oldPercentage != potPercentage)
      {
        swimming = true;
        // Serial.print("Pot percentage: ");
        // Serial.print(potPercentage);
        // Serial.println("%");
        oldPercentage = potPercentage;
      }
    }
    
    leftHook = digitalRead(10); //Read if Left Hook is active
    //Action of Left Hook
    if(leftHook == HIGH) 
    {
      Keyboard.press(' ');
      Serial.println("Space Bar");
    } 
    Keyboard.release(' ');
    
    rightHook = digitalRead(3); //Reads if Right Hook is active
    //Action of Right Hook
    if(rightHook == HIGH) 
    {
      Keyboard.press('C');
      Serial.println("Cancel");
    } 
    Keyboard.release('C');
  
    //Only Active when tail is moving
    if(swimming) 
    {
      flexUp = analogRead(A6);
      goUp = map(flexUp, 1023, 1, 100, 1);
      if(goUp <= 50)
        Keyboard.press(KEY_UP_ARROW);

      flexLeft = analogRead(A5);
      goLeft = map(flexLeft, 1023, 1, 100, 1);
      if(goLeft <= 50)
        Keyboard.press(KEY_LEFT_ARROW);

      flexDown = analogRead(A2);
      goDown = map(flexDown, 1023, 1, 100, 1);
      if(goDown <= 50)
        Keyboard.press(KEY_DOWN_ARROW);

      flexRight = analogRead(A1);
      goRight = map(flexRight, 1023, 1, 100, 1);
      if(goRight <= 50)
        Keyboard.press(KEY_RIGHT_ARROW);

      Serial.println("Swimming");
    }

  delay(100);
  swimming = false;
  }
}

Demonstration



Team 3 - Co-op League of Legends Controller

 Co-op League of Legends Controller



 
https://youtu.be/9FyNy_wmSOw
 
 
 
 
  1.  The idea for our controller came from our team's shared enjoyment of the game League of Legends and its lore. We wanted to pay tribute to one of the game's artifacts with a great backstory, a pair of powerful gauntlets that ended up in the hands of two different people; therefore, we decided on two different controllers in the form of Ezreal and Kassadin's gauntlets. One controls movement and skillshot direction mirroring a ranged adc (ezreal), while the other is used to fire abilities mirroring the ability-based assassin (kassadin). The idea is you would play League cooperatively with two people, each using one gauntlet, but one person could play with both gauntlets as well. The novelty of engaging in gameplay in a new manner (coop) and the lore representation seek to give the player an enjoyable, social way of playing a famously toxic and stressful game.Question: Do you think that making the controllers character specific in the game as well would make the design better and have a stronger thematic and give more room to explore better thematic to mechanic ties? Reference:
    Ezreal with his gauntlet 

     
      
    Kassadin with his gauntlet 

     
     Ezreal's Gauntlet
     
    #include <Adafruit_CircuitPlayground.h> #include <Adafruit_Circuit_Playground.h> #include <Mouse.h> #include <Keyboard.h> #include <Wire.h> #include <SPI.h> void setup() { // put your setup code here, to run once: // put your setup code here, to run once: CircuitPlayground.begin(); Serial.begin(9600); Mouse.begin(); Keyboard.begin(); CircuitPlayground.setBrightness(60); for(int i = 0; i < 9; i++){ CircuitPlayground.setPixelColor(i,128,0,128); }
    CircuitPlayground.setAccelRange(LIS3DH_RANGE_2_G); //need to create a variable to store the mouses last know position from the center point // Using mouse libraray exmaple code as a base lets cook } // the loop routine runs over and over again forever: void loop() { // read the input on analog pin A0: int analogValue = analogRead(A3); // Rescale to potentiometer's voltage (from 0V to 5V): float voltage = analogValue * (3.3/ 1023); if(analogValue > 240){ Keyboard.press('q'); delay(75); Keyboard.release('q'); } if(analogValue > 240 && analogValue < 300){ Keyboard.press('w'); delay(75); Keyboard.release('w'); } if(analogValue > 300){ Keyboard.press('e'); delay(75); Keyboard.release('e'); }
    // print out the value you read: Serial.print("Analog: "); Serial.print(analogValue); Serial.print(", Voltage: "); Serial.println(voltage); }

  2. char getMappedChar(int analogValue) { // Define the ranges for each character with dead zones const int deadZoneSize = 10; // Size of each dead zone const int charRanges[] = {163, 162, 162, 162, 162, 162}; // Sizes for q, w, e, r, d, f const char chars[] = {'q', 'w', 'e', 'r', 'd', 'f'}; int start = 0; for (int i = 0; i < 6; i++) { int end = start + charRanges[i] - 1; // End of current char's range if (analogValue >= start && analogValue <= end) { return chars[i]; } start = end + 1 + deadZoneSize; // Skip the dead zone } return '\0'; // Return null if out of range (shouldn't happen for 0-1022) } void setup() { Serial.begin(9600); } void loop() { // Simulate an analog input (0-1023) for testing int simulatedValue = random(0, 1023); char mappedChar = getMappedChar(simulatedValue); Serial.print("Value: "); Serial.print(simulatedValue); Serial.print(" → Mapped Char: "); Serial.println(mappedChar); delay(500); // Slow down output for readability }
  3. char getMappedChar(int analogValue) { const int deadZoneSize = 50; // Increased dead zone size const int charRanges[] = {129, 129, 129, 129, 129, 128}; // q, w, e, r, d, f const char chars[] = {'q', 'w', 'e', 'r', 'd', 'f'}; int start = 0; for (int i = 0; i < 6; i++) { int end = start + charRanges[i] - 1; // End of current char's range if (analogValue >= start && analogValue <= end) { return chars[i]; } start = end + 1 + deadZoneSize; // Skip dead zone } return '\0'; // Out of range (1023 is unused) } void setup() { Serial.begin(9600); } void loop() { // Simulate analog input (0-1023) int simulatedValue = random(0, 1023); char mappedChar = getMappedChar(simulatedValue); Serial.print("Value: "); Serial.print(simulatedValue); Serial.print(" → Mapped Char: "); Serial.println(mappedChar); delay(500); }
  4. switch (mappedChar) { case 'q': Serial.println("Action: Q pressed!"); // Your code for 'q' here break; case 'w': Serial.println("Action: W pressed!"); // Your code for 'w' here break; case 'e': Serial.println("Action: E pressed!"); // Your code for 'e' here break; case 'r': Serial.println("Action: R pressed!"); // Your code for 'r' here break; case 'd': Serial.println("Action: D pressed!"); // Your code for 'd' here break; case 'f': Serial.println("Action: F pressed!"); // Your code for 'f' here break; default: Serial.println("No action (dead zone or out of range)"); break;


  5. ''#include <Adafruit_CircuitPlayground.h> #include <Adafruit_Circuit_Playground.h> #include <Mouse.h> #include <Wire.h> #include <SPI.h> int range = 12; int delayTimer = 2; int center = range/2; int threshold = range / 4; float minMotionx = 1; float maxMoition = 10; bool on = false; void setup() { // put your setup code here, to run once: // put your setup code here, to run once: CircuitPlayground.begin(); Serial.begin(9600); Mouse.begin(); CircuitPlayground.setBrightness(75); for(int i = 0; i < 9; i++){ CircuitPlayground.setPixelColor(i,0,0,128); }
    CircuitPlayground.setAccelRange(LIS3DH_RANGE_2_G); //need to create a variable to store the mouses last know position from the center point // Using mouse libraray exmaple code as a base lets cook
    } float AccelReader(){ float x = 0; float y = 0; float z = 0; //Should it be a one time read on call or should i have a read for a set Time? //The examples I've seen have had a fixed read but i think that wil for(int i = 0; i < 15; i++){ x += CircuitPlayground.motionX(); y += CircuitPlayground.motionY(); z += CircuitPlayground.motionZ();
    } //might need to trim these to be an average or make a buffer return sqrt(xx + yy + zz); } float lerp(float x, float x0, float x1, float y0, float y1) { // Check if the input value (x) is outside its desired range and clamp to // those min/max y values. if (x <= x0) { return y0; } else if (x >= x1) { return y1; } // Otherwise compute the value y based on x's position within its range and // the desired y min & max. return y0 + (y1-y0)((x-x0)/(x1-x0)); } void loop() { // put your main code here, to run repeatedly: if(CircuitPlayground.leftButton() == HIGH && on == false){ on = true; } if(CircuitPlayground.rightButton() == HIGH && on == true){ on = false; } if(on){ float inputX = CircuitPlayground.motionX(); Serial.println(CircuitPlayground.motionX()); float inputY = CircuitPlayground.motionY(); Serial.println(CircuitPlayground.motionY()); float x_mag = abs(inputX); float x_mouse = lerp(x_mag, minMotionx, maxMoition, 0.0, 12); float y_mag = abs(inputY); float y_mouse = lerp(y_mag, minMotionx, maxMoition, 0.0, 12); // Change the mouse direction based on the direction of the acceleration. if (inputX < 0) { x_mouse = -1.0; } if (inputY < 0) { y_mouse= -1.0; }

    //int mouseX = Mapping(inputX, 0); //Serial.println(inputX); //int mouseY = Mapping(inputY, 1); //Serial.println(inputY); Mouse.move((int)x_mouse, (int)y_mouse, 0); delay(10); if(CircuitPlayground.slideSwitch()){ Mouse.click(MOUSE_RIGHT); } } }'''










  6. Kassadin's Gauntlet
  7. #include <Adafruit_CircuitPlayground.h> #include <Adafruit_Circuit_Playground.h> #include <Mouse.h> #include <Keyboard.h> #include <Wire.h> #include <SPI.h> //splits the analog value across 6 values and assigns a button to each range char getMappedChar(int analogValue) { const int deadZoneSize = 50; // dead zone size between values const int charRanges[] = {129, 129, 129, 129, 129, 128}; // q, w, e, r, d, f const char chars[] = {'q', 'w', 'e', 'r', 'd', 'f'}; int start = 0; for (int i = 0; i < 6; i++) { int end = start + charRanges[i] - 1; // End of current char's range if (analogValue >= start && analogValue <= end) { return chars[i]; } start = end + 1 + deadZoneSize; // Skip dead zone } return '\0'; // Out of range (1023 is unused) } void setup() { // put your setup code here, to run once: // put your setup code here, to run once: CircuitPlayground.begin(); Serial.begin(9600); Mouse.begin(); Keyboard.begin(); CircuitPlayground.setBrightness(60); for(int i = 0; i < 9; i++){ CircuitPlayground.setPixelColor(i,128,0,128); }
    CircuitPlayground.setAccelRange(LIS3DH_RANGE_2_G); } bool firing_State; // the loop routine runs over and over again forever: void loop() { while (CircuitPlayground.slideSwitch()) { int analogValue = analogRead(A1); // Rescale to potentiometer's voltage (from 5v to 3.3V): float voltage = analogValue * (3.3/ 1023); char keypress = getMappedChar(analogValue); //can fire if (CircuitPlayground.motionX() > 9) { firing_State = true; } //Swapps key press based on potentiometer switch (keypress) { case 'q': if(firing_State){ Serial.println("Action: Q pressed!"); Keyboard.press('q'); delay(100); Keyboard.release('q'); } break; case 'w': if(firing_State){ Serial.println("Action: W pressed!"); Keyboard.press('w'); delay(100); Keyboard.release('w'); } break; case 'e': if(firing_State){ Serial.println("Action: E pressed!"); Keyboard.press('e'); delay(100); Keyboard.release('e'); } break; case 'r': if(firing_State){ Serial.println("Action: R pressed!"); Keyboard.press('r'); delay(100); Keyboard.release('r'); } break; case 'd': if(firing_State){ Serial.println("Action: D pressed!"); Keyboard.press('d'); delay(100); Keyboard.release('d'); } break; case 'f': if(firing_State){ Serial.println("Action: F pressed!"); Keyboard.press('f'); delay(100); Keyboard.release('f'); } break; default: Serial.println("No action (dead zone or out of range)"); break; }
    // print out the value you read: Serial.print("Analog: "); Serial.print(analogValue); Serial.print(", Voltage: "); Serial.println(voltage); } }
  8. k