Skip to content

Instantly share code, notes, and snippets.

@Romern
Last active April 8, 2018 13:57
Show Gist options
  • Save Romern/28b69e750e5efc930abb6b8a6b1fbcae to your computer and use it in GitHub Desktop.
Save Romern/28b69e750e5efc930abb6b8a6b1fbcae to your computer and use it in GitHub Desktop.
Snake written for Arduino with tiny screen
//SNAKE
#include "lcd.h"
#include "util.h"
#include "os_input.h"
#include "os_core.h"
#include "os_scheduler.h"
#include "os_memory.h"
#include "keyb_processor.h"
#include <math.h>
#include <stdlib.h>
#include <avr/interrupt.h>
#define DELAY 1000
#define XRES 16
#define YRES 4
#define MAXTAIL 64 //16*4
#define UPPERPIXELID 0
#define UPPERPIXEL (CUSTOM_CHAR( \
0x1F, \
0x1F, \
0x1F, \
0x1F, \
0x00, \
0x00, \
0x00, \
0x00))
#define LOWERPIXELID 5
#define LOWERPIXEL (CUSTOM_CHAR( \
0x00, \
0x00, \
0x00, \
0x00, \
0x1F, \
0x1F, \
0x1F, \
0x1F))
#define WHOLEPIXELID 0xFF
typedef enum Richtung {
UP,
DOWN,
LEFT,
RIGHT
} Richtung;
Richtung richt;
Richtung oldricht;
uint8_t speed;
uint8_t highscore;
bool endmenu;
typedef struct {
uint8_t xpos;
uint8_t ypos;
} Block;
typedef struct {
Block data [MAXTAIL];
uint8_t size;
uint8_t length;
uint8_t head;
uint8_t tail;
uint8_t timeSlice;
Block kopf;
Block treat;
} Body;
Body snake;
Block nulli;
static char PROGMEM const gameover [] ="Game Over!\nScore: ";
void schlange_init (Body* queue) {
queue->size = MAXTAIL;
for(uint8_t i = 0; i<queue->size; i++){
queue->data[i] = nulli;
}
queue->tail = 0;
queue->head = 0;
}
bool schlange_hasNext (Body* queue) {
return (queue->head != queue->tail);
}
Block schlange_getFirst (Body* queue) {
if (schlange_hasNext(queue)) {
return queue->data[queue->tail];
}
return nulli;
}
void schlange_dropFirst (Body* queue) {
if (schlange_hasNext(queue)) {
queue->data[queue->tail] = nulli;
queue->tail++;
queue->length--;
if (queue->tail==queue->size)
queue->tail = 0;
}
}
void schlange_append (Body* queue, Block append) {
queue->data[queue->head] = append;
queue->head++;
queue->length++;
if (queue->head==queue->size)
queue->head = 0;
}
void drawSnake() {
lcd_clear();
bool matrix[XRES][YRES];
for(uint8_t x = 0; x<XRES; x++){ //create bitmap
for(uint8_t y = 0; y<YRES; y++){ //create bitmap
matrix[x][y] = false;
}
}
for(uint8_t i = 0; i<snake.size; i++){ //create bitmap
if (snake.data[i].xpos != 100) {
matrix[snake.data[i].xpos][snake.data[i].ypos] = true;
}
}
matrix[snake.treat.xpos][snake.treat.ypos] = true;
matrix[snake.kopf.xpos][snake.kopf.ypos] = true;
for(int y = YRES-1; y>=0; y -=2){
for(uint8_t x = 0; x<XRES; x++){
if (matrix[x][y]==true && matrix[x][y-1]==true) {
lcd_writeChar(WHOLEPIXELID); // ?
} else if (matrix[x][y]==true && matrix[x][y-1]==false) {
lcd_writeChar(UPPERPIXELID); // ?
} else if (matrix[x][y]==false && matrix[x][y-1]==false) {
lcd_writeChar(' '); //
} else if (matrix[x][y]==false && matrix[x][y-1]==true) {
lcd_writeChar(LOWERPIXELID); // ?
}
}
}
delayMs(DELAY/speed);
}
void setDirection(Key newdir) {
switch (newdir.key) {
case KEYB_KEY_ARROW_LEFT:
if (oldricht != RIGHT)
richt = LEFT;
break;
case KEYB_KEY_ARROW_RIGHT:
if (oldricht != LEFT)
richt = RIGHT;
break;
case KEYB_KEY_ARROW_UP:
if (oldricht != DOWN)
richt = UP;
break;
case KEYB_KEY_ARROW_DOWN:
if (oldricht != UP)
richt = DOWN;
break;
}
}
void setDirectionMenu(Key newdir) {
if (newdir.meta == KEYB_KM_MAKE) {
switch (newdir.key) {
case KEYB_KEY_ARROW_LEFT:
if (speed>1)
speed--;
break;
case KEYB_KEY_ARROW_RIGHT:
if (speed<10)
speed++;
break;
}
}
lcd_clear();
lcd_writeProgString(PSTR("Speed: "));
lcd_writeChar('<');
lcd_writeDec(speed);
lcd_writeChar('>');
lcd_writeChar('\n');
lcd_writeProgString(PSTR("Highscore: "));
lcd_writeDec(highscore);
}
void quitFunktion(Key newkey) {
if (newkey.key == KEYB_KEY_CTRL_ENTER) {
endmenu = false;
}
}
PROGRAM(1, AUTOSTART) {
lcd_clear();
lcd_registerCustomChar(UPPERPIXELID, UPPERPIXEL);
lcd_registerCustomChar(LOWERPIXELID, LOWERPIXEL);
//init keyboard
keyb_start();
highscore = 20;
speed = 4;
srand ( 42 );
while (1) { //menu loop
keyb_set_processor(KEYB_KT_ARROW, NULL);
endmenu = true;
lcd_clear();
lcd_writeProgString(PSTR("Speed: "));
lcd_writeChar('<');
lcd_writeDec(speed);
lcd_writeChar('>');
lcd_writeChar('\n');
lcd_writeProgString(PSTR("Highscore: "));
lcd_writeDec(highscore);
keyb_set_processor(KEYB_KT_ARROW, setDirectionMenu);
keyb_set_main_processor(quitFunktion);
while (endmenu == true) {
delayMs(1);
} //wait for menu to finish
keyb_set_main_processor(NULL);
keyb_set_processor(KEYB_KT_ARROW, setDirection);
snake.kopf.xpos = 8;
snake.kopf.ypos = 2;
nulli.xpos = 100;
nulli.ypos = 100;
snake.treat.xpos = 1;
snake.treat.ypos = 1;
richt = LEFT;
schlange_init(&snake);
drawSnake();
oldricht = LEFT;
bool ending = false;
while (1) { //gameloop //get new direction
Block lastpos;
lastpos.xpos = snake.kopf.xpos;
lastpos.ypos = snake.kopf.ypos;
switch(richt) { //move head
case LEFT:
snake.kopf.xpos--;
break;
case RIGHT:
snake.kopf.xpos++;
break;
case UP:
snake.kopf.ypos++;
break;
case DOWN:
snake.kopf.ypos--;
break;
}
oldricht = richt;
if (snake.kopf.xpos>XRES) { //wenn nach links raus wieder rechts spawnen
snake.kopf.xpos = XRES-1;
} else if (snake.kopf.xpos == XRES) { //wenn nach rechts raus wieder links spawnen
snake.kopf.xpos = 0;
} else if (snake.kopf.ypos > YRES) { //wenn nach unten raus wieder oben spawnen
snake.kopf.ypos = YRES-1;
} else if (snake.kopf.ypos == YRES) { //wenn nach oben raus wieder unten spawnen
snake.kopf.ypos = 0;
}
for (uint8_t i = 0 ; i<snake.size; i++) { //prüfe nach kollision
if (snake.data[i].xpos == snake.kopf.xpos && snake.data[i].ypos == snake.kopf.ypos) {
if (snake.length > highscore)
highscore = snake.length;
lcd_clear();
lcd_writeProgString(gameover);
lcd_writeDec(snake.length);
ending = true;
delayMs(2500);
}
}
if (ending) {
break;
}
if (snake.treat.xpos == snake.kopf.xpos && snake.treat.ypos == snake.kopf.ypos) { //prüfe ob treat gegessen wurde
schlange_append(&snake,lastpos); //neues körperteil, ohne das eins entfernt wird
while (snake.treat.xpos == snake.kopf.xpos && snake.treat.ypos == snake.kopf.ypos) { //setze treat neu, sodass es nicht an derselben stelle ist
snake.treat.xpos = (rand() % (XRES));
snake.treat.ypos = (rand() % (YRES));
}
} else if (snake.length != 0) { //move the body by removing the last bodypart
schlange_dropFirst(&snake); //and adding one at the position of the head before it was moved
schlange_append(&snake,lastpos);
}
drawSnake();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment