Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Manufacturing Technology >> Herstellungsprozess

ATtiny85 Mini-Arcade: Snake – Handheld OLED-Spielekonsole selbst bauen

Komponenten und Materialien

Microchip ATtiny85 1
Grafik-OLED 128×64 1
SparkFun microB USB Breakout 1
Arduino Nano R3 (zum Programmieren des ATtiny85) 1

Benötigte Werkzeuge und Maschinen

Apps und Online-Dienste

Über dieses Projekt

Inspiration und Vorprojekt

Dezember 2017: Ich baute eine Handheld-Arduino-Pong-Konsole mit Arduino Nano, OLED und zwei Tasten.

ATtiny85 Mini-Arcade: Snake – Handheld OLED-Spielekonsole selbst bauen

Damals okay, aber zu groß und klobig. Jetzt wollte ich eine winzige Konsole für Snake bauen.

ATtiny85 Mini-Arcade: Snake – Handheld OLED-Spielekonsole selbst bauen

Die gewählten Komponenten

Für kleine Größe kein Arduino-Dev-Board → ATtiny85.

ATtiny85 Mini-Arcade: Snake – Handheld OLED-Spielekonsole selbst bauen

Genug I/O für das Spiel: zwei ADC-Pins, I2C-Port, ein GPIO-Pin. Einfaches 2-Achsen-Joystick/Switch-Modul (3 Pins für Signale).

ATtiny85 Mini-Arcade: Snake – Handheld OLED-Spielekonsole selbst bauen

Display: DFRobots 128×64 OLED – klein, aber ausreichend Auflösung.

ATtiny85 Mini-Arcade: Snake – Handheld OLED-Spielekonsole selbst bauen

System verlöten

ATtiny85 auf SOP-8-auf-DIP-8-Breakout-PCB löten, auf kleines Lochrasterboard. Zwei Header: einer zum Programmieren, einer fürs Display. Joystick-Pins anlöten und verdrahten. Zum Schluss micro-USB-Breakout für Stromversorgung anschließen.

ATtiny85 Mini-Arcade: Snake – Handheld OLED-Spielekonsole selbst bauen
ATtiny85 Mini-Arcade: Snake – Handheld OLED-Spielekonsole selbst bauen

Gehäuse designen

In Fusion 360 designed. Zuerst echte Bauteile platzieren, dann Gehäuse drumherum.

ATtiny85 Mini-Arcade: Snake – Handheld OLED-Spielekonsole selbst bauen
ATtiny85 Mini-Arcade: Snake – Handheld OLED-Spielekonsole selbst bauen

Ziel: 80er-Jahre-Arcade-Optik, aber winzig. Renderings:

ATtiny85 Mini-Arcade: Snake – Handheld OLED-Spielekonsole selbst bauen
ATtiny85 Mini-Arcade: Snake – Handheld OLED-Spielekonsole selbst bauen

Spiel programmieren

Snake ist einfach zu programmieren. Maximale Schlangenlänge: 30 (RAM sparen) → nach 29 gefressenen Pixeln gewinnt der Spieler. 2D-Array speichert Koordinaten jedes Segments.

ATtiny85 Mini-Arcade: Snake – Handheld OLED-Spielekonsole selbst bauen

Kopf bewegt sich → vorherige Positionen kaskadieren nach unten. Neues Segment bei Fressen an zufälliger Position. Kollisionsprüfung: Iteration durch alle Segmente, Prüfung ob Kopfkoordinaten gleich. Kollision mit Wänden = Game Over.

ATtiny85 Mini-Arcade: Snake – Handheld OLED-Spielekonsole selbst bauen

Snake spielen

Konsole einschalten, warten bis Futter und erstes Segment geladen. Joystick steuern, Snake frisst Futter. Macht Spaß, toller Zeitvertreib im Miniformat.

ATtiny85 Mini-Arcade: Snake – Handheld OLED-Spielekonsole selbst bauen

Code

ATtiny85 Code (C/C++)

U8g2lib vorher installieren!

//#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
#define X 0
#define Y 1
#define JOYSTICK_X 2
#define JOYSTICK_Y 3
#define DIR_THRESH 300

uint8_t segmentPositions[MAX_LENGTH][2];
uint8_t headPosition[2] = {63, 31};
uint8_t foodPosition[2];
uint8_t tempPosition0[2];
uint8_t tempPosition1[2];
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;
  }
  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();
}

Benutzerdefinierte Teile und Gehäuse

(STL-Dateien im Originalprojekt verlinkt)

Schaltpläne

ATtiny85 Mini-Arcade: Snake – Handheld OLED-Spielekonsole selbst bauen

Herstellungsprozess

  1. TinyML Spracherkennung mit Edge Impulse auf Arduino Nano 33 BLE Sense
  2. Echtzeit-Gyroskop-Spiel mit Arduino Nano & MPU-6050
  3. Arduino Digitaler Würfel: LCD-Würfel mit Zufallszahlen (1–6)
  4. 37-LED-Roulette-Spiel mit Arduino Nano bauen – Europäisches Layout
  5. Tragbarer Entfernungsmesser – Arduino Nano DIY-Kit mit HC-SR04, 18650-Akku und 3D-gedrucktem Gehäuse
  6. Audio-reaktive Schreibtischlampe mit Arduino Nano bauen
  7. Kupfer-Galvanik-Projekt: Intelligentes System mit Arduino UNO bauen
  8. NeoPixel-Matrix Pong auf Arduino Nano: Neon-Pong selbst bauen
  9. Beeindruckende Lichtsequenzen mit Arduino und Schieberegister erstellen
  10. Smart Plug: 120 V Arduino-Steckdose mit Echtzeituhr