Hello hello? Hey, you’re doing great! Most people don’t last this long!…I mean, y’know. They usually move on to other classes by now. I’m not implying that they failed, that’s not what I meant…anyways, I better not take up too much of your time, things start getting real on this blog post - at least you’d hope so, given that it’s the final one. We’ve reached the end of this semester, which means it’s time for the final controller design!
This controller is meant to mimic the layout of the office you’re located in during FNAF 1, for a more immersive experience. Unfortunately, having tiny little door buttons would be far too finesse for a game where you’ll likely be jumping any time you need to press a button. So, I chose touch sensors for the door buttons to mimic the idea of slamming a door button. Using light sensors seemed like an obvious choice, but wound up having some ironic logic: you cover the light sensor in order to turn on the lights in-game. Maybe it’s something like turning out the overhead lights to find something glowing in your room. There are also 4 total LEDs (two on each side) used to signal the state of the doors & lights in-game: one RGB LED that changes between red and green depending on the door’s status of open or closed, and one white LED that lights up/flickers when the lights are active.
//left half, CPE & pot#include <Mouse.h>#include <Adafruit_CircuitPlayground.h>#include <Adafruit_Circuit_Playground.h>// inputsint touchSen = 6;int lightSen = A2;int pot = A7;// outputsint wLED = 10;int rLED = A6;int gLED = A5;// variables for runningbool doorShut;bool lightOn;int potVal;void setup() {Serial.begin(9600);Mouse.begin();Mouse.move(0, 0, 0); // I think??? this moves the mouse to the bottom left corner of the screenpinMode(touchSen, INPUT);pinMode(wLED, OUTPUT);doorShut = false;lightOn = false;analogWrite(rLED, 255);delay(100);}void loop() {if(digitalRead(touchSen)) {Mouse.move(30, 500, 0); // I'll be honest I'm estimating values here bc my CPE brokeMouse.click();delay(20);if(doorShut == false) {analogWrite(gLED, 255);analogWrite(rLED, 0);doorShut = true;delay(100);} else if(doorShut == true) {analogWrite(rLED, 255);analogWrite(gLED, 0);doorShut = false;delay(100);}}if(lightOn == false) {Mouse.move(40, 550, 0);Mouse.click();delay(20);if(map(analogRead(lightSen), 0, 1023, 0, 10) < 4) {digitalWrite(wLED, HIGH);lightOn = true;delay(100);}}else if(lightOn == true) {Mouse.move(40, 550, 0);Mouse.click();delay(20);if(map(analogRead(lightSen), 0, 1023, 0, 10) >= 4) {digitalWrite(wLED, LOW);lightOn = false;delay(100);}}potVal = map(analogRead(pot), 0. 1023, 0, 11); // cycle through 11 cams, plus first option for shutting themswitch(potVal) {case 1:// move mouse & click for cam 1adelay(100);break;case 2:// move mouse & click for cam 1bdelay(100);break;case 3:// move mouse & click for cam 1cdelay(100);break;case 4:// move mouse & click for cam 2adelay(100);break;case 5:// move mouse & click for cam 2bdelay(100);break;case 6:// move mouse & click for cam 3delay(100);break;case 7:// move mouse & click for cam 4adelay(100);break;case 8:// move mouse & click for cam 4bdelay(100);break;case 9:// move mouse & click for cam 5delay(100);break;case 10:// move mouse & click for cam 6delay(100);break;case 11:// move mouse & click for cam 7delay(100);break;default:// move mouse to shut camerasdelay(100);break;}}
//right half, CPB & toggle#include <Mouse.h>#include <Adafruit_TinyUSB.h>#include <Adafruit_CircuitPlayground.h>#include <Adafruit_Circuit_Playground.h>// inputsint touchSen = 1;int lightSen = A3;int tog = 12;// outputsint wLED = 3;int rLED = A1;int gLED = A2;// variables for runningbool doorShut;bool lightOn;bool togOn;int togVal;void setup() {Serial.begin(9600);Mouse.begin();Mouse.move(0, 0, 0); // I'm assuming this moves it to bottom left cornerdelay(20);pinMode(touchSen, INPUT);pinMode(wLED, OUTPUT);pinMode(togVal, INPUT_PULLUP);doorShut = false;lightOn = false;togOn = false;analogWrite(rLED, 255);delay(100);}void loop() {if(digitalRead(touchSen)) {Mouse.move(1000, 500, 0); // estimating values againMouse.click();if(doorShut == false) {analogWrite(gLED, 255);analogWrite(rLED, 0);doorShut = true;delay(100);} else if(doorShut == true) {analogWrite(rLED, 255);analogWrite(gLED, 0);doorShut = false;delay(100);}}if(lightOn == false) {Mouse.move(990, 550, 0); // estimating values againMouse.click();if(map(analogRead(lightSen), 0, 1023, 0, 10) < 4) {digitalWrite(wLED, HIGH);lightOn = true;delay(100);}}else if(lightOn == true) {Mouse.move(990, 550, 0); // estimating values againMouse.click();if(map(analogRead(lightSen), 0, 1023, 0, 10) >= 4) {digitalWrite(wLED, LOW);lightOn = false;delay(100);}}togVal = digitalRead(tog); // I'm realizing now that I mis-wired this; probably needed two different values sent to the CPB to designate directionMouse.move(0, 0, 0); // reset mouse position}
The potentiometer and toggle switch in the stage floor are parallels, yet opposites. The toggle switch allows for camera movement; since the game is controlled with the mouse, this is the only way you’re able to move the game camera without pressing buttons you don’t want to. The potentiometer is how you control the cameras; clamped into 10 sections, with the first one meaning that the cameras are closed, and the subsequent 9 opening the 9 security cameras you see in the game. It’ll lead to a lot of flashing cameras, but luckily with FNAF 1 it’s not seeing the big picture that’s important, it’s tricking the animatronics - specifically Foxy - into thinking you’re looking at him.
(Video)
For my design question: what kinds of props should I add to the miniature office?
Thanks for sticking with this project for this long. Catch you on the flip side!