Hra had

Hra HAD je jednoduchá hra, ve které hráč ovládá hada, který se pohybuje po hrací ploše (tedy 8x8 matice). Cílem je sbírat jídlo a tím had roste. Hráč se musí vyhýbat kolizím s vlastním tělem. Hra končí, když do sebe narazí.
Pro tento projekt potřebujete Arduino, které bude sloužit jako hlavní řídící jednotka. Dále budete potřebovat 8x8 LED matici, PS2 joystick a potenciometr.
Budete potřebovat knihovnu LedControl.h .
Tento projekt představuje jednoduchou hru Snake na LED matici 8x8, kterou lze ovládat joystickem a potenciometrem. Joystick slouží k řízení směru pohybu hada, zatímco potenciometr nastavuje rychlost. Hra generuje "jídlo" na náhodné pozici a pokaždé, když ho had "sní," se prodlouží. Cílem je zvětšit délku hada na maximum, aniž by narazil do vlastního těla, což by způsobilo konec hry.

Zapojení:

Kód pro Arduino:

//from: https://github.com/fyemane/Arduino-snake-game
#include "LedControl.h" // Knihovna LedControl se používá pro ovládání LED matice. Najdete ji pomocí správce knihoven nebo si ji stáhněte jako zip zde: https://github.com/wayoda/LedControl

#define joystickX A2   // pin osy X joysticku
#define joystickY A1   // pin osy Y joysticku

#define potentiometer A3 // potenciometr pro ovládání rychlosti hada

#define CLK 2   // hodiny pro LED matici
#define CS  3  // chip-select pro LED matici
#define DIN 4 // data-in pro LED matici

// Jas LED matice: mezi 0 (nejtmavší) a 15 (nejjasnější)
const short intensity = 1;

// nižší = rychlejší scrollování zprávy
const short messageSpeed = 10;

// počáteční délka hada (1...63, doporučeno 3)
const short initialSnakeLength = 3;


void setup() {
  Serial.begin(115200);  // nastavte stejnou baudovou rychlost na vašem sériovém monitoru
  initialize();         // inicializace pinů a LED matice
  calibrateJoystick(); // kalibrace domácí pozice joysticku (nechte jej nepohnutý)
  showSnakeMessage(); // posunuje zprávu 'snake' kolem matice
}


void loop() {
  generateFood();
  scanJoystick();    // zabraňuje generátoru jídla, aby běžel, v tomto případě by běžel navždy, protože nebude schopen najít pixel bez hada
  calculateSnake();  // vypočítá parametry hada
  handleGameStates();
  
  // odkomentujte, pokud chcete, aby se aktuální herní plán vytiskl do seriálu (trochu zpomalí hru)
   dumpGameBoard();
}





// --------------------------------------------------------------- //
// -------------------- podpůrné proměnné --------------------- //
// --------------------------------------------------------------- //

LedControl matrix(DIN, CLK, CS, 1);

struct Point {
  int row = 0, col = 0;
  Point(int row = 0, int col = 0): row(row), col(col) {}
};

struct Coordinate {
  int x = 0, y = 0;
  Coordinate(int x = 0, int y = 0): x(x), y(y) {}
};

bool win = false;
bool gameOver = false;

// primární souřadnice hadí hlavy (hadí hlava), budou vygenerovány náhodně
Point snake;

// jídlo zatím nikde není
Point food(-1, -1);

// vytvořit s výchozími hodnotami v případě, že uživatel vypne kalibraci
Coordinate joystickHome(500, 500);

// hadí parametry
int snakeLength = initialSnakeLength; // zvolené uživatelem v sekci konfigurace
int snakeSpeed = 1; // bude nastaveno podle hodnoty potenciometru, nemůže být 0
int snakeDirection = 0; // pokud je 0, had se nepohybuje

// směrové konstanty
const short up     = 1;
const short right  = 2;
const short down   = 3; // 'down - 2' musí být 'up'
const short left   = 4; // 'left - 2' musí být 'right'

// práh, kde bude akceptován pohyb joysticku
const int joystickThreshold = 160;

// umělá logaritmičnost (strmost) potenciometru (-1 = lineární, 1 = přirozená, větší = strmější (doporučeno 0...1))
const float logarithmity = 0.4;

// uložení segmentů hadího těla
int gameboard[8][8] = {};




// ------------------------------------------------------------ //
// -------------------------- funkce -------------------------- //
// ------------------------------------------------------------ //


