18 April 2022

David Trefry, Final Controller: Pinball Machine for Demon's Tilt

Game Controller: Pinball Controller for Demon's Tilt

My game controller is for a digital pinball game called Demon's Tilt. My controller's conceptual model is that of a pinball machine. It is meant to bring the arcade's analog appeal to this digital game.

This controller's enclosure has a sloping face and display monitor to display art from the game. Further, the input methods on the controller are placed where they would be on a pinball machine. The input methods of this controller are meant directly reflect the outputs in Demon's Tilt. 

The first input is a plunger on the controller;s front. There is a protruding shaft that must be pulled and released in order to launch the ball in game. This is an unconventional switch. When the plunger is pulled back, a circuit is broken and the controller outputs the "space" key. When the plunger is released, a spring pushes it back into place and completes the circuit. This directly mirrors the action of pulling back the plunger in game and launching the ball.

The second and third inputs both control the flippers in game. These are unconventional switches that do not mirror the buttons on an actual pinball machine, but instead, resemble pulling on the flippers themselves to strike the ball on the other end. Users pull this controller's levers towards themselves to activate the levers in game. When these levers are pulled back, their other ends complete circuits which output the "b" and "c" keys. When they are released, springs push them back, breaking the circuit.

Lastly, this controller uses the accelerometer on an internal CPB for the nudge inputs in game. When the user tilts the controller, it activates the "wasd" keys which nudges the ball in the four cardinal directions. This input directly mirrors how users would tilt a pinball machine, mirroring the in game output.

There are only two levers and a plunger sticking out of the enclosure which can be moved, which is a key constraint for the user. With knowledge of an actual pinball machine and its signifiers, the user is meant to presume the purpose of these protruding input options and what they signify; this includes how tilting a pinball machine is the literal way to nudge the ball. The user is intended to infer that they can tilt the controller in order to do the associated action in game.

For Peers:

How better might this controller convey its conceptual model and are its affordances clear? 

Schematic:

 



Video:



Code:

#include "Adafruit_TinyUSB.h"
#include <Adafruit_CircuitPlayground.h>
#include <Adafruit_Circuit_Playground.h>

//HID report descriptor using TinyUSB's template
//Single Report (no ID) descriptor
uint8_t const desc_hid_report[] =
{
  TUD_HID_REPORT_DESC_KEYBOARD()
};

//USB HID object. For ESP32 these values cannot be changed after this declaration
//desc report, desc len, protocol, interval, use out endpoint
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_KEYBOARD, 2, false);
//https://github.com/hathach/tinyusb/blob/master/src/class/hid/hid.h

//Variables
const int debounce = 100;
const int thresh = 500;

int rightFlipperPin = 6; //A1
int leftFlipperPin = 0; //A6
int plungerPin = 1; //A7


void setup() {
  // Standard setup
  Serial.begin(9600);
  CircuitPlayground.begin();
  pinMode(CPLAY_LEFTBUTTON, INPUT_PULLDOWN); //button A
  usb_hid.begin();

  //declaring pins
  pinMode(rightFlipperPin, INPUT_PULLDOWN);
  pinMode(leftFlipperPin, INPUT_PULLDOWN);
  pinMode(plungerPin, INPUT_PULLDOWN);
}

void loop() {
  //setting up variables for keyboard outputs through TinyUSB library
  uint8_t const report_id = 0; //unsigned 8bit (1 byte) int
  uint8_t const modifier = 0; //used by libraries to save space
  uint8_t keycode[6] = { 0 }; //normal int is 16 bit (4 byte)

  //Mapping accelerometer inputs to a discrete range
  float accelX = CircuitPlayground.motionX();
  int xMap = map(accelX, -10, 10, -1, 2);
  float accelY = CircuitPlayground.motionY();
  int yMap = map(accelY, -10, 10, -1, 2);

  //if the controller is titled left, the key "A" is output
    if(xMap > 0 && abs(accelX) > abs(accelY)){
      keycode[0] = 0x04; //HEX key A
      usb_hid.keyboardReport(report_id, modifier, keycode);
      delay(debounce);
      usb_hid.keyboardRelease(0);
    }
  //if the controller is titled right, the key "D" is output
    if(xMap < 0 && abs(accelX) > abs(accelY)){
      keycode[0] = 0x07; //HEX key D
      usb_hid.keyboardReport(report_id, modifier, keycode);
      delay(debounce);
      usb_hid.keyboardRelease(0);
    }
  //if the controller is titled back, the key "S" is output
    if(yMap > 0 && abs(accelY) > abs(accelX)){
      keycode[0] = 0x16; //HEX key S
      usb_hid.keyboardReport(report_id, modifier, keycode);
      delay(debounce);
      usb_hid.keyboardRelease(0);
    }
  //if the controller is titled forward, the key "W" is output
    if(yMap < 0 && abs(accelY) > abs(accelX)){
      keycode[0] = 0x1A; //HEX key W
      usb_hid.keyboardReport(report_id, modifier, keycode);
      delay(debounce);
      usb_hid.keyboardRelease(0);
    }

  //While the right flipper unconventional switch is closed, output "b"
    if(digitalRead(rightFlipperPin)){
      keycode[0] = 0x05; //HEX key right shift, b
      usb_hid.keyboardReport(report_id, modifier, keycode);
      delay(debounce);
    }
  //While the left flipper unconventional switch is closed, output "c"
    if(digitalRead(leftFlipperPin)){
      keycode[0] = 0x06; //HEX key left shift c
      usb_hid.keyboardReport(report_id, modifier, keycode);
      delay(debounce);
     }
  //While the plunger unconventional switch is open, output "space" key
    if(!digitalRead(plungerPin)){
      keycode[0] = 0x2C; //HEX key space
      usb_hid.keyboardReport(report_id, modifier, keycode);
      delay(debounce);
     }
  //when each loop completes, keyboard inputs are released
    usb_hid.keyboardRelease(0);
}

No comments:

Post a Comment

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