Industrial manufacturing
Industrial Internet of Things | Industrial materials | Equipment Maintenance and Repair | Industrial programming |
home  MfgRobots >> Industrial manufacturing >  >> Manufacturing Technology >> Manufacturing process

ATtiny85 Mini Arcade: Snake – Build a Handheld OLED Game Console

Components and supplies

ATtiny85 Mini Arcade: Snake – Build a Handheld OLED Game Console
Microchip Technology ATtiny85
×1
ATtiny85 Mini Arcade: Snake – Build a Handheld OLED Game Console
Graphic OLED, 128 x 64
×1
ATtiny85 Mini Arcade: Snake – Build a Handheld OLED Game Console
SparkFun microB USB Breakout
×1
ATtiny85 Mini Arcade: Snake – Build a Handheld OLED Game Console
Arduino Nano R3
×1

Necessary tools and machines

ATtiny85 Mini Arcade: Snake – Build a Handheld OLED Game Console
Soldering iron (generic)
ATtiny85 Mini Arcade: Snake – Build a Handheld OLED Game Console
3D Printer (generic)

Apps and online services

ATtiny85 Mini Arcade: Snake – Build a Handheld OLED Game Console
Autodesk Fusion 360
ATtiny85 Mini Arcade: Snake – Build a Handheld OLED Game Console
Arduino IDE

About this project

Inspiration and Past Project

In December of 2017, I created a Handheld Arduino Pong Console that used an Arduino Nano and OLED screen, along with two buttons.

ATtiny85 Mini Arcade: Snake – Build a Handheld OLED Game Console

This was fine at the time, but the console was a bit too large and cumbersome. Recently, however, I have been trying to recreate some of my past projects. This time, I wanted to make a very tiny console that people can play snake on.

ATtiny85 Mini Arcade: Snake – Build a Handheld OLED Game Console

The Chosen Components

To make the console small, I couldn’t use any Arduino dev board, which is why I went with an ATtiny85.

ATtiny85 Mini Arcade: Snake – Build a Handheld OLED Game Console

It features enough I/O to run the game, including two ADC pins and, I2C port, and a GPIO pin. I opted to use a simple 2-axis joystick/switch module, as it is easy to interface with and only needs 3 pins for signaling.

ATtiny85 Mini Arcade: Snake – Build a Handheld OLED Game Console

Finally, it was time to decide which display was needed. Since DFRobot’s 128 x 64 OLED screen has a small size but plenty of resolution, I went with it.

ATtiny85 Mini Arcade: Snake – Build a Handheld OLED Game Console

Soldering a System

To begin, I attached an ATtiny85 to a SOP-8 to DIP-8 breakout PCB and soldered it to a small piece of perf-board. Next, I soldered on two headers- one for programming and the other for the screen. After doing that, I connected the analog joystick’s pins to the perf-board and wired it accordingly. For the final step, I wired a micro USB breakout board to the rest of the system for power.

ATtiny85 Mini Arcade: Snake – Build a Handheld OLED Game Console
ATtiny85 Mini Arcade: Snake – Build a Handheld OLED Game Console

Designing an Enclosure

The enclosure was designed in Fusion 360. I began by creating and laying out the components I used in the actual build, then I created an enclosure around them.

ATtiny85 Mini Arcade: Snake – Build a Handheld OLED Game Console
ATtiny85 Mini Arcade: Snake – Build a Handheld OLED Game Console

I wanted to mimic an arcade box from the 80’s, but still maintain a very small size. Below are some renders of the enclosure:

ATtiny85 Mini Arcade: Snake – Build a Handheld OLED Game Console
ATtiny85 Mini Arcade: Snake – Build a Handheld OLED Game Console

Programming the Game

Snake is a fairly easy game to program. I set a maximum snake length of 30 to save on RAM, meaning that once the snake has eaten 29 pixels, the player wins. To keep track of the segments of the snake, I created a 2-dimensional array that stores ordered pairs for each segment.

ATtiny85 Mini Arcade: Snake – Build a Handheld OLED Game Console

Whenever the head moves to a new location, its previous positions get cascaded downwards. Every time a segment is consumed, a new one is spawned at a random point. Collision checking is done by iterating through the coordinates of each segment and seeing if the head’s coordinates are the same. Additionally, hitting the snake along any of the walls will cause the player to lose as well.

ATtiny85 Mini Arcade: Snake – Build a Handheld OLED Game Console

Playing Snake

I started by powering on the console and waiting for the screen to load in the food and first segment of the snake. Then I simply piloted the snake by moving the joystick in the correct direction while watching it eat the food. This game is fun to play and is a great boredom killer in a tiny package.

ATtiny85 Mini Arcade: Snake – Build a Handheld OLED Game Console

Code

  • ATTiny85 Code
ATTiny85 CodeC/C++
Make sure to install U8g2lib first
//#include <TinyWireM.h>
#include <U8g2lib.h>

U8G2_SSD1306_128X64_NONAME_1_SW_I2C u8g(U8G2_R0,/* clock=/ 2, / data=/ 0, / reset=*/ U8X8_PIN_NONE);

#define MAX_LENGTH 30 //30 segments max

#define X 0
#define Y 1

#define JOYSTICK_X 2
#define JOYSTICK_Y 3

#define DIR_THRESH 300 //Values must be either 0-300 or 723-1023 to count

uint8_t segmentPositions[MAX_LENGTH][2];

uint8_t headPosition[2] = {63, 31}; //Place snake in beginning to start
uint8_t foodPosition[2]; //Where the food is located
uint8_t tempPosition0[2]; //Store position of previous segment to pass on to next
uint8_t tempPosition1[2]; //Store position of previous segment to pass on to next

int segmentLength = 1;

void gameUpdate();

enum DIRECTIONS {
  RIGHT,
  DOWN,
  LEFT,
  UP
} currentDirection;

void setup() {
  //TinyWireM.begin();
  u8g.begin();
  u8g.setPowerSave(0);
  pinMode(JOYSTICK_X, INPUT);
  pinMode(JOYSTICK_Y, INPUT);
  randomSeed(analogRead(0));
  beginGame();
}

void loop() {
  u8g.firstPage();
  do {
    gameUpdate();
    u8g.setColorIndex(1);
  }
  while(u8g.nextPage());

}

void beginGame(){
  currentDirection = RIGHT;
  spawnFood();
  delay(1000);
}

bool checkCollisions(){
  for(int i=1; i<segmentLength; i++){
    if(segmentPositions[i][X] == headPosition[X]){
      if(segmentPositions[i][Y] == headPosition[Y]){
        return 1;
      }
    }
  }
  if(headPosition[X] <= 0 || headPosition[X] >= 128) return 1;
  else if(headPosition[Y] <= 0 || headPosition[Y] >= 64) return 1;
  return false;
}

void spawnFood(){
  int randomX = random(5, 123);
  int randomY = random(5, 60);
  foodPosition[X] = randomX;
  foodPosition[Y] = randomY;
}

void checkFoodEaten(){
  if(headPosition[X] == foodPosition[X] || headPosition[Y] == foodPosition[Y]){
    segmentLength += 1;
    spawnFood();
  }
}

void updateDirection(){
  int joy_x_val = analogRead(JOYSTICK_X);
  int joy_y_val = analogRead(JOYSTICK_Y);
  if(joy_x_val <= DIR_THRESH) currentDirection = LEFT;
  else if(joy_x_val >= 1023-DIR_THRESH) currentDirection = RIGHT;
  else if(joy_y_val <= DIR_THRESH) currentDirection = UP;
  else if(joy_y_val >= 1023-DIR_THRESH) currentDirection = DOWN;
}

void displaySegments(){
  for(int segment=0; segment < segmentLength; segment++){
    u8g.drawPixel(segmentPositions[segment][X], segmentPositions[segment][Y]);
  }
  u8g.drawPixel(foodPosition[X], foodPosition[Y]);
}

void gameUpdate(){
  updateDirection();
  tempPosition0[X] = headPosition[X];
  tempPosition0[Y] = headPosition[Y];
  switch(currentDirection){
    case UP:
      headPosition[Y] -= 1;
      break;
    case DOWN:
      headPosition[Y] += 1;
      break;
    case LEFT:
      headPosition[X] -= 1;
      break;
    case RIGHT:
      headPosition[X] += 1;
      break;
  }
  //Update each segment's position relative to the head
  for(int segment=1; segment < segmentLength; segment+= 2){
    tempPosition1[X] = segmentPositions[segment][X];
    tempPosition1[Y] = segmentPositions[segment][Y];
    segmentPositions[segment][X] = tempPosition0[X];
    segmentPositions[segment][Y] = tempPosition0[Y];
    
    tempPosition0[X] = segmentPositions[segment+1][X];
    tempPosition0[Y] = segmentPositions[segment+1][Y];
    segmentPositions[segment+1][X] = tempPosition1[X];
    segmentPositions[segment+1][Y] = tempPosition1[Y];
  }
  displaySegments();
  checkFoodEaten();
  if(checkCollisions()) endGame();
  if(segmentLength>= MAX_LENGTH) endGame();
  delay(50);
}

void endGame(){
  segmentLength = 1;
  headPosition[0] = 63;
  headPosition[1] = 31;
  beginGame();
}

Custom parts and enclosures

Schematics

ATtiny85 Mini Arcade: Snake – Build a Handheld OLED Game Console

Manufacturing process

  1. Arduino Digital Dice Project: Build Your Own LCD-based Random Number Generator
  2. Portable Range Detector – Arduino Nano DIY Kit with HC‑SR04, 18650 Power, and 3D‑Printed Enclosure
  3. Copper Electroplating Project: Build a Smart System with Arduino UNO
  4. NeoPixel Matrix Pong on Arduino Nano: Build a Neon Pong Game
  5. Create Stunning Light Sequences with Arduino Shift Register
  6. Smart Plug: 120V Arduino‑Based Smart Outlet with Real‑Time Clock
  7. Build a Mini Piano with Arduino UNO – Step-by-Step Tutorial
  8. Arduino Tennis Game – Build a Virtual Racquet Experience with NeoPixel, Sensors, and Bluetooth
  9. Build a Compact CNC Machine with Arduino UNO
  10. Smart Alzheimer’s Companion: Arduino-Based Alert System