18 April 2022

GAME CONTROLLER - VAMPIRE SURVIVORS






This my game controller project for DIG3602 Physical Computing. 
The game I am covering is called Vampire Survivors, it is an indie game released in December 2021.
Even though it is a recent game, the graphics are closer to a 80's game console. Nonetheless the gameplay is smooth and the roguelike elements are makes it more modern. The goal of this game is to fight off hordes of vampires and related monsters and survive as long as possible. This is one of those games that blows every other early access indie games out of the water. 

My controller consists of 3 distinct parts. The main part is the Circuit Playground Bluefruit (CPB) running with Arduino. I have an attached an external battery using the 2 pin JST port of the CPB which is the second part. Lastly, the 3D printed enclosure where the CPB and the battery resides, which I printed in the UCF Downtown's Maker Space.

What I want from the CPB is two main features. I want to use the accelerometer that is part of the CPB to determine my inputs, and I want to use the Bluetooth functionalities of the device to have a completely wireless controller.

The 3D printed enclosure I made represents a garlic. Now I chose the garlic because in this game, like in many vampire stories and pieces of fiction, vampires have weaknesses and one of the most known weakness is garlic. Similarly, in this game there are power ups and weapons you can acquire through leveling up. One of those power ups is the garlic which gives your character an area of effect around it that damages and pushes back enemies. It is one of my favorite power ups so once I brainstormed ideas for the game controller I knew instantly I would be using this game and this power.

Regarding the controller functionalities: the main use of the CPB is the integrated accelerometer. Using arduino code, the CPB is able to read X and Y values that fluctuate when tilting the device. It then maps those values accordingly to 4 different outputs ( W, A, S,D keyboard presses) to be able to control thecharacter's movement. The character moves in the four directions but can move diagonally with 2 simultaneous inputs. One more input/output is the ENTER keyboard press to select a menu or power up and whatnot. That is determined with reading the X, Y and Z values. If the sum of those values reaches a threshold, a shake is detected and the key is pressed.







The use of accelerometer in technology and gaming especially has hugely evolved through the years. In my opinion my controller and its use of accelerometer is now considered relatively rudimentary compared to VR controllers and high tech devices that use them. I am now left wondering if tilt controls and accelerometer devices will play a significant part in the future of gaming?






CODE:

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

BLEDis bledis;
BLEHidAdafruit blehid;
const int debounce = 15;
boolean shook = false;
int shakeT = 25;



void setup() {    // put your setup code here, to run once:
Serial.begin(9000);
  delay(1000);
  CircuitPlayground.begin();
  Bluefruit.begin();
  Bluefruit.setTxPower(4);    // Check bluefruit.h for supported values

  // Configure and Start Device Information Service
  bledis.setManufacturer("Adafruit Industries");
  bledis.setModel("Bluefruit Feather 52");
  bledis.begin();
  blehid.begin();
  //
 
    // Set up and start advertising
  startAdv();
  // set up
  

  }
  void loop() {    // put your main code here, to run repeatedly:
    //read accelerometer x and y 
    float x = CircuitPlayground.motionX(); 
    float y = CircuitPlayground.motionY();
    Serial.print(x);
    Serial.print("\t");
    Serial.println(y);

    //read switch on CPB, when on controls functional
  if(digitalRead(7)){
    //go right
    if(x < -3 ) { 
      blehid.keyPress('d');
    //delay(debounce);
    } 
    
    //go left
    if(x > 3) { 
      blehid.keyPress('a'); 
    delay(debounce); 
    } 
    //neutral position
    if(x < 1 && x > -1 && y < 1 && y > -1 ) {
          
          blehid.keyRelease();
    }
     
    //go up
    if(y < -3) {
      blehid.keyPress('w'); 
    delay(debounce);
    } 
    //go down
    if(y > 3) { 
      blehid.keyPress('s');
      delay(debounce); 
      }
      
 
// read absolute value of all accelerometer X Y Z values, if sum of those reach threshhold, enter key press
    float shake = abs(CircuitPlayground.motionX()) + abs(CircuitPlayground.motionY())+ abs(CircuitPlayground.motionZ());
      if(shake > shakeT) {
        uint8_t keycodes[6] = {HID_KEY_ENTER, HID_KEY_NONE ,HID_KEY_NONE ,HID_KEY_NONE ,HID_KEY_NONE};
          blehid.keyboardReport(0 , keycodes);
          delay(debounce);
        }

  }
 }
void startAdv(void)
{  
  // Advertising packet
  Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
  Bluefruit.Advertising.addTxPower();
  Bluefruit.Advertising.addAppearance(BLE_APPEARANCE_HID_KEYBOARD);
  
  // Include BLE HID service
  Bluefruit.Advertising.addService(blehid);

  // There is enough room for the dev name in the advertising packet
  Bluefruit.Advertising.addName();
  
  /* Start Advertising
   * - Enable auto advertising if disconnected
   * - Interval:  fast mode = 20 ms, slow mode = 152.5 ms
   * - Timeout for fast mode is 30 seconds
   * - Start(timeout) with timeout = 0 will advertise forever (until connected)
   * 
   * For recommended advertising interval
   * https://developer.apple.com/library/content/qa/qa1931/_index.html   
   */
  Bluefruit.Advertising.restartOnDisconnect(true);
  Bluefruit.Advertising.setInterval(32, 244);    // in unit of 0.625 ms
  Bluefruit.Advertising.setFastTimeout(30);      // number of seconds in fast mode
  Bluefruit.Advertising.start(0);                // 0 = Don't stop advertising after n seconds
}

No comments:

Post a Comment

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