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.