Spike Game (Portable Game Console)
A small and portable gaming console!
Components and supplies
ARDUINO UNO R3
10 jumper wires 150mm male
Esp32 C3 Mini
Push Button
SSD1306 OLED Display
Tools and machines
3D printer (making the case)
Apps and platforms
Arduino IDE
Project description
Code
Spike Game (Arduino UNO R3)
cpp
The code for the game if you use a Arduino UNO R3
1#include <Wire.h> 2#include <Adafruit_GFX.h> 3#include <Adafruit_SSD1306.h> 4#include <EEPROM.h> 5 6#define BUTTON_PIN 3 7 8bool rectCollision(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2) { 9 return !(x1 + w1 < x2 || x1 > x2 + w2 || y1 + h1 < y2 || y1 > y2 + h2); 10} 11 12bool isJumping = false; 13bool gameOver = false; 14int PlayerY = 40; 15int velocity = 0; 16const int gravity = 2; 17const int groundY = 40; 18float PillarX1 = 128.0; 19float PillarX2 = 180.0; 20float gameSpeed = 3.0; 21unsigned long lastSpeedIncrease = 0; 22unsigned long lastFrame = 0; 23unsigned long score = 0; 24unsigned long highScore = 0; 25 26bool buttonPressed = false; 27 28// OLED-display (128x64) 29Adafruit_SSD1306 display(128, 64, &Wire, -1); 30 31void setup() { 32 Wire.begin(); 33 pinMode(BUTTON_PIN, INPUT_PULLUP); 34 35 if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { 36 while (1); 37 } 38 39 display.clearDisplay(); 40 display.display(); 41 randomSeed(analogRead(0)); 42 43 EEPROM.get(0, highScore); 44 if (highScore > 99999) highScore = 0; 45 46 lastSpeedIncrease = millis(); 47 lastFrame = millis(); 48} 49 50void loop() { 51 unsigned long currentTime = millis(); 52 if (currentTime - lastFrame < 50) return; 53 lastFrame = currentTime; 54 55 int buttonState = digitalRead(BUTTON_PIN); 56 57 if (gameOver) { 58 if (buttonState == HIGH && !buttonPressed) { 59 buttonPressed = true; 60 } 61 if (buttonState == LOW && buttonPressed) { 62 buttonPressed = false; 63 SweepEffect(10); 64 resetGame(); 65 } 66 return; 67 } 68 69 // Jump 70 if (buttonState == LOW && !buttonPressed && PlayerY == groundY) { 71 buttonPressed = true; 72 isJumping = true; 73 velocity = -13; 74 } 75 if (buttonState == HIGH) { 76 buttonPressed = false; 77 } 78 79 // Physics 80 if (isJumping) { 81 PlayerY += velocity; 82 velocity += gravity; 83 if (PlayerY >= groundY) { 84 PlayerY = groundY; 85 isJumping = false; 86 } 87 } 88 89 // Moving spikes 90 PillarX1 -= gameSpeed; 91 PillarX2 -= gameSpeed; 92 93 if (PillarX1 < -10) { 94 PillarX1 = 128 + random(10, 40); 95 } 96 if (PillarX2 < -10) { 97 PillarX2 = 128 + random(10, 40); 98 } 99 100 101 if (currentTime - lastSpeedIncrease > 2000) { 102 gameSpeed += 0.2; 103 lastSpeedIncrease = currentTime; 104 } 105 106 // Score 107 score++; 108 109 // Display 110 display.clearDisplay(); 111 display.fillRoundRect(10, PlayerY, 8, 14, 4, SSD1306_WHITE); 112 display.fillTriangle((int)PillarX1, groundY + 17, (int)PillarX1 + 5, groundY, (int)PillarX1 + 10, groundY + 17, SSD1306_WHITE); 113 display.fillTriangle((int)PillarX2, groundY + 17, (int)PillarX2 + 5, groundY, (int)PillarX2 + 10, groundY + 17, SSD1306_WHITE); 114 display.drawLine(0, 58, 128, 58, SSD1306_WHITE); 115 display.setTextSize(1); 116 display.setTextColor(SSD1306_WHITE); 117 display.setCursor(0, 0); 118 display.print("Score: "); 119 display.print(score / 10); 120 display.display(); 121 122 // COLLISION DETECTION 123 bool Pillar1 = rectCollision(10, PlayerY, 8, 14, (int)PillarX1, groundY, 10, 15); 124 bool Pillar2 = rectCollision(10, PlayerY, 8, 14, (int)PillarX2, groundY, 10, 15); 125 126 if (Pillar1 || Pillar2) { 127 gameOver = true; 128 129 // High score save 130 if (score > highScore) { 131 highScore = score; 132 EEPROM.put(0, highScore); 133 } 134 135 // Game Over display 136 SweepEffect(10); 137 display.clearDisplay(); 138 display.setTextSize(1); 139 display.setCursor(43, 0); 140 display.print("Score:"); 141 display.print(score / 10); 142 display.setCursor(26, 40); 143 display.print("High Score:"); 144 display.print(highScore / 10); 145 display.setTextSize(2); 146 display.setCursor(12, 15); 147 display.print("Game Over"); 148 display.setTextSize(1); 149 display.setCursor(15, 55); 150 display.print("Press to restart"); 151 display.display(); 152 } 153} 154 155void resetGame() { 156 isJumping = false; 157 PlayerY = groundY; 158 velocity = 0; 159 PillarX1 = 128.0; 160 PillarX2 = 180.0; 161 gameSpeed = 3.0; 162 score = 0; 163 gameOver = false; 164 lastSpeedIncrease = millis(); 165 lastFrame = millis(); 166 display.clearDisplay(); 167 display.display(); 168} 169 170void SweepEffect(int speed) { 171 172 173 for (int i = 0; i < display.width(); i += speed) { 174 display.fillRect(i, 0, speed, display.height(), WHITE); 175 display.display(); 176 } 177 178 179 for (int i = 0; i < display.width(); i += speed) { 180 display.fillRect(i, 0, speed, display.height(), BLACK); 181 display.display(); 182 } 183}
Spike Game (Esp32 C3 MINI)
cpp
The code for the game if you use a Esp32 C3 MINI
1#include <Wire.h> 2#include <Adafruit_GFX.h> 3#include <Adafruit_SSD1306.h> 4#include <EEPROM.h> 5 6#define BUTTON_PIN 3 7 8bool rectCollision(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2) { 9 return !(x1 + w1 < x2 || x1 > x2 + w2 || y1 + h1 < y2 || y1 > y2 + h2); 10} 11 12bool isJumping = false; 13bool gameOver = false; 14int PlayerY = 40; 15int velocity = 0; 16const int gravity = 2; 17const int groundY = 40; 18 19 20float PillarX1 = 128.0; 21float Pillarx2 = 180.0; 22float gameSpeed = 3.0; 23 24unsigned long lastSpeedIncrease = 0; 25unsigned long lastFrame = 0; 26unsigned long score = 0; 27unsigned long highScore = 0; 28 29bool buttonPressed = false; 30 31// OLED-display (128x64) 32Adafruit_SSD1306 display(128, 64, &Wire, -1); 33 34void setup() { 35 Wire.begin(8, 9); 36 37 pinMode(BUTTON_PIN, INPUT_PULLUP); 38 39 if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { 40 while (1); 41 } 42 43 display.clearDisplay(); 44 display.display(); 45 randomSeed(analogRead(0)); 46 47 EEPROM.begin(8); 48 EEPROM.get(0, highScore); 49 if (highScore > 99999) highScore = 0; 50} 51 52void loop() { 53 unsigned long currentTime = millis(); 54 if (currentTime - lastFrame < 50) return; 55 lastFrame = currentTime; 56 57 int buttonState = digitalRead(BUTTON_PIN); 58 59 // Game over 60 if (gameOver) { 61 if (buttonState == HIGH && !buttonPressed) { 62 buttonPressed = true; 63 } 64 65 if (buttonState == LOW && buttonPressed) { 66 buttonPressed = false; 67 SweepEffect(10); 68 resetGame(); 69 } 70 return; 71 } 72 73 // Jump 74 if (buttonState == LOW && !buttonPressed && PlayerY == groundY) { 75 buttonPressed = true; 76 isJumping = true; 77 velocity = -13; 78 } 79 if (buttonState == HIGH) { 80 buttonPressed = false; 81 } 82 83 // Physics 84 if (isJumping) { 85 PlayerY += velocity; 86 velocity += gravity; 87 if (PlayerY >= groundY) { 88 PlayerY = groundY; 89 isJumping = false; 90 } 91 } 92 93 94 PillarX1 -= gameSpeed; 95 Pillarx2 -= gameSpeed; 96 97 if ( PillarX1 < -10) { 98 PillarX1 = 128 + random(15, 60); 99 } 100 101 if ( Pillarx2 < -10) { 102 Pillarx2 = 128 + random(15, 60); 103 } 104 105 106 if (currentTime - lastSpeedIncrease > 2000) { 107 gameSpeed += 0.2; 108 lastSpeedIncrease = currentTime; 109 } 110 111 // Score 112 score++; 113 114 // Display 115 display.clearDisplay(); 116 display.fillRoundRect(10, PlayerY, 8, 14, 4, SSD1306_WHITE); 117 display.fillTriangle((int) PillarX1, groundY + 17, (int) PillarX1 + 5, groundY, (int) PillarX1 + 10, groundY + 17, SSD1306_WHITE); 118 display.fillTriangle((int) Pillarx2, groundY + 17, (int) Pillarx2 + 5, groundY, (int) Pillarx2 + 10, groundY + 17, SSD1306_WHITE); 119 display.drawLine(0, 58, 128, 58, SSD1306_WHITE); 120 display.setTextSize(1); 121 display.setTextColor(SSD1306_WHITE); 122 display.setCursor(0, 0); 123 display.print("Score: "); 124 display.print(score / 10); 125 display.display(); 126 127 // COLLISION DETECTION 128 bool Pillar1 = rectCollision(10, PlayerY, 8, 14, (int) PillarX1, groundY, 10, 15); 129 bool Pillar2 = rectCollision(10, PlayerY, 8, 14, (int) Pillarx2, groundY, 10, 15); 130 131 if (Pillar1 || Pillar2) { 132 gameOver = true; 133 134 // High score Save 135 if (score > highScore) { 136 highScore = score; 137 EEPROM.put(0, highScore); 138 EEPROM.commit(); 139 } 140 141 //Game Over 142 SweepEffect(10); 143 display.clearDisplay(); 144 display.setTextSize(1); 145 display.setCursor(43, 0); 146 display.print("Score:"); 147 display.print(score / 10); 148 display.setCursor(26, 40); 149 display.print("High Score:"); 150 display.print(highScore / 10); 151 display.setTextSize(2); 152 display.setCursor(12, 15); 153 display.print("Game Over"); 154 display.setTextSize(1); 155 display.setCursor(15, 55); 156 display.print("Press to restart"); 157 display.display(); 158 } 159} 160 161void resetGame() { 162 isJumping = false; 163 PlayerY = groundY; 164 velocity = 0; 165 PillarX1 = 128.0; 166 Pillarx2 = 180.0; 167 gameSpeed = 3.0; 168 score = 0; 169 gameOver = false; 170 lastSpeedIncrease = millis(); 171 lastFrame = millis(); 172 display.clearDisplay(); 173 display.display(); 174} 175 176void SweepEffect(int speed) { 177 178 179 for (int i = 0; i < display.width(); i += speed) { 180 display.fillRect(i, 0, speed, display.height(), WHITE); 181 display.display(); 182 } 183 184 185 for (int i = 0; i < display.width(); i += speed) { 186 display.fillRect(i, 0, speed, display.height(), BLACK); 187 display.display(); 188 } 189}
Downloadable files
Spike Game Arduino UNO R3
Spike Game Arduino UNO R3
Spike Game Arduino UNO.png

Spike Game Esp32 C3 Mini
Spike Game Esp32 C3 Mini
Spike Game Esp32 C3 Mini.png

Case pic 1
Case pic 1
Skärmbild 2025-08-12 191900.png

Case pic 2
Case pic 2
Skärmbild 2025-08-12 191831.png

The Case STL file
The case to hold everything (Not necessary)
Spike_Game_Case.stl
Game Footage 1
Game Footage 1
IMG_5902.jpg

Game Footage 2
Game Footage 2
IMG_5900.jpg

Game Footage 3
Game Footage 3
IMG_5897.jpg

Comments
Only logged in users can leave comments