Skip to content

Instantly share code, notes, and snippets.

@longtran2904
Last active May 15, 2020 11:07
Show Gist options
  • Save longtran2904/2f46330be5a796a5b7298eef12506cc9 to your computer and use it in GitHub Desktop.
Save longtran2904/2f46330be5a796a5b7298eef12506cc9 to your computer and use it in GitHub Desktop.
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);
}
#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();
};
#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);
}
#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;
}
#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