Skip to content

Snake on an OLED

April 6, 2022

I’m quite pleased with this. I came across a snake game played with an attiny85 on Hackaday. The code is written in c++ so i grabbed it and whittled it down to basic C for LCC1802. I had the oled from previous efforts and i found a sort-of mini-joystick in a bargain bin of Radio Shack stuff.

The combination is actually pretty playable. painting the whole screen over spi is a bit slow but individual moves are fast enough that the gameplay is fine.

The code is quite long but the basic game loop is readable:

    while(1){
		reset();
		placedot();
		while(!gameover()){
			changeNextMove();
			moveSnake();
		   // check if you hit the dot
			if ((snake[0] == dot[0]) && (snake[1] == dot[1]))
			{
			  snakeLen++;
			  placeDot();
			}
			changeNextMove();
			delay(100);
		}
		// blink the screen to indicate game over
		delay(300);
		oled18blinkScreen(3);
		delay(100);
		// display the user's score
		oled18drawImage(SCORE,0);
		oled18displayScore(snakeLen - 3);
		delay(3000);
	}

Just as an example, the placeDot() routine calls a routine to place a pixel on the oled which in turn calls an old LCD routine to do the spi write. All of them are shown below. The rand routine is one Marcel Tongren wrote for the crosslib games.

// put the dot on a random place on the board
void placeDot()
{
  int i;
  // select a new random place for the dot
  //srand(millis());
  uint8_t x = (rand() % 14) + 1;
  uint8_t y = (rand() % 6) + 1;
  for (i = 0; i < snakeLen; ++i)
  {
    // check if the randomly selected dot is not a snake block
    if ((snake[2 * i] == x) && (snake[(2 * i) + 1] == y))
    {
      placeDot();
      return;
    }

  }
  dot[0] = x; dot[1] = y;

  // place the dot on the screen
  oled18drawPixel(dot[0], dot[1]);
}

/// x in range <0, 16), y in range <0, 8) - fills a 8x8 pixel block on the specified index
void oled18drawPixel(uint8_t x, uint8_t y)
{
  uint8_t j;
  x *= NUM_PAGES;
  oled18setPageAddr(y, y);
  oled18setColAddr(x + 1, x + 7);
  for (j = 0; j < 6; j++)
  {
    LcdWrite(LCD_D,0x7E); // do not fill it completely, make a 1 pixel wide border around it
  }
}

void LcdWrite(unsigned char dc, unsigned char payload) //flag for data vs command, byte to send out
{
	register unsigned char dummy;
	digitalWrite(lcdcmd,dc); //set data or command
	spisend(payload);
}

The new WordPress editor won’t let me collapse the code blocks so i won’t paste the whole code in here. if i can figure out how to do it i’ll come back and edit the post.

From → Uncategorized

Leave a Comment

Leave a comment