Assignment:
This week we were given the option of creating a game with the Arduino and I decided to continue with my favorite Processing game thus far, my F1 simulator. I wanted to make a controller that would be integrated into the game.
Game Controller:
There are three main inputs in a car (a simplified automatic one anyways), steering, gas, and acceleration. My game already had these inputs but steering was in essence binary (full left, neutral, full right). I decided that analog input could make for much more fun steering and in addition to gas/brake buttons I could make a F1 car controller.
For the steering I used the potentiometer. I had to rework all my code for how the car was steered as it was no longer left or right, but rather any value from full left to full right and anywhere in-between. I ended up checking which way the potentiometer was facing and mapping the annual acceleration of the car off of this.
I also added a brake and gas button. These were super easy to implement as they behaved exactly the same as if I was pressing the up or down arrow in the keyboard controls so all I had to was change to binary values if they were on or off.
Finally I wanted something a bit extra than just inputs, also outputs that could make the player feel more like they were in a car. I decided to add two LEDs, a green one that would light up when pressing the gas, and a red one that would light up when braking, or flash when the car crashed like hazard lights. This allowed me to try the no delay blinking code as well.
Circuit
Code
Arduino Code
const int brakeLed = 5; const int forwardLed = 4; const int forwardButton = 2; const int brakeButton = 3; const int sensorPin = A0; int forward = 0; int brake = 0; int crash = 0; long timer = 0; int timerLength = 500; bool onOff = false; void setup() { Serial.begin(9600); Serial.println("0,0"); pinMode(brakeLed, OUTPUT); pinMode(forwardLed, OUTPUT); pinMode(forwardButton, INPUT); pinMode(brakeButton, INPUT); } void loop() { while (Serial.available()) { forward = Serial.parseInt(); brake = Serial.parseInt(); crash = Serial.parseInt(); if (Serial.read() == '\n') { if (crash) { if (millis() > timer) { onOff = !onOff; digitalWrite(brakeLed, onOff); digitalWrite(forwardLed, LOW); timer = millis() + timerLength; } } else{ digitalWrite(forwardLed, forward); digitalWrite(brakeLed, brake); } int forwardToggle = digitalRead(forwardButton); delay(1); int brakeToggle = digitalRead(brakeButton); delay(1); int steeringInput = analogRead(sensorPin); delay(1); Serial.print(forwardToggle); Serial.print(','); Serial.print(brakeToggle); Serial.print(','); Serial.println(steeringInput); } } }
Processing Code
import processing.sound.*; //======= Global variables ======== int gameMode = 0; //0 is main menu, 1 select your car, 2 running game, 3 crash, 4 controls menu, 5 credits Team teams[] = new Team[10]; int teamSelector = 0; //Which team from array is selected int[][] teamDict = {{7, 0, 7, 0, 0}, {8, 1, 8, 0, 1}, {5, 2, 5, 0, 2}, {4, 3, 4, 0, 3}, {0, 4, 0, 0, 4}, {2, 5, 2, 1, 0}, {1, 6, 1, 1, 1}, {6, 7, 6, 1, 2}, {9, 8, 9, 1, 3}, {3, 9, 3, 1, 4}}; //Dictonary containing index of car sprite, associated team image sprite index, team name index, menu row, menu col //====== Team Selection Menu Variables PImage teamMenuImg; //====== Trak Menu Variables // PImage track[][] = new PImage[10][10]; //For tile system //float tileWidth = 2560; //For tile system PImage map; float trackScale = 1; //What percent of original size should track be drawn //====== Main Game Variables float rotation = PI; //Current angle float speed = 0; //Current speed float maxSpeed = 500; //Max speed on the track float sandMaxSpeed = 20; //Max speed off the track float posX = -4886.6123; //0,0 is top left of track , values increase negative as they are reversed float posY = -1254.3951; float acceleration = 5; //How fast the car speeds up on track float sandAcceleration = 1; //How fast the car speeds up in sand float brakeDeacceleration = 10; //How quick the car stops when braking on track float coastDeacceleration = 2; //How quick the car stops when no power float sandDeacceleration = 15; //How quick the car stops in sand float angularAcceleration = PI/20; //How fast the car turns boolean reverse = false; float carScale = 0.3; //What percent of original size should car be drawn //Keyboard inputs boolean forward = false; boolean brake = false; boolean left = false; boolean right = false; //Sound SoundFile accSound; float accSoundAmp = 0; float soundRate = 0.5; //Timing int passedTime; //How long has passed since saved time mark int savedTime; //Savea time to start timer boolean activeTimer = false; //Set to false, becomes active when crossing start line or false if reversed over int bestTime = -1; //Menu files PImage controls; PImage credits; //Main menu variables int numButtons = 3; int activeButton = 0; // 0 for start, 1 for controls, 2 for credits int buttonWidth = 200; int buttonHeight = 100; int buttonSpacing = 50; int buttonYOffset = 100; String buttonContent[] = {"Start Game","Controls","Credits"}; float buttonX; float buttonY; //Arduino game control variables import processing.serial.*; Serial myPort; boolean crash = false; void setup() { fullScreen(); //Set up the team array //======================================================================================= PImage[] carSprites; PImage[] teamSprites; String[] nameArray = {"McLaren F1 Team", "Scuderia AlphaTauri Honda", "Mercedes-AMG Petronas F1 Team", "ROKiT Williams Racing", "Haas F1 Team", "BWT Racing Point F1 Team", "Scuderia Ferrari", "Alfa Romeo Racing ORLEN", "Aston Martin Red Bull Racing", "Renault F1 Team" }; //Alfa Romeo, Red Bull, Racing Point, Haas, Mclaren, Mercedes, AlphaTauri, Ferrari, Renault, Williams //Set sprite sheets carSprites = getCarSpriteSheet("SpriteSheetCars.png"); //Load the car sprite sheet into sprites teamSprites = getTeamSpriteSheet("Teams.png"); //Load the team sprite sheet into sprites //Set teams array with appropiate info for (int i = 0; i < 10; i++) { Team newTeam = new Team(); newTeam.setName(nameArray[teamDict[i][2]]); //Set team name newTeam.setCarImg(carSprites[teamDict[i][0]]); //Set team img newTeam.setTeamImg(teamSprites[teamDict[i][1]]); //Set team car img teams[i] = newTeam; } //======================================================================================= //Load menu imgs teamMenuImg = loadImage("Teams.png"); controls = loadImage("Controls.png"); credits = loadImage("Credits.png"); //======================================================================================= //Load map map = loadImage("Track.png"); //======================================================================================= //Load sound accSound = new SoundFile(this, "acc.wav"); accSound.loop(); accSound.amp(accSoundAmp); accSound.rate(soundRate); //Start lap timer savedTime = millis(); //Start serial communication with controller String portname=Serial.list()[1]; myPort = new Serial(this,portname,9600); myPort.clear(); myPort.bufferUntil('\n'); } void draw() { //Main Gamemode Control selector switch(gameMode) { case 0: mainMenu(); break; case 1: teamMenu(); break; case 2: runGame(); break; case 3: crash(); break; case 4: controls(); break; case 5: credits(); break; } } //When all game cariables need to be reset to start status void resetVariables(){ accSound.amp(0); forward = brake = right = left = false; activeTimer = false; speed = 0; gameMode = 0; posX = -4886.6123; //0,0 is top left of track , values increase negative as they are reversed posY = -1254.3951; rotation = PI; crash = false; } void serialEvent(Serial myPort){ String s=myPort.readStringUntil('\n'); s=trim(s); if (s!=null){ println(s); int values[]=int(split(s,',')); if (values.length==3){ if(values[0] == 1 && values[1] == 1){ forward = false; brake = false; } else if (values[0] == 1){ forward = true; } else if (values[1] == 1){ brake = true; } else if (values[0] == 0 && values[1] == 0){ forward = false; brake = false; } int steering = values[2]; //Turn left if(steering > 1023/2){ left = true; right = false; angularAcceleration = map(values[2],1023/2,1023,0, PI/20); } else if(steering < 1023/2){ left = false; right = true; angularAcceleration = map(values[2],1023/2,0,0, PI/20); } } } println(crash); myPort.write(int(forward)+","+int(brake)+","+int(crash)+"\n"); }
Results