Last active
May 15, 2020 11:07
-
-
Save longtran2904/2f46330be5a796a5b7298eef12506cc9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Engine::Engine() { | |
time = 0; | |
} | |
void Engine::updateLoop(float deltaTime) { | |
this->deltaTime = deltaTime; | |
time += deltaTime; | |
// Button input: | |
int buttonStateOld = buttonState; | |
buttonState = digitalRead(button1Pin); | |
button1Down = buttonState == 1; | |
button1DownThisFrame = button1Down && buttonState != buttonStateOld; | |
button1UpThisFrame = buttonState == 0 && buttonStateOld == 1; | |
if (button1DownThisFrame) { | |
button1DownDuration = 0; | |
} | |
if (button1Down) { | |
button1DownDuration += deltaTime; | |
} | |
// Get analog stick input: | |
const float inputThreshold = 0.1; | |
inputX = remap(analogRead(xPin), 0, 1023, -1, 1); | |
inputY = -remap(analogRead(yPin), 0, 1023, -1, 1); | |
Serial.print("X: "); | |
Serial.print(inputX); | |
Serial.print(" Y: "); | |
Serial.print(inputY); | |
Serial.print("\n"); | |
if (abs(inputX) < inputThreshold) { | |
inputX = 0; | |
} | |
if (abs(inputY) < inputThreshold) { | |
inputY = 0; | |
} | |
} | |
void Engine::playSound(int frequency, int duration) { | |
tone(buzzerPin, frequency, duration); | |
} | |
void Engine::clearScreen() { | |
display.clearDisplay(); | |
display.display(); | |
} | |
void Engine::SetPixel(int x, int y) { | |
display.drawPixel(x, y, SSD1306_WHITE); | |
display.display(); | |
} | |
void Engine::SetPixels(int positionX, int positionY, int sizeX, int sizeY) { | |
display.fillRect(positionX, positionY, sizeX, sizeY, WHITE); | |
Serial.println("drawing"); | |
display.display(); | |
} | |
void Engine::DrawToDisplay() { | |
display.clearDisplay(); | |
display.setTextColor(WHITE); | |
display.setTextSize(10); | |
display.setCursor(32, 32); | |
display.print("HELLO WORLD"); | |
display.display(); | |
Serial.println("Done drawing"); | |
} | |
void Engine::begin() { | |
display.begin(SSD1306_SWITCHCAPVCC, 0x3D); | |
display.clearDisplay(); | |
display.display(); | |
pinMode(button1Pin, INPUT_PULLUP); | |
pinMode(button2Pin, INPUT_PULLUP); | |
pinMode(xPin, INPUT); | |
pinMode(yPin, INPUT); | |
pinMode(buzzerPin, OUTPUT); | |
Serial.println("begin"); | |
} | |
void Engine::Display() { | |
display.display(); | |
Serial.println("Display"); | |
} | |
bool Engine::GetPixel(int x, int y) { | |
return display.getPixel(x, y); | |
} | |
float Engine::remap(float value, float minOld, float maxOld, float minNew, float maxNew) { | |
return minNew + (value - minOld) / (maxOld - minOld) * (maxNew - minNew); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <Arduino.h> | |
#include <Adafruit_GFX.h> | |
#include <Adafruit_SSD1306.h> | |
class Engine { | |
private: | |
// Input pins: | |
const int button1Pin = 4; | |
const int button2Pin = 5; | |
const int xPin = 0; | |
const int yPin = 1; | |
// Audio pins: | |
const int buzzerPin = 7; | |
// Display pins: | |
const int OLED_D0 = 8; | |
const int OLED_D1 = 9; | |
const int OLED_RES = 10; | |
const int OLED_DC = 11; | |
const int OLED_CS = 12; | |
Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, OLED_D1, OLED_D0, OLED_DC, OLED_RES, OLED_CS); | |
int buttonState; | |
float remap(float, float, float, float, float); | |
public: | |
float deltaTime; | |
unsigned long time; | |
// Player input info: | |
float inputX; | |
float inputY; | |
bool button1Down; | |
bool button1UpThisFrame; | |
bool button1DownThisFrame; | |
float button1DownDuration; | |
bool button2Down; | |
bool button2UpThisFrame; | |
bool button2DownThisFrame; | |
float button2DownDuration; | |
Engine(); | |
void begin(); | |
void playSound(int frequency, int duration); | |
void updateLoop(float); | |
void clearScreen(); | |
void SetPixel(int x, int y); | |
void SetPixels(int positionX, int positionY, int sizeX, int sizeY); | |
void Display(); | |
bool GetPixel(int x, int y); | |
void DrawToDisplay(); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "Engine.h" | |
#include "SnakeGame.h" | |
#include "Game.h" | |
const bool showStartupSequence = true; | |
const int numGames = 2; | |
int activeGameIndex = 0; | |
unsigned long timeOld; | |
int x, y; // This is for testing the display | |
Engine engine; | |
SnakeGame game; // If i remove this line of code everything would work fine | |
void setup() { | |
Serial.begin(115200); | |
engine.begin(); | |
engine.clearScreen(); | |
timeOld = millis(); | |
} | |
void loop() { | |
// Calculate delta time | |
unsigned long frameStartTime = millis(); | |
unsigned long deltaTimeMillis = frameStartTime - timeOld; | |
float deltaTime = deltaTimeMillis / 1000.0; | |
timeOld = frameStartTime; | |
// Update | |
engine.updateLoop(deltaTime); | |
engine.SetPixels(x, y, 16, 16); | |
x, y++; | |
game.updateLoop(engine); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "SnakeGame.h" | |
#include "Arduino.h" | |
#include "Engine.h" | |
SnakeGame::SnakeGame() { | |
Serial.println("PLEASE WORK"); | |
snakeLength = 1; | |
timeSinceLastMove = 0; | |
x[0] = 0; | |
y[0] = 3; | |
dirX = 1; | |
dirY = 0; | |
nextDirX = dirX; | |
nextDirY = dirY; | |
timeRemainingToNextFoodSpawn = 1.5; | |
foodExists = false; | |
gameOver = false; | |
scoreDisplayAmount = -5; | |
} | |
void SnakeGame::updateLoop(Engine& engine) { | |
//Engine& engine = *ptrEngine; | |
if (gameOver) { | |
scoreDisplayAmount += engine.deltaTime * 10; | |
for (int i = 0; i < min(snakeLength, (int)scoreDisplayAmount); i++) { | |
int x = i % 16; | |
int y = i / 16; | |
engine.SetPixel(x, y); | |
} | |
return; | |
} | |
timeSinceLastMove += engine.deltaTime; | |
// Set next dir to whichever input axis is currently greater | |
// This dir is stored for the next time the snake moves | |
// (overwriting the value immediately would not allow preventing dir from being reversed) | |
if (engine.inputX != 0 || engine.inputY != 0) { | |
// Stick is further along x axis than y axis | |
if (abs(engine.inputX) > abs(engine.inputY)) { | |
int inputDirX = sign(engine.inputX); | |
// Dont allow dir to be reversed | |
if (inputDirX != -dirX) { | |
nextDirX = inputDirX; | |
nextDirY = 0; | |
} | |
} | |
// Stick is further along y axis than x axis | |
else { | |
int inputDirY = sign(engine.inputY); | |
// Dont allow dir to be reversed | |
if (inputDirY != -dirY) { | |
nextDirY = inputDirY; | |
nextDirX = 0; | |
} | |
} | |
} | |
// Move | |
if (timeSinceLastMove > timeBetweenMoves) { | |
timeSinceLastMove = timeSinceLastMove - timeBetweenMoves; | |
dirX = nextDirX; | |
dirY = nextDirY; | |
// Calculate new head position: | |
int newHeadX = x[0] + dirX; | |
int newHeadY = y[0] + dirY; | |
// Wrap around: | |
newHeadX = (newHeadX >= width) ? 0 : newHeadX; | |
newHeadX = (newHeadX < 0) ? width - 1 : newHeadX; | |
newHeadY = (newHeadY >= height) ? 0 : newHeadY; | |
newHeadY = (newHeadY < 0) ? height - 1 : newHeadY; | |
// Update snake points | |
for (int i = snakeLength - 1; i > 0; i--) { | |
x[i] = x[i - 1]; | |
y[i] = y[i - 1]; | |
// Check for self-collision | |
if (newHeadX == x[i] && newHeadY == y[i]) { | |
gameOver = true; | |
engine.playSound(200, 1000); | |
} | |
} | |
// Move head | |
x[0] = newHeadX; | |
y[0] = newHeadY; | |
// Eat food | |
if (foodExists) { | |
if (x[0] == foodX && y[0] == foodY) { | |
foodExists = false; | |
// Add point to end of snake | |
int nextPointDirX = -dirX; | |
int nextPointDirY = -dirY; | |
if (snakeLength > 1) { | |
nextPointDirX = sign(x[snakeLength - 1] - x[snakeLength - 2]); | |
nextPointDirY = sign(y[snakeLength - 1] - y[snakeLength - 2]); | |
} | |
x[snakeLength] = x[snakeLength - 1] + nextPointDirX; | |
y[snakeLength] = y[snakeLength - 1] + nextPointDirY; | |
snakeLength++; | |
// Play sound | |
if ((snakeLength - 1) % 5 == 0) { | |
engine.playSound(523, 450); | |
} | |
else { | |
engine.playSound(349, 150); | |
} | |
} | |
} | |
} | |
// Draw snake | |
for (int i = 0; i < snakeLength; i++) { | |
//engine.SetPixel((int)x[i], (int)y[i]); | |
engine.SetPixels((int)x[i], (int)y[i], snakeSize, snakeSize); | |
Serial.println("Drawing snake"); | |
} | |
// Draw food | |
if (foodExists) { | |
//engine.SetPixel(foodX, foodY); | |
engine.SetPixels(foodX, foodY, snakeSize, snakeSize); | |
} | |
else { | |
// Handle food spawning | |
timeRemainingToNextFoodSpawn -= engine.deltaTime; | |
if (timeRemainingToNextFoodSpawn <= 0) { | |
placeFood(); | |
} | |
} | |
} | |
// Place food randomly on tile not currently occupied by snake | |
void SnakeGame::placeFood() { | |
const int numTiles = width * height; | |
int randomIndex = random(0, numTiles); | |
// Create map of tiles occupied by snake | |
bool occupancyMap[numTiles] = { false }; | |
for (int i = 0; i < snakeLength; i++) { | |
int snakeIndex = y[i] * width + x[i]; | |
occupancyMap[snakeIndex] = true; | |
} | |
for (int i = 0; i < numTiles; i++) { | |
// Cant spawn food here, tile contains snake | |
if (occupancyMap[randomIndex] == true) { | |
randomIndex = (randomIndex + 1) % numTiles; | |
} | |
// Can spawn food here | |
else { | |
foodX = randomIndex % width; | |
foodY = randomIndex / width; | |
timeRemainingToNextFoodSpawn = random(foodSpawnMillisMin, foodSpawnMillisMax) / 1000.0; | |
foodExists = true; | |
return; | |
} | |
} | |
} | |
int SnakeGame::sign(float value) { | |
if (value == 0) { | |
return 0; | |
} | |
return (value < 0) ? -1 : 1; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "Game.h" | |
#include "Engine.h" | |
class SnakeGame { | |
private: | |
const int snakeSize = 4; | |
static const int width = 128 / 4; | |
static const int height = 64 / 4; | |
const float timeBetweenMoves = .2; | |
const int foodSpawnMillisMin = 400; | |
const int foodSpawnMillisMax = 2000; | |
unsigned char x[width * height]; | |
unsigned char y[width * height]; | |
int snakeLength; | |
float timeSinceLastMove; | |
int dirX; | |
int dirY; | |
int nextDirX; | |
int nextDirY; | |
bool foodExists; | |
float timeRemainingToNextFoodSpawn; | |
int foodX; | |
int foodY; | |
bool gameOver; | |
float scoreDisplayAmount; | |
void placeFood(); | |
int sign(float); | |
public: | |
SnakeGame(); | |
void updateLoop(Engine&); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment