18 April 2021

Crypt of the Necrodancer: Gyro-Glove


 For my game controller, I created a gyroscopic glove that would press the Up, Down, Left, and Right keys depending on the tilt of the glove. I chose the game Crypt of the Necrodancer, because I thought it would be an interesting challenge to try and make a controller for it, and I also like unique rhythm games.

                                    

The Concept

You may be wondering, why a glove? I got the idea based on the phrase "wearing your heart on your sleeve", or in this case it would be the glove. Within the game you move based on timing to the music, and in the middle of the metronome is a heart. The main character also wears gloves, so it fits in that sense as well. I wanted it to simulate the curse that the player character is under in a way as well, which is that they are only able to move their body with the tempo of the music.



Parts of the Controller:

On the back hand part of the glove, you see the "heart" of the controller, the circuit playground, as well as some arrow markings to signify that you should tilt the glove in order to press those arrows. So tilting your hand left presses the left arrow, tilting your hand right presses the right arrow, bending your wrist up hits the up button, and bending your wrist down hits the down button. You can also hit combo buttons on the tilts that have a combination of both, like if you tilt left and bend up you will hit the left and up button at once. When a arrow is hit the circuit playground will light up saying it was hit, you cannot hit another arrow until it is not lit, this helps give feedback to the person playing. On the palm of the hand there is a circular mark marked with an up and down arrow in the middle to signify pressing or gripping  the palm of the hand to press the up and down button. On the microprocessor itself, you are also able to press the b button in order to press the escape button. It is not really necessary to use in the game, so I didn't clearly mark it, but I included the option for convenience.



Reflection:

I had originally had a much more complicated set up with my schematic with four pressure sensors on the finger tips, but due to time constraints, and some frustration while building, I ended up simplifying the design to focus on the gyroscope. (The original set up was all wired, and I had some frustration keeping the wires working and fitting them into a outer glove comfortably.) I eventually found a way to keep the wiring together better, and if I would've had more time, I would definitely go back and try to do what I had originally planned.


Question:

Do you think there is a better way to signify to others that they need to tilt their hands to press a button?


Code:


#include <Adafruit_CircuitPlayground.h>

#include <Adafruit_Circuit_Playground.h>

#include <Keyboard.h>


//Constants========================

const int debounce = 200; //button press delay

const float thresholdR = 6.9;//right min

const float thresholdL = 1.7;//left min

const float thresholdD = 1.5;//down min

const float thresholdU = 4.3; //up min

const float dblThresh1 = 2; //combination arrow threshold 1

const float dblThresh2 = 6; //combination threshold 2

const int touchThresh = 500; //min pressure to count as pressed

const float zThresh = 4; //z axis threshold

const float zThreshL = 7.5; //z axis threshold for left tilt


//Variables=======================  

//check if returned to neutral state--------------------------------------

bool gyroReturn=1; //gyroscope check

bool touchReturn1=1;// pressure sensor check


//analog reads----------------------------------------------------

int touchPin1= 1;   // the FSR and 10K pulldown are connected to a1


// the analog reading from the FSR resistor divider--------------

int touch1;         

    


//Setup============================================

void setup() {

 //escape key setup

 pinMode( 5, INPUT_PULLDOWN);//Escape Button


Serial.begin(9600);

CircuitPlayground.begin();

//keyboard set up

Keyboard.begin();

}


//Loop============================================

