Last active
April 8, 2018 13:57
-
-
Save Romern/28b69e750e5efc930abb6b8a6b1fbcae to your computer and use it in GitHub Desktop.
Snake written for Arduino with tiny screen
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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