Our controller was designed for critically acclaimed walking
simulator, The Stanley Parable. In The Stanley Parable, the
player is frequently treated as a separate being to the player character
Stanley. The player merely controls Stanley actions and movements, just like a
puppeteer controls a puppet. That comparison inspired the conceptual model
we used. Instead of just metaphorically puppeteering Stanley through the game,
you are now literally puppeteering Stanley.
Our controller is meant to have a very neutral color scheme,
using the natural color of the wood. We chose this, both because we thought it
looked nice, but also because it fit in with the general aesthetic of The
Stanley Parable. The wires being visible are meant to represent the strings
normally attached to puppet controllers.
Using a gyroscope housed inside each controller, the player can
move around and control the camera, as well as click on objects and press
buttons. The right controller controls player movement, while the left
controller controls the camera. Tilting the right controller forward moves the
player forward, tilting left moves left, tilting right moves right, tilting
back moves backwards. The same general principle follows for the right
controller, only it moves the camera instead. By quickly moving the right
controller up, the player can make a generic keyboard input. By quickly moving
the left controller up, the player can click on an object in-game.
In other words, we mapped tilting a controller in a
direction to moving whatever thing said controller controls in the same
direction.
The signifier as to what input a player is inputting
is the direction they are tilting the controllers, and the feedback is
Stanley or the camera moving in that direction. The signifier for
inputting a keyboard input or a click input is the player moving the controller
up, which has the feedback of the game performing that input.
The affordances of our design makes it so that the
player can control both the camera and Stanley simultaneously, as well as
perform clicks and button inputs. The limitations are that, functionally
speaking, the controller can only make two non-movement/non-camera inputs.
Our Question: What other games do you believe this
controller would be well-suited for, either mechanically or thematically?
Video: https://drive.google.com/file/d/1pfHmym14S9zgqTD6UF5qc1okjSb_ZxnX/view
Schematic:
Code:#include <Keyboard.h>#include <Adafruit_MPU6050.h>#include <Adafruit_Sensor.h>#include <Wire.h>#include <Mouse.h>Adafruit_MPU6050 mpu; // Address 0x68 - for movement/keyboardAdafruit_MPU6050 mpu2; // Address 0x69 - for mouse// Variablesfloat moveX = 0;float moveY = 0;float mouseX = 0;float mouseY = 0;float sensitivity = 40.0; // Mouse Sensitivityvoid setup(void) {Serial.begin(115200);while (!Serial) delay(10);// Initialize first MPU and check for testing purposesif (!mpu.begin(0x68)) {Serial.println("Failed to find MPU6050 at 0x68");while (1) delay(10);}Serial.println("MPU6050 #1 Found at 0x68!");// Initialize second MPU (ADO high) and check for testing purposesif (!mpu2.begin(0x69)) {Serial.println("Failed to find MPU6050 at 0x69");while (1) delay(10);}Serial.println("MPU6050 #2 Found at 0x69!");// Configure both sensorsmpu.setAccelerometerRange(MPU6050_RANGE_8_G);mpu.setGyroRange(MPU6050_RANGE_500_DEG);mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);mpu2.setAccelerometerRange(MPU6050_RANGE_8_G);mpu2.setGyroRange(MPU6050_RANGE_500_DEG);mpu2.setFilterBandwidth(MPU6050_BAND_21_HZ);delay(100);// Initialize keyboard and mosue librariesKeyboard.begin();Mouse.begin();}void loop() {// Get events from first MPU (movement control)sensors_event_t a, g, temp;mpu.getEvent(&a, &g, &temp);// Get events from second MPU (mouse control)sensors_event_t a2, g2, temp2;mpu2.getEvent(&a2, &g2, &temp2);float deltaTime = 0.01;// Use MPU g for movementmoveX += g.gyro.y * deltaTime - 0.0005; // Adjust for driftmoveY += g.gyro.x * deltaTime;// Use MPU2 g2 for mousemouseX -= g2.gyro.y * deltaTime * sensitivity;mouseY -= -1 * (g2.gyro.x * deltaTime * sensitivity + 0.03); // Adjust for drift// Move mouse directily toMouse.move(mouseX, mouseY);// Thresholds for inputsfloat threshold = 0.1;// FORWARD / BACKWARD (W/S)if (moveY > threshold) {Keyboard.release('s');Keyboard.press('w');Serial.println("W");} else if (moveY < -threshold) {Keyboard.release('w');Keyboard.press('s');Serial.println("S");} else {Keyboard.release('w');Keyboard.release('s');}// LEFT / RIGHT (A/D)if (moveX > threshold) {Keyboard.release('d');Keyboard.press('a');Serial.println("A");} else if (moveX < -threshold) {Keyboard.release('a');Keyboard.press('d');Serial.println("D");} else {Keyboard.release('a');Keyboard.release('d');}// JUMP (Z-axis acceleration spike on movement MPU)if (a.acceleration.z > 15.0) {Keyboard.press(' ');Serial.println("Jump");} else {Keyboard.release(' ');}// All other possible prompts (Z-axis acceleration spike on mouse MPU)if (a2.acceleration.z > 15.0){Keyboard.press('e');Keyboard.press('r');Keyboard.press('q');Keyboard.press('t');Keyboard.press('y');Keyboard.press('u');Keyboard.press('i');Serial.println("all buttons");} else {Keyboard.release('e');Keyboard.release('r');Keyboard.release('q');Keyboard.release('t');Keyboard.release('y');Keyboard.release('u');Keyboard.release('i');}// Gentle decay to prevent imbalance and adjust for different resting positionsmoveX *= 0.995;moveY *= 0.995;mouseX *= 0.995;mouseY *= 0.995;delay(10);}
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.