void loop() {

//Escape key press====================================

 if (digitalRead(5) == 1){

 Keyboard.write(177);//escape

 Serial.println("escape");

 delay (debounce+ 200);

  }


//Gyroscope==============================================

//read accelerometer x and y

float x = CircuitPlayground.motionX();

float y = CircuitPlayground.motionY();

float z = CircuitPlayground.motionZ(); 

Serial.print (x);

Serial.print ("\t");

Serial.println(y);

Serial.print ("\t");

Serial.println(z);

// 2 Combo arrows--------------------------------------------------

if (x < -dblThresh1 && y > dblThresh1 && gyroReturn == 1){//left down

  gyroReturn = 0;

  Keyboard.write(216);//left

  Keyboard.write(217);//down

  delay(debounce);

  Serial.println("Left-Down");

 

  //light up

  CircuitPlayground.setPixelColor(9,50,5,20);

  CircuitPlayground.setPixelColor(8,50,5,20);

  CircuitPlayground.setPixelColor(7,50,5,20);

  CircuitPlayground.setPixelColor(6,50,5,20);

   CircuitPlayground.setPixelColor(5,50,5,20);

   CircuitPlayground.setPixelColor(4,50,5,20);

   CircuitPlayground.setPixelColor(3,50,5,20);

   CircuitPlayground.setPixelColor(2,50,5,20);

   CircuitPlayground.setPixelColor(1,50,5,20);

   CircuitPlayground.setPixelColor(0,50,5,20);

 }


else if (x < -dblThresh1 && y < -thresholdU && gyroReturn == 1){//left up

 gyroReturn = 0;

  Keyboard.write(216);//left

  Keyboard.write(218);//up

  delay(debounce);

  Serial.println("Left-Up");

 

  //light up

   CircuitPlayground.setPixelColor(9,50,5,20);

   CircuitPlayground.setPixelColor(8,50,5,20);

   CircuitPlayground.setPixelColor(7,50,5,20);

   CircuitPlayground.setPixelColor(6,50,5,20);

   CircuitPlayground.setPixelColor(5,50,5,20);

   CircuitPlayground.setPixelColor(4,50,5,20);

   CircuitPlayground.setPixelColor(3,50,5,20);


   CircuitPlayground.setPixelColor(2,50,5,20);

   CircuitPlayground.setPixelColor(1,50,5,20);

   CircuitPlayground.setPixelColor(0,50,5,20);

}


else if (x > thresholdR && y > dblThresh1 && gyroReturn == 1){//right down

  gyroReturn = 0;

  Keyboard.write(215);//right

  Keyboard.write(217);//down

  delay(debounce);

  Serial.println("Right-Down");

 

  //light up

   CircuitPlayground.setPixelColor(9,50,5,20);

   CircuitPlayground.setPixelColor(8,50,5,20);

   CircuitPlayground.setPixelColor(7,50,5,20);

   CircuitPlayground.setPixelColor(6,50,5,20);

   CircuitPlayground.setPixelColor(5,50,5,20);

   CircuitPlayground.setPixelColor(4,50,5,20);

   CircuitPlayground.setPixelColor(3,50,5,20);

   CircuitPlayground.setPixelColor(2,50,5,20);

   CircuitPlayground.setPixelColor(1,50,5,20);

   CircuitPlayground.setPixelColor(0,50,5,20);


else if (x > dblThresh1 && y < -thresholdR && gyroReturn == 1){//right up

  gyroReturn = 0;

  Keyboard.write(215);//right

  Keyboard.write(218);//up

  delay(debounce);

  Serial.println("Right-Up");

 

  //light up

   CircuitPlayground.setPixelColor(9,50,5,20);

   CircuitPlayground.setPixelColor(8,50,5,20);

   CircuitPlayground.setPixelColor(7,50,5,20);

   CircuitPlayground.setPixelColor(6,50,5,20);

   CircuitPlayground.setPixelColor(5,50,5,20);

   CircuitPlayground.setPixelColor(4,50,5,20);

   CircuitPlayground.setPixelColor(3,50,5,20);

   CircuitPlayground.setPixelColor(2,50,5,20);

   CircuitPlayground.setPixelColor(1,50,5,20);

   CircuitPlayground.setPixelColor(0,50,5,20);

}


 //normal arrows---------------------------------------------------------------------------

//negative x left 

else if (x < thresholdL &&  z > zThreshL && gyroReturn == 1){

 gyroReturn = 0;

  Keyboard.write(216);

  delay(debounce);

  Serial.println("Left");

 

  //light up

   CircuitPlayground.setPixelColor(9,50,5,20);

   CircuitPlayground.setPixelColor(8,50,5,20);

   CircuitPlayground.setPixelColor(7,50,5,20);

   CircuitPlayground.setPixelColor(6,50,5,20);

   CircuitPlayground.setPixelColor(5,50,5,20);

   CircuitPlayground.setPixelColor(4,50,5,20);

   CircuitPlayground.setPixelColor(3,50,5,20);

   CircuitPlayground.setPixelColor(2,50,5,20);

   CircuitPlayground.setPixelColor(1,50,5,20);

   CircuitPlayground.setPixelColor(0,50,5,20);

}


//positive x right 

else if (x > thresholdR && z < zThresh && gyroReturn == 1){

 gyroReturn = 0;

  Keyboard.write(215);

  delay(debounce);

  Serial.println("Right");

 

  //light up

   CircuitPlayground.setPixelColor(9,50,5,20);

   CircuitPlayground.setPixelColor(8,50,5,20);

   CircuitPlayground.setPixelColor(7,50,5,20);

   CircuitPlayground.setPixelColor(6,50,5,20);

   CircuitPlayground.setPixelColor(5,50,5,20);

   CircuitPlayground.setPixelColor(4,50,5,20);

   CircuitPlayground.setPixelColor(3,50,5,20);

   CircuitPlayground.setPixelColor(2,50,5,20);

   CircuitPlayground.setPixelColor(1,50,5,20);

   CircuitPlayground.setPixelColor(0,50,5,20);

}


//negative y up

else if (y < -thresholdU && z > zThresh && gyroReturn == 1){

 gyroReturn = 0;

  Keyboard.write(218);

  delay(debounce);

  Serial.println("Up");

  //light up

   CircuitPlayground.setPixelColor(9,50,5,20);

   CircuitPlayground.setPixelColor(8,50,5,20);

   CircuitPlayground.setPixelColor(7,50,5,20);

   CircuitPlayground.setPixelColor(6,50,5,20);

   CircuitPlayground.setPixelColor(5,50,5,20);

   CircuitPlayground.setPixelColor(4,50,5,20);

   CircuitPlayground.setPixelColor(3,50,5,20);

   CircuitPlayground.setPixelColor(2,50,5,20);

   CircuitPlayground.setPixelColor(1,50,5,20);

   CircuitPlayground.setPixelColor(0,50,5,20);

}


//positive y Down

else if (y > thresholdD && z > zThresh && gyroReturn == 1){

  gyroReturn = 0;

  Keyboard.write(217);

  delay(debounce);

  Serial.println("Down");

  //light up

      CircuitPlayground.setPixelColor(9,50,5,20);

      CircuitPlayground.setPixelColor(8,50,5,20);

      CircuitPlayground.setPixelColor(7,50,5,20);

      CircuitPlayground.setPixelColor(6,50,5,20);

      CircuitPlayground.setPixelColor(5,50,5,20);

      CircuitPlayground.setPixelColor(4,50,5,20);

      CircuitPlayground.setPixelColor(3,50,5,20);

      CircuitPlayground.setPixelColor(2,50,5,20);

      CircuitPlayground.setPixelColor(1,50,5,20);

      CircuitPlayground.setPixelColor(0,50,5,20);

//if still "pressed" stay "pressed"

else if (y > thresholdD && gyroReturn == 0 ||y < -thresholdU && gyroReturn == 0||x > thresholdR && gyroReturn == 0||x < thresholdL && gyroReturn == 0){ 

 gyroReturn = 0;

  //delay(1000);

  Serial.println("not returned");

}

else {

  gyroReturn = 1;

  Serial.println("Neutral");

  //turn off lights

   CircuitPlayground.setPixelColor(9,0,0,0);

   CircuitPlayground.setPixelColor(8,0,0,0);

   CircuitPlayground.setPixelColor(7,0,0,0);

   CircuitPlayground.setPixelColor(6,0,0,0);

   CircuitPlayground.setPixelColor(5,0,0,0);

   CircuitPlayground.setPixelColor(4,0,0,0);

   CircuitPlayground.setPixelColor(3,0,0,0);

   CircuitPlayground.setPixelColor(2,0,0,0);

   CircuitPlayground.setPixelColor(1,0,0,0);

   CircuitPlayground.setPixelColor(0,0,0,0);

}

//Touch Sense============================================== 

//pressure read

touch1 = analogRead(touchPin1);  

Serial.print("Touch reading 1 = ");

Serial.print(touch1);     // the raw analog reading


//pressed 

//up down when hand neutral 

  if (touch1 > touchThresh && touchReturn1 == 1 && gyroReturn == 1) {

    touchReturn1 = 0;

    Keyboard.write(218);

    Keyboard.write(217);


    delay(debounce);

    Serial.println("up-down");

  }

//left right when hand tilted

  else if (touch1 > touchThresh && touchReturn1 == 1 && gyroReturn != 1) {

    touchReturn1 = 0;

    Keyboard.write(216);

     Keyboard.write(215);

    delay(debounce);

    Serial.println("left right");

  }

//else pressure released

   else {

    touchReturn1 = 1;

    Serial.println("Neutral");

  }

}

No comments:

Post a Comment

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