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:



No comments:

Post a Comment

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