17 April 2022

Joseph Hart Major 2

Super Monkey Ball: Banana Mania Controller

The controller is a spherical motion detecting device designed after the character shape in Super Monkey Ball. It has one button for toggling motion controls.

LED lights deliver feedback on user behavior: such as what direction they are tilting the device; if it is in motion-control mode or not, and which direction is the forward direction.

Monkey Ball has one mechanic of rolling the ball around; the controllers looks like the capsule the character rolls around it, connecting to the experience thematically as well in terms of physicality.







My question is: since my game didn't quite work out, what other games would suite this controller?


Full Code:

#include <Adafruit_CircuitPlayground.h>

#include <Adafruit_Circuit_Playground.h>

#include <bluefruit.h>

#include <math.h>


BLEDis bledis;

BLEHidAdafruit blehid;


int debounce(200);  //Only used for toggling motion controls

int neonum;         //For lighting up LED's

int movedir;        //For  motion-to-key presses


int gate = 0;       //Place holder for remembering previous movedir value

bool motion = false;  //Motion control toggle

bool deadzone;        //Device is flat and has no output


const float thresh = 1.5; //The degree in decimal-system by which the device must be tilt to exit deadzone


void setup(){

  //Init library

  Bluefruit.begin();

  Bluefruit.setTxPower(4);

  //Configure and start device information service

  bledis.setManufacturer("Adafruit Industries");

  bledis.setModel("Bluefruit Feather 52");

  bledis.begin();

  //Start HID, Bluetooth, and Playground

  blehid.begin();

  Adv();

  CircuitPlayground.begin();

  //other

  //Serial.begin(9600); //All debugging has since been removed

}


void Adv(void) {

  //Bluetooth advertise info

  Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);

  Bluefruit.Advertising.addTxPower();

  Bluefruit.Advertising.addAppearance(BLE_APPEARANCE_HID_KEYBOARD);

  Bluefruit.Advertising.addService(blehid);

  Bluefruit.Advertising.addName();

  Bluefruit.Advertising.restartOnDisconnect(true);

  Bluefruit.Advertising.setInterval(32, 244);

  Bluefruit.Advertising.setFastTimeout(30);

  Bluefruit.Advertising.start(0);

}


void GetTilt() {

  //Read motion values, then check for dead zone. If it's good light appropriate pixels

  //Otherwise, if dead, then light up all pixels.

  float x = CircuitPlayground.motionX();

  float y = CircuitPlayground.motionY();

  float rad = atan2(y, x);

  deadcheck(x,y);

  if (!deadzone) setPixels(rad);

  else setCali();

}


void setPixels(float rad){

  //Map the neonum to 10 and movedir to 8 (circuit board has 10 lights and keyboard has 8 directions).

  //Belt the values if they drop below 0. Clear all pixels eitherway.

  //If motion controls are on, we assgin the regular data.

  //If not, we need to call neoreverse and cut the g in rgb.

  neonum = mapfloat(rad, -PI, PI, 0, 10); neonum -= 2;

  movedir = mapfloat(rad, -PI, PI, 0, 8); movedir -= 2;

  if (neonum < 0) neonum += 10;

  if (movedir < 0) movedir += 8;

  CircuitPlayground.clearPixels();

  if (motion)CircuitPlayground.setPixelColor(neonum, 30, 30, 30);

  else CircuitPlayground.setPixelColor(neoReverse(neonum), 30, 0, 30);

}


//Light up the board blue if calibrated, and forward facing lights greenish blue.

void setCali(){

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

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

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

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

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

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

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

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

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

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

}


//Get the reverse of our neonum as it relates to the parimeter of the Arduino

int neoReverse(int x) {

  int result = x + 5; //5 will get us half way around the arduino board, the opposite end.

  if (result > 9) result -= 10; //If our math goes above 9 we need to remove the ten's place from the result.

  return result;

}


//Professor's delight

float mapfloat(float x, float in_min, float in_max, float out_min, float out_max) {

  float result = (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;

  return result;

}


//Determine if our motion floats don't exceed the threshold

void deadcheck(float x, float y){

  if ((x > -thresh && x < thresh)&&(y > -thresh && y < thresh)){

    deadzone = true;

  } else {

    deadzone = false;

  }

}


void loop() {

  //Clear keys incase of deadzone

  if (deadzone) blehid.keyRelease();

  //Getting tilt is all that stuff above we just went through

  GetTilt();

  //Press the button to toggle motion control.

  if (digitalRead(CPLAY_RIGHTBUTTON)) {

    motion = !motion;

    blehid.keyRelease();

    delay(debounce);

  }

  if (motion && !deadzone) {

    //We are going to observe the movedir variable and act accordingly.

    //First thing's first, are we surpassing the threshold? If not, return nothing to escape the function.

    //Next we check to see if the movedir variable is repeating;

    //if not (meaning a new/different input has been performed) we release the keys.

    //After that we begin pressing and holding the appropriate keys.

    //We set a holder variable to keep track of what input was last used, and then break.

    switch (movedir) {

      //Left

      case 5:

        if (deadzone)return;

        if (gate != movedir) blehid.keyRelease();

        blehid.keyPress('a');

        gate = movedir;

        break;

      //Down Left

      case 6:

        if (deadzone)return;

        if (gate != movedir) blehid.keyRelease();

        blehid.keyPress('a');

        blehid.keyPress('s');

        gate = movedir;

        break;

      //Down

      case 7:

        if (deadzone){blehid.keyRelease(); break;}

        if (gate != movedir) blehid.keyRelease();

        blehid.keyPress('s');

        gate = movedir;

        break;

      //Down Right

      case 0:

        if (deadzone)return;

        if (gate != movedir) blehid.keyRelease();

        blehid.keyPress('s');

        blehid.keyPress('d');

        gate = movedir;

        break;

      //Right

      case 1:

        if (deadzone)return;

        if (gate != movedir) blehid.keyRelease();

        blehid.keyPress('d');

        gate = movedir;

        break;

      //Up Right

      case 2:

        if (deadzone)return;

        if (gate != movedir) blehid.keyRelease();

        blehid.keyPress('w');

        blehid.keyPress('d');

        gate = movedir;

        break;

      //Up

      case 3:

        if (deadzone)return;

        if (gate != movedir) blehid.keyRelease();

        blehid.keyPress('w');

        gate = movedir;

        break;

      //Up Left

      case 4:

        if (deadzone)return;

        if (gate != movedir) blehid.keyRelease();

        blehid.keyPress('w');

        blehid.keyPress('a');

        gate = movedir;

        break;

      default: break;

    }

  }

}


No comments:

Post a Comment

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