26 November 2023

Pan's Flute - Morgan DeMunck



Pan’s Flute is a panpipe controller where the player uses their breath to control directional movement for the rhythm-based roguelike game Crypt of the Necrodancer. As the game itself is largely about acting to the beat of the music in the dungeon—whether it be for movement or attacking enemies—it made logistical sense to have a controller modeled after a musical instrument. Though I originally was intending to use an orchestral flute as my controller, I ultimately decided to
go for the panpipes as I thought they were more visually interesting and would better lend itself to the high fantasy setting of the game. I thought it would also be appropriate to name the controller Pan’s Flute to further push the high fantasy aspect by referencing the Grecian god of the wild.

By blowing into the pipes (as if playing a real set of panpipes) the player controls directional movement. Directional movement is all that’s necessary—the game only uses the 4 directional arrows to determine both movement and action. Each pipe corresponds to a directional arrow key on the keyboard (e.g. the longest pipe corresponding to the up arrow key), so the player is quite literally creating music alongside the game producing music itself, further pushing the musical theme.

Do you think there’s enough feedback to signify playing the pipes, or should there be more emphasis such as a short electronic note?



SCHEMATICS



CODE

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

/* VARIABLES */
float upValue;
float rightValue;
float leftValue;
float downValue;

int upThreshold = 30;
int rightThreshold = 75;
int leftThreshold = 60;
int downThreshold = 150;

/* PINS */
int upSensor = A0;
int rightSensor = A3;
int leftSensor = A4;
int downSensor = A6;

void setup() {
  Serial.begin(9600);
  CircuitPlayground.begin();
  Keyboard.begin();

  //PINS
  pinMode (upSensor, INPUT);
  pinMode (rightSensor, INPUT);
  pinMode (leftSensor, INPUT);
  pinMode (downSensor, INPUT);
}

void loop() {
  troubleshoot();
  moveDirection();
}

/* Troubleshooting for sound pressure testing--comment this out when not in use */

void troubleshoot() {  
  Serial.print("Up Arrow Sound Level: ");
  Serial.println(upValue);
  Serial.print("Right Arrow Sound Level: ");
  Serial.println(rightValue);
  Serial.print("Left Arrow Sound Level: ");
  Serial.println(leftValue);
  Serial.print("Down Arrow Sound Level: ");
  Serial.println(downValue);
 
  delay(180);
}

/* Controls directional input */

void moveDirection () {
  upValue = analogRead(upSensor);
  rightValue = analogRead(rightSensor);
  leftValue = analogRead(leftSensor);
  downValue = analogRead (downSensor);
 
  if (upValue >= upThreshold) {
    Keyboard.write(KEY_UP_ARROW);
    Serial.println ("Moved up!");
  }

    if (rightValue >= rightThreshold) {
    Keyboard.write(KEY_RIGHT_ARROW);
    Serial.println ("Moved right!");
  }

  if (leftValue >= leftThreshold) {
    Keyboard.write(KEY_LEFT_ARROW);
    Serial.println ("Moved left!");
  }
 
  if (downValue >= downThreshold) {
    Keyboard.write(KEY_DOWN_ARROW);
    Serial.println ("Moved down!");
  }
}


No comments:

Post a Comment

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