// pokud není jídlo, vygenerujte si ho a také zkontrolujte vítězství
void generateFood() {
  if (food.row == -1 || food.col == -1) {
    if (snakeLength >= 64) {
      win = true;
      return; // zabránit spuštění generátoru jídla, v tomto případě by běžel navždy, protože nebude schopen najít pixel bez hada
    }

    // generujte jídlo, dokud nebude ve správné poloze
    do {
      food.col = random(8);
      food.row = random(8);
    } while (gameboard[food.row][food.col] > 0);
  }
}


// sleduje pohyby joysticku a bliká s jídlem
void scanJoystick() {
  int previousDirection = snakeDirection; // uložit poslední směr
  long timestamp = millis();

  while (millis() < timestamp + snakeSpeed) {
    // vypočítat rychlost hada exponenciálně (10...1000 ms)
    float raw = mapf(analogRead(potentiometer), 0, 1023, 0, 1);
    snakeSpeed = mapf(pow(raw, 3.5), 0, 1, 10, 1000); // měnit rychlost exponenciálně
    if (snakeSpeed == 0) snakeSpeed = 1; // bezpečnost: rychlost nemůže být 0

    // určit směr hada
    analogRead(joystickY) < joystickHome.y - joystickThreshold ? snakeDirection = right : 0;
    analogRead(joystickY) > joystickHome.y + joystickThreshold ? snakeDirection = left  : 0;
    analogRead(joystickX) < joystickHome.x - joystickThreshold ? snakeDirection = up    : 0;
    analogRead(joystickX) > joystickHome.x + joystickThreshold ? snakeDirection = down  : 0;

    // ignorovat změnu směru o 180 stupňů (žádný efekt pro nepohybujícího se hada)
    snakeDirection + 2 == previousDirection & previousDirection != 0 ? snakeDirection = previousDirection : 0;
    snakeDirection - 2 == previousDirection & previousDirection != 0 ? snakeDirection = previousDirection : 0;

    // inteligentně blikat s jídlem
    matrix.setLed(0, food.row, food.col, millis() % 100 < 50 ? 1 : 0);
  }
}


// vypočítat údaje o pohybu hada
void calculateSnake() {
  switch (snakeDirection) {
    case up:
      snake.row--;
      fixEdge();
      matrix.setLed(0, snake.row, snake.col, 1);
      break;

    case right:
      snake.col++;
      fixEdge();
      matrix.setLed(0, snake.row, snake.col, 1);
      break;

    case down:
      snake.row++;
      fixEdge();
      matrix.setLed(0, snake.row, snake.col, 1);
      break;

    case left:
      snake.col--;
      fixEdge();
      matrix.setLed(0, snake.row, snake.col, 1);
      break;

    default: // pokud se had nepohybuje, odejděte
      return;
  }

  // pokud existuje segment hadího těla, způsobí to konec hry (had se musí pohybovat)
  if (gameboard[snake.row][snake.col] > 1 & snakeDirection != 0) {
    gameOver = true;
    return;
  }

  // zkontrolujte, zda bylo jídlo snědeno
  if (snake.row == food.row & snake.col == food.col) {
    food.row = -1; // reset food
    food.col = -1;

    // přírůstek délky hada
    snakeLength++;

    // zvětšit všechny segmenty hadího těla
    for (int row = 0; row < 8; row++) {
      for (int col = 0; col < 8; col++) {
        if (gameboard[row][col] > 0 ) {
          gameboard[row][col]++;
        }
      }
    }
  }

  // přidat nový segment na umístění hadí hlavy
  gameboard[snake.row][snake.col] = snakeLength + 1; // se za chvíli sníží

  // snižte všechny segmenty hadího těla, pokud je segment 0, vypněte odpovídající LED
  for (int row = 0; row < 8; row++) {
    for (int col = 0; col < 8; col++) {
      // pokud existuje segment těla, snižte jeho hodnotu
      if (gameboard[row][col] > 0 ) {
        gameboard[row][col]--;
      }

      // zobrazit aktuální pixel
      matrix.setLed(0, row, col, gameboard[row][col] == 0 ? 0 : 1);
    }
  }
}


// způsobí, že se had objeví na druhé straně obrazovky, pokud se dostane z okraje
void fixEdge() {
  snake.col < 0 ? snake.col += 8 : 0;
  snake.col > 7 ? snake.col -= 8 : 0;
  snake.row < 0 ? snake.row += 8 : 0;
  snake.row > 7 ? snake.row -= 8 : 0;
}


void handleGameStates() {
  if (gameOver || win) {
    unrollSnake();

    showScoreMessage(snakeLength - initialSnakeLength);

    if (gameOver) showGameOverMessage();
    else if (win) showWinMessage();

    // znovu spustit hru
    win = false;
    gameOver = false;
    snake.row = random(8);
    snake.col = random(8);
    food.row = -1;
    food.col = -1;
    snakeLength = initialSnakeLength;
    snakeDirection = 0;
    memset(gameboard, 0, sizeof(gameboard[0][0]) * 8 * 8);
    matrix.clearDisplay(0);
  }
}


void unrollSnake() {
  // vypněte LED kontrolku jídla
  matrix.setLed(0, food.row, food.col, 0);

  delay(800);

  // 5x zablikat na obrazovce
  for (int i = 0; i < 5; i++) {
    // převrátit obrazovku
    for (int row = 0; row < 8; row++) {
      for (int col = 0; col < 8; col++) {
        matrix.setLed(0, row, col, gameboard[row][col] == 0 ? 1 : 0);
      }
    }

    delay(20);

    // převrátit zpět
    for (int row = 0; row < 8; row++) {
      for (int col = 0; col < 8; col++) {
        matrix.setLed(0, row, col, gameboard[row][col] == 0 ? 0 : 1);
      }
    }

    delay(50);

  }


  delay(600);

  for (int i = 1; i <= snakeLength; i++) {
    for (int row = 0; row < 8; row++) {
      for (int col = 0; col < 8; col++) {
        if (gameboard[row][col] == i) {
          matrix.setLed(0, row, col, 0);
          delay(100);
        }
      }
    }
  }
}


// 10krát zkalibrujte joystick domů
void calibrateJoystick() {
  Coordinate values;

  for (int i = 0; i < 10; i++) {
    values.x += analogRead(joystickX);
    values.y += analogRead(joystickY);
  }

  joystickHome.x = values.x / 10;
  joystickHome.y = values.y / 10;
}


void initialize(){
  
  matrix.shutdown(0, false);
  matrix.setIntensity(0, intensity);
  matrix.clearDisplay(0);

  randomSeed(analogRead(A5));
  snake.row = random(8);
  snake.col = random(8);
}


void dumpGameBoard() {
  String buff = "nnn";
  for (int row = 0; row < 8; row++) {
    for (int col = 0; col < 8; col++) {
      if (gameboard[row][col] < 10) buff += " ";
      if (gameboard[row][col] != 0) buff += gameboard[row][col];
      else if (col == food.col & row == food.row) buff += "@";
      else buff += "-";
      buff += " ";
    }
    buff += "n";
  }
  Serial.println(buff);
}





// ------------------------------------------------------------- //
// -------------------------- zprávy --------------------------- //
// ------------------------------------------------------------- //

const PROGMEM bool snakeMessage[8][56] = {
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}
};

const PROGMEM bool gameOverMessage[8][90] = {
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}
};

const PROGMEM bool scoreMessage[8][58] = {
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
};

const PROGMEM bool digits[][8][8] = {
  {
    {0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 1, 1, 1, 1, 0, 0},
    {0, 1, 1, 0, 0, 1, 1, 0},
    {0, 1, 1, 0, 1, 1, 1, 0},
    {0, 1, 1, 1, 0, 1, 1, 0},
    {0, 1, 1, 0, 0, 1, 1, 0},
    {0, 1, 1, 0, 0, 1, 1, 0},
    {0, 0, 1, 1, 1, 1, 0, 0}
  },
  {
    {0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 1, 1, 0, 0, 0},
    {0, 0, 0, 1, 1, 0, 0, 0},
    {0, 0, 1, 1, 1, 0, 0, 0},
    {0, 0, 0, 1, 1, 0, 0, 0},
    {0, 0, 0, 1, 1, 0, 0, 0},
    {0, 0, 0, 1, 1, 0, 0, 0},
    {0, 1, 1, 1, 1, 1, 1, 0}
  },
  {
    {0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 1, 1, 1, 1, 0, 0},
    {0, 1, 1, 0, 0, 1, 1, 0},
    {0, 0, 0, 0, 0, 1, 1, 0},
    {0, 0, 0, 0, 1, 1, 0, 0},
    {0, 0, 1, 1, 0, 0, 0, 0},
    {0, 1, 1, 0, 0, 0, 0, 0},
    {0, 1, 1, 1, 1, 1, 1, 0}
  },
  {
    {0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 1, 1, 1, 1, 0, 0},
    {0, 1, 1, 0, 0, 1, 1, 0},
    {0, 0, 0, 0, 0, 1, 1, 0},
    {0, 0, 0, 1, 1, 1, 0, 0},
    {0, 0, 0, 0, 0, 1, 1, 0},
    {0, 1, 1, 0, 0, 1, 1, 0},
    {0, 0, 1, 1, 1, 1, 0, 0}
  },
  {
    {0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 1, 1, 0, 0},
    {0, 0, 0, 1, 1, 1, 0, 0},
    {0, 0, 1, 0, 1, 1, 0, 0},
    {0, 1, 0, 0, 1, 1, 0, 0},
    {0, 1, 1, 1, 1, 1, 1, 0},
    {0, 0, 0, 0, 1, 1, 0, 0},
    {0, 0, 0, 0, 1, 1, 0, 0}
  },
  {
    {0, 0, 0, 0, 0, 0, 0, 0},
    {0, 1, 1, 1, 1, 1, 1, 0},
    {0, 1, 1, 0, 0, 0, 0, 0},
    {0, 1, 1, 1, 1, 1, 0, 0},
    {0, 0, 0, 0, 0, 1, 1, 0},
    {0, 0, 0, 0, 0, 1, 1, 0},
    {0, 1, 1, 0, 0, 1, 1, 0},
    {0, 0, 1, 1, 1, 1, 0, 0}
  },
  {
    {0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 1, 1, 1, 1, 0, 0},
    {0, 1, 1, 0, 0, 1, 1, 0},
    {0, 1, 1, 0, 0, 0, 0, 0},
    {0, 1, 1, 1, 1, 1, 0, 0},
    {0, 1, 1, 0, 0, 1, 1, 0},
    {0, 1, 1, 0, 0, 1, 1, 0},
    {0, 0, 1, 1, 1, 1, 0, 0}
  },
  {
    {0, 0, 0, 0, 0, 0, 0, 0},
    {0, 1, 1, 1, 1, 1, 1, 0},
    {0, 1, 1, 0, 0, 1, 1, 0},
    {0, 0, 0, 0, 1, 1, 0, 0},
    {0, 0, 0, 0, 1, 1, 0, 0},
    {0, 0, 0, 1, 1, 0, 0, 0},
    {0, 0, 0, 1, 1, 0, 0, 0},
    {0, 0, 0, 1, 1, 0, 0, 0}
  },
  {
    {0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 1, 1, 1, 1, 0, 0},
    {0, 1, 1, 0, 0, 1, 1, 0},
    {0, 1, 1, 0, 0, 1, 1, 0},
    {0, 0, 1, 1, 1, 1, 0, 0},
    {0, 1, 1, 0, 0, 1, 1, 0},
    {0, 1, 1, 0, 0, 1, 1, 0},
    {0, 0, 1, 1, 1, 1, 0, 0}
  },
  {
    {0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 1, 1, 1, 1, 0, 0},
    {0, 1, 1, 0, 0, 1, 1, 0},
    {0, 1, 1, 0, 0, 1, 1, 0},
    {0, 0, 1, 1, 1, 1, 1, 0},
    {0, 0, 0, 0, 0, 1, 1, 0},
    {0, 1, 1, 0, 0, 1, 1, 0},
    {0, 0, 1, 1, 1, 1, 0, 0}
  }
};


// posouvá zprávu „snake“ po matrici
void showSnakeMessage() {
  [&] {
    for (int d = 0; d < sizeof(snakeMessage[0]) - 7; d++) {
      for (int col = 0; col < 8; col++) {
        delay(messageSpeed);
        for (int row = 0; row < 8; row++) {
          // toto přečte bajt z PROGMEM a zobrazí jej na obrazovce
          matrix.setLed(0, row, col, pgm_read_byte(&(snakeMessage[row][col + d])));
        }
      }

      // pokud je joystick posunut, opusťte zprávu
      if (analogRead(joystickY) < joystickHome.y - joystickThreshold
              || analogRead(joystickY) > joystickHome.y + joystickThreshold
              || analogRead(joystickX) < joystickHome.x - joystickThreshold
              || analogRead(joystickX) > joystickHome.x + joystickThreshold) {
        return; // vrátit funkci lambda
      }
    }
  }();

  matrix.clearDisplay(0);

  // počkejte, až se joystick vrátí
  while (analogRead(joystickY) < joystickHome.y - joystickThreshold
          || analogRead(joystickY) > joystickHome.y + joystickThreshold
          || analogRead(joystickX) < joystickHome.x - joystickThreshold
          || analogRead(joystickX) > joystickHome.x + joystickThreshold) {}

}


// posouvá zprávu „game over“ po matrici
void showGameOverMessage() {
  [&] {
    for (int d = 0; d < sizeof(gameOverMessage[0]) - 7; d++) {
      for (int col = 0; col < 8; col++) {
        delay(messageSpeed);
        for (int row = 0; row < 8; row++) {
          // toto přečte bajt z PROGMEM a zobrazí jej na obrazovce
          matrix.setLed(0, row, col, pgm_read_byte(&(gameOverMessage[row][col + d])));
        }
      }

      // pokud je joystick posunut, opusťte zprávu
      if (analogRead(joystickY) < joystickHome.y - joystickThreshold
              || analogRead(joystickY) > joystickHome.y + joystickThreshold
              || analogRead(joystickX) < joystickHome.x - joystickThreshold
              || analogRead(joystickX) > joystickHome.x + joystickThreshold) {
        return; // vrátit funkci lambda
      }
    }
  }();

  matrix.clearDisplay(0);

  // počkejte, až se joystick vrátí
  while (analogRead(joystickY) < joystickHome.y - joystickThreshold
          || analogRead(joystickY) > joystickHome.y + joystickThreshold
          || analogRead(joystickX) < joystickHome.x - joystickThreshold
          || analogRead(joystickX) > joystickHome.x + joystickThreshold) {}

}


// posouvá zprávu „win“ po matrici
void showWinMessage() {
  // dosud neimplementováno // implementujte to
}


// posouvá zprávu „score“ po matrici
void showScoreMessage(int score) {
  if (score < 0 || score > 99) return;

  // určete číslice skóre
  int second = score % 10;
  int first = (score / 10) % 10;

  [&] {
    for (int d = 0; d < sizeof(scoreMessage[0]) + 2 * sizeof(digits[0][0]); d++) {
      for (int col = 0; col < 8; col++) {
        delay(messageSpeed);
        for (int row = 0; row < 8; row++) {
          if (d <= sizeof(scoreMessage[0]) - 8) {
            matrix.setLed(0, row, col, pgm_read_byte(&(scoreMessage[row][col + d])));
          }

          int c = col + d - sizeof(scoreMessage[0]) + 6; // posunout o 6 px před předchozí zprávu

          // pokud je skóre < 10, posuňte první číslici (nulu)
          if (score < 10) c += 8;

          if (c >= 0 & c < 8) {
            if (first > 0) matrix.setLed(0, row, col, pgm_read_byte(&(digits[first][row][c]))); // zobrazit, pouze pokud je skóre >= 10 (viz výše)
          } else {
            c -= 8;
            if (c >= 0 & c < 8) {
              matrix.setLed(0, row, col, pgm_read_byte(&(digits[second][row][c]))); // ukázat vždy
            }
          }
        }
      }

      // pokud je joystick posunut, opusťte zprávu
      if (analogRead(joystickY) < joystickHome.y - joystickThreshold
              || analogRead(joystickY) > joystickHome.y + joystickThreshold
              || analogRead(joystickX) < joystickHome.x - joystickThreshold
              || analogRead(joystickX) > joystickHome.x + joystickThreshold) {
        return; // vrátit funkci lambda
      }
    }
  }();

  matrix.clearDisplay(0);


}


// standardní mapová funkce, ale s plováky
float mapf(float x, float in_min, float in_max, float out_min, float out_max) {
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

Další podobné články

Ovládání teploty pomocí relé a senzoru DS18B20

Tento projekt umožňuje měřit teplotu pomocí senzoru DS18B20, zobrazit ji na I2C LCD displeji, a ovládat relé podle teplotních limitů. Relé bude aktivní, když je teplota mezi 0 a 22 stupni Celsia. Projekt může sloužit k ovládání topení, ventilace nebo jiného zařízení podle okolní teploty.