consolidated both snake trees, saving ~950 bytes
This commit is contained in:
parent
291c90ccf6
commit
3a0d8799bd
|
@ -1,131 +1,9 @@
|
||||||
|
#include "../games/snake/snake_game.h"
|
||||||
|
|
||||||
#include "../config.h"
|
/**
|
||||||
#include "../pixel.h"
|
* Snake in demo mode.
|
||||||
#include "../util.h"
|
*/
|
||||||
#include "../random/prng.h"
|
void snake_animation(void)
|
||||||
#include "snake.h"
|
{
|
||||||
|
snake_engine(1);
|
||||||
#define RANDOM8() (random8())
|
|
||||||
|
|
||||||
void snake(){
|
|
||||||
pixel pixels[64];
|
|
||||||
pixels[0] = (pixel){NUM_COLS/2, NUM_ROWS/2};
|
|
||||||
pixels[1] = (pixel){NUM_COLS/2, (NUM_ROWS/2)-1};
|
|
||||||
|
|
||||||
pixel * head = &pixels[1];
|
|
||||||
pixel * tail = &pixels[0];
|
|
||||||
pixel old_head;
|
|
||||||
|
|
||||||
pixel apples[10];
|
|
||||||
unsigned char apple_num = 0;
|
|
||||||
|
|
||||||
direction dir = up;
|
|
||||||
|
|
||||||
clear_screen(0);
|
|
||||||
|
|
||||||
unsigned char x=0, dead=0;
|
|
||||||
while(1){
|
|
||||||
x++;
|
|
||||||
old_head = *head;
|
|
||||||
if(++head == pixels + 64) head = pixels;
|
|
||||||
|
|
||||||
unsigned char dead_cnt=0;
|
|
||||||
|
|
||||||
unsigned char apple_found = 0, j;
|
|
||||||
for(j=0;j<apple_num;j++){
|
|
||||||
unsigned char i;
|
|
||||||
for(i=0;i<4;i++){
|
|
||||||
if ( (next_pixel(old_head, i).x == apples[j].x) && (next_pixel(old_head, i).y == apples[j].y) ){
|
|
||||||
apple_found = 1;
|
|
||||||
dir = i;
|
|
||||||
for(;j<apple_num-1;j++){
|
|
||||||
apples[j]=apples[j+1];
|
|
||||||
}
|
|
||||||
apple_num--;
|
|
||||||
goto apple_se;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
apple_se:
|
|
||||||
|
|
||||||
if(apple_found){
|
|
||||||
|
|
||||||
}else{
|
|
||||||
while(get_next_pixel(old_head, dir)){
|
|
||||||
if((dead_cnt++)==4){
|
|
||||||
dead = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
dir = direction_r(dir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!dead){
|
|
||||||
*head = next_pixel(old_head, dir);
|
|
||||||
setpixel(*head, 3);
|
|
||||||
|
|
||||||
if((RANDOM8()&0xff)<80){
|
|
||||||
unsigned char j;
|
|
||||||
unsigned char nextapple=0, distx, disty, shortdist=255, xy=0;
|
|
||||||
if(!apple_num){
|
|
||||||
dir = RANDOM8()%4;
|
|
||||||
}else{
|
|
||||||
for(j=0;j<apple_num;j++){
|
|
||||||
if(head->x > apples[j].x){
|
|
||||||
distx = head->x - apples[j].x;
|
|
||||||
}else{
|
|
||||||
distx = apples[j].x - head->x;
|
|
||||||
}
|
|
||||||
if(head->y > apples[j].y){
|
|
||||||
disty = head->y - apples[j].y;
|
|
||||||
}else{
|
|
||||||
disty = apples[j].y - head->y;
|
|
||||||
}
|
|
||||||
if ((distx + disty) < shortdist){
|
|
||||||
shortdist = distx + disty;
|
|
||||||
nextapple = j;
|
|
||||||
xy = (distx > disty)?1:0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(xy){
|
|
||||||
dir = (apples[nextapple].x > head->x)?left:right;
|
|
||||||
}else{
|
|
||||||
dir = (apples[nextapple].y > head->y)?down:up;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( (apple_num<9) && ((RANDOM8()&0xff)<10) ){
|
|
||||||
pixel new_apple = (pixel){RANDOM8()%NUM_COLS,RANDOM8()%NUM_ROWS};
|
|
||||||
if(!get_pixel(new_apple)){
|
|
||||||
apples[apple_num++]=new_apple;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!apple_found){
|
|
||||||
clearpixel(*tail);
|
|
||||||
if(++tail == pixels + 64) tail = pixels;
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
while(tail != head){
|
|
||||||
clearpixel(*tail);
|
|
||||||
if((++tail)>pixels+64) tail = pixels;
|
|
||||||
wait (60);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(j=0;j<apple_num;j++){
|
|
||||||
if(x%2){
|
|
||||||
setpixel(apples[j], 2);
|
|
||||||
}else{
|
|
||||||
#ifdef CAN_SUPPORT
|
|
||||||
clearpixel(apples[j]);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wait (SNAKE_DELAY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
#ifndef SNAKE_H_
|
#ifndef SNAKE_H_
|
||||||
#define SNAKE_H_
|
#define SNAKE_H_
|
||||||
|
|
||||||
void snake();
|
void snake_animation(void);
|
||||||
void snake_game();
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* SNAKE_H_ */
|
#endif /* SNAKE_H_ */
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "scrolltext/scrolltext.h"
|
#include "scrolltext/scrolltext.h"
|
||||||
|
#include "animations/snake.h"
|
||||||
#include "animations/programm.h"
|
#include "animations/programm.h"
|
||||||
#include "animations/matrix.h"
|
#include "animations/matrix.h"
|
||||||
#include "animations/gameoflife.h"
|
#include "animations/gameoflife.h"
|
||||||
|
@ -76,7 +77,7 @@ void display_loop(){
|
||||||
|
|
||||||
#ifdef ANIMATION_SNAKE
|
#ifdef ANIMATION_SNAKE
|
||||||
case 4:
|
case 4:
|
||||||
snake();
|
snake_animation();
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,12 @@ ifeq ($(GAME_SNAKE),y)
|
||||||
SUBDIRS += games/snake
|
SUBDIRS += games/snake
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(ANIMATION_SNAKE),y)
|
||||||
|
ifneq ($(GAME_SNAKE),y)
|
||||||
|
SUBDIRS += games/snake
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(GAME_BREAKOUT),y)
|
ifeq ($(GAME_BREAKOUT),y)
|
||||||
SUBDIRS += games/breakout
|
SUBDIRS += games/breakout
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -1,190 +1,429 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include "../../config.h"
|
#include "../../config.h"
|
||||||
#include "../../compat/pgmspace.h"
|
#include "../../compat/pgmspace.h"
|
||||||
#include "../../menu/menu.h"
|
|
||||||
#include "../../pixel.h"
|
#include "../../pixel.h"
|
||||||
#include "../../random/prng.h"
|
#include "../../random/prng.h"
|
||||||
#include "../../util.h"
|
#include "../../util.h"
|
||||||
#include "../../joystick/joystick.h"
|
#include "../../joystick/joystick.h"
|
||||||
|
#include "../../menu/menu.h"
|
||||||
|
#include "snake_game.h"
|
||||||
|
|
||||||
// if defined, joystick controls are NOT as "seen"
|
#if defined MENU_SUPPORT && defined GAME_SNAKE
|
||||||
// by the snake but absolute, that is, if pressing
|
// snake icon (MSB is leftmost pixel)
|
||||||
// up, snake goes up, etc.
|
|
||||||
#define GAME_SNAKE_NEWCONTROL
|
|
||||||
|
|
||||||
void snake_game();
|
|
||||||
|
|
||||||
#ifdef MENU_SUPPORT
|
|
||||||
// MSB is leftmost pixel
|
|
||||||
static uint8_t icon[8] PROGMEM =
|
static uint8_t icon[8] PROGMEM =
|
||||||
{0xff, 0x81, 0xbd, 0xa5, 0xa5, 0xad, 0xa1, 0xbf}; // Snake icon
|
{0xff, 0x81, 0xbd, 0xa5, 0xa5, 0xad, 0xa1, 0xbf};
|
||||||
|
|
||||||
game_descriptor_t snake_game_descriptor __attribute__((section(".game_descriptors"))) =
|
game_descriptor_t snake_game_descriptor __attribute__((section(".game_descriptors"))) =
|
||||||
{&snake_game, icon};
|
{
|
||||||
|
&snake_game,
|
||||||
|
icon,
|
||||||
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void snake_game()
|
|
||||||
|
// If defined, joystick controls are NOT as "seen" by the snake but absolute,
|
||||||
|
// that is, if pressing up, snake goes up, etc.
|
||||||
|
#define SNAKE_NEWCONTROL
|
||||||
|
|
||||||
|
// limits
|
||||||
|
#define SNAKE_MAX_LENGTH 64
|
||||||
|
#define SNAKE_MAX_APPLES 10
|
||||||
|
|
||||||
|
// delays (in milliseconds)
|
||||||
|
#define SNAKE_CYCLE_DELAY 100
|
||||||
|
#define SNAKE_TERMINATION_DELAY 60
|
||||||
|
|
||||||
|
// colors
|
||||||
|
#define SNAKE_COLOR_BORDER 3
|
||||||
|
#define SNAKE_COLOR_PROTAGONIST 3
|
||||||
|
#define SNAKE_COLOR_APPLE 3
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Directions of the snake.
|
||||||
|
*/
|
||||||
|
typedef enum snake_dir
|
||||||
{
|
{
|
||||||
pixel pixels[64] = {{4, NUM_ROWS - 2}, {4, NUM_ROWS - 3}};
|
SNAKE_DIR_UP, //!< SNAKE_DIR_UP Snake is heading up.
|
||||||
pixel *head = &pixels[1];
|
SNAKE_DIR_RIGHT,//!< SNAKE_DIR_RIGHT Snake is heading right.
|
||||||
pixel *tail = &pixels[0];
|
SNAKE_DIR_DOWN, //!< SNAKE_DIR_DOWN Snake is heading down.
|
||||||
pixel old_head;
|
SNAKE_DIR_LEFT, //!< SNAKE_DIR_LEFT Snake is heading left.
|
||||||
|
SNAKE_DIR_NONE //!< SNAKE_DIR_NONE Helper value for a "resting" joystick.
|
||||||
|
} snake_dir_t;
|
||||||
|
|
||||||
pixel apples[10];
|
|
||||||
unsigned char apple_num = 0;
|
|
||||||
direction dir = up;
|
|
||||||
|
|
||||||
clear_screen(0);
|
/**
|
||||||
|
* This structure represents the snake character itself. It keeps track of the
|
||||||
|
* snake's segments, its head and tail and the direction it is heading.
|
||||||
|
*/
|
||||||
|
typedef struct snake_protagonist
|
||||||
|
{
|
||||||
|
pixel aSegments[SNAKE_MAX_LENGTH]; /** All segments of the snake. */
|
||||||
|
uint8_t nHeadIndex; /** Index of the head segment. */
|
||||||
|
uint8_t nTailIndex; /** Index of the tail segment. */
|
||||||
|
snake_dir_t dir; /** Direction of the snake. */
|
||||||
|
} snake_protagonist_t;
|
||||||
|
|
||||||
unsigned char apple_found = 0;
|
|
||||||
unsigned char j;
|
|
||||||
|
|
||||||
unsigned char x, y, dead = 0;
|
/**
|
||||||
uint8_t joy, joy_old = 0xff, joy_cmd = 0xff;
|
* This structure keeps track of all apples which are on the playing field.
|
||||||
|
*/
|
||||||
|
typedef struct snake_apples
|
||||||
|
{
|
||||||
|
pixel aApples[SNAKE_MAX_APPLES]; /** All apple positions */
|
||||||
|
uint8_t nAppleCount; /** Counter of currently existing apples */
|
||||||
|
} snake_apples_t;
|
||||||
|
|
||||||
// zeichne Rahmen
|
|
||||||
for (x = 0; x < NUM_COLS; x++)
|
/**
|
||||||
|
* Moves a pixel to the given direction.
|
||||||
|
* @param pxNext pixel to be moved
|
||||||
|
* @param dir direction
|
||||||
|
*/
|
||||||
|
static pixel snake_applyDirection(pixel pxNext,
|
||||||
|
snake_dir_t dir)
|
||||||
|
{
|
||||||
|
assert(dir < 4);
|
||||||
|
static int8_t const nDelta[] = {0, -1, 0, 1, 0};
|
||||||
|
return (pixel){pxNext.x + nDelta[dir], pxNext.y + nDelta[dir + 1]};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This functions draws a border around the playing field.
|
||||||
|
*/
|
||||||
|
static void snake_drawBorder(void)
|
||||||
|
{
|
||||||
|
#if NUM_COLS == NUM_ROWS
|
||||||
|
for (uint8_t i = NUM_COLS; i--;)
|
||||||
{
|
{
|
||||||
for (y = 0; y < NUM_ROWS; y++)
|
setpixel((pixel){i, 0}, SNAKE_COLOR_BORDER);
|
||||||
{
|
setpixel((pixel){i, NUM_ROWS - 1}, SNAKE_COLOR_BORDER);
|
||||||
if (((x == 0) || (x == NUM_COLS - 1)) || ((y == 0) || (y
|
setpixel((pixel){0, i}, SNAKE_COLOR_BORDER);
|
||||||
== NUM_ROWS - 1)))
|
setpixel((pixel){NUM_COLS -1, i}, SNAKE_COLOR_BORDER);
|
||||||
{
|
|
||||||
setpixel((pixel) {x, y}, 3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
x = 0;
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
x++;
|
|
||||||
old_head = *head;
|
|
||||||
if (++head == pixels + 64)
|
|
||||||
head = pixels;
|
|
||||||
|
|
||||||
#ifdef GAME_SNAKE_NEWCONTROL
|
|
||||||
if (joy_cmd != 0xff)
|
|
||||||
{
|
|
||||||
if ((dir == left && joy_cmd != right) || (dir == right && joy_cmd
|
|
||||||
!= left) || (dir == up && joy_cmd != down) || (dir == down
|
|
||||||
&& joy_cmd != up))
|
|
||||||
dir = joy_cmd;
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (joy_cmd == right)
|
for (uint8_t x = MAX_COLS; x--;)
|
||||||
{
|
{
|
||||||
dir = direction_r(dir);
|
setpixel((pixel){x, 0}, SNAKE_COLOR_BORDER);
|
||||||
joy_cmd = 0xff;
|
setpixel((pixel){x, NUM_ROWS - 1}, SNAKE_COLOR_BORDER);
|
||||||
}
|
}
|
||||||
else if (joy_cmd == left)
|
for (uint8_t y = MAX_ROWS; y--;)
|
||||||
{
|
{
|
||||||
dir = direction_r(dir);
|
setpixel((pixel){0, y}, SNAKE_COLOR_BORDER);
|
||||||
dir = direction_r(dir);
|
setpixel((pixel){NUM_COLS -1, y}, SNAKE_COLOR_BORDER);
|
||||||
dir = direction_r(dir);
|
|
||||||
joy_cmd = 0xff;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// kopf einen weiter bewegen
|
|
||||||
*head = next_pixel(old_head, dir);
|
|
||||||
|
|
||||||
apple_found = 0;
|
/**
|
||||||
|
* Translates port information into directions.
|
||||||
// pr?fen ob man auf nen Apfel drauf ist
|
* @return Current direction of the joystick
|
||||||
for (j = 0; j < apple_num; j++)
|
*/
|
||||||
|
static snake_dir_t snake_queryJoystick(void)
|
||||||
|
{
|
||||||
|
snake_dir_t dirJoystick;
|
||||||
|
if (JOYISUP)
|
||||||
{
|
{
|
||||||
if ((head->x == apples[j].x) && (head->y == apples[j].y))
|
dirJoystick = SNAKE_DIR_UP;
|
||||||
{
|
|
||||||
apple_found = 1;
|
|
||||||
for (; j < apple_num - 1; j++)
|
|
||||||
{
|
|
||||||
apples[j] = apples[j + 1];
|
|
||||||
}
|
|
||||||
apple_num--;
|
|
||||||
goto apple_se;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (get_pixel(*head))
|
|
||||||
{
|
|
||||||
dead = 1;
|
|
||||||
}
|
|
||||||
apple_se:
|
|
||||||
|
|
||||||
if (!dead)
|
|
||||||
{
|
|
||||||
setpixel(*head, 3);
|
|
||||||
|
|
||||||
// setze neue ?pfel
|
|
||||||
if ((apple_num < 9) && (random8() < 10))
|
|
||||||
{
|
|
||||||
pixel new_apple = (pixel) {(random8() % (NUM_COLS-2))+1,
|
|
||||||
(random8() % (NUM_ROWS-2))+1};
|
|
||||||
if (!get_pixel(new_apple))
|
|
||||||
{
|
|
||||||
apples[apple_num++] = new_apple;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// l?sche Ende
|
|
||||||
if (!apple_found && !dead)
|
|
||||||
{
|
|
||||||
clearpixel(*tail);
|
|
||||||
if (++tail == pixels + 64)
|
|
||||||
tail = pixels;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
while (tail != head)
|
|
||||||
{
|
|
||||||
clearpixel(*tail);
|
|
||||||
if ((++tail) > pixels + 64)
|
|
||||||
tail = pixels;
|
|
||||||
wait(60);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (j = 0; j < apple_num; j++)
|
|
||||||
{
|
|
||||||
if (x % 2)
|
|
||||||
{
|
|
||||||
setpixel(apples[j], 3);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
clearpixel(apples[j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (j = 0; j < 20; j++)
|
|
||||||
{
|
|
||||||
if (JOYISLEFT)
|
|
||||||
{
|
|
||||||
joy = left;
|
|
||||||
}
|
}
|
||||||
else if (JOYISRIGHT)
|
else if (JOYISRIGHT)
|
||||||
{
|
{
|
||||||
joy = right;
|
dirJoystick = SNAKE_DIR_RIGHT;
|
||||||
#ifdef GAME_SNAKE_NEWCONTROL
|
|
||||||
}
|
|
||||||
else if (JOYISUP)
|
|
||||||
{
|
|
||||||
joy = up;
|
|
||||||
}
|
}
|
||||||
else if (JOYISDOWN)
|
else if (JOYISDOWN)
|
||||||
{
|
{
|
||||||
joy = down;
|
dirJoystick = SNAKE_DIR_DOWN;
|
||||||
#endif
|
}
|
||||||
|
else if (JOYISLEFT)
|
||||||
|
{
|
||||||
|
dirJoystick = SNAKE_DIR_LEFT;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
joy = 0xff;
|
dirJoystick = SNAKE_DIR_NONE;
|
||||||
}
|
}
|
||||||
if (joy != joy_old)
|
|
||||||
|
return dirJoystick;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the structure which represents the snake itself.
|
||||||
|
* @param pprotSnake The protagonist structure to be initialized.
|
||||||
|
*/
|
||||||
|
static void snake_initGameProtagonist(snake_protagonist_t *pprotSnake)
|
||||||
|
{
|
||||||
|
pprotSnake->aSegments[0] = (pixel){4, NUM_ROWS - 2};
|
||||||
|
pprotSnake->aSegments[1] = (pixel){4, NUM_ROWS - 3};
|
||||||
|
pprotSnake->nTailIndex = 0;
|
||||||
|
pprotSnake->nHeadIndex = 1;
|
||||||
|
pprotSnake->dir = SNAKE_DIR_UP;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef GAME_SNAKE
|
||||||
|
/**
|
||||||
|
* Determines the next direction of the snake depending on joystick input.
|
||||||
|
* @param pprotSnake Protagonist structure to be controlled.
|
||||||
|
* @param pdirLast The last joystick movement to avoid key repeat.
|
||||||
|
*/
|
||||||
|
static void snake_userControl(snake_protagonist_t *pprotSnake,
|
||||||
|
snake_dir_t *pdirLast)
|
||||||
|
{
|
||||||
|
snake_dir_t dirJoystick = snake_queryJoystick();
|
||||||
|
#ifdef SNAKE_NEWCONTROL
|
||||||
|
if (dirJoystick != SNAKE_DIR_NONE)
|
||||||
{
|
{
|
||||||
joy_cmd = joy;
|
// valid transitions can only be uneven
|
||||||
|
if ((pprotSnake->dir + dirJoystick) & 0x01)
|
||||||
|
{
|
||||||
|
pprotSnake->dir = dirJoystick;
|
||||||
}
|
}
|
||||||
joy_old = joy;
|
}
|
||||||
wait(5);
|
#else
|
||||||
|
if ((dirJoystick ^ *pdirLast) && (dirJoystick != SNAKE_DIR_NONE))
|
||||||
|
{ // only left or right movements are valid
|
||||||
|
if (dirJoystick & 0x01)
|
||||||
|
{
|
||||||
|
// rotate through directions (either clockwise or counterclockwise)
|
||||||
|
pprotSnake->dir = (pprotSnake->dir +
|
||||||
|
(dirJoystick == SNAKE_DIR_LEFT ? 3 : 1)) % 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*pdirLast = dirJoystick;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef ANIMATION_SNAKE
|
||||||
|
/**
|
||||||
|
* Approaches directions which may lead to an apple.
|
||||||
|
* @param pprotSnake The hungry protagonist.
|
||||||
|
* @param pApples A bunch of apples.
|
||||||
|
*/
|
||||||
|
static void snake_autoRoute(snake_protagonist_t *pprotSnake,
|
||||||
|
snake_apples_t *pApples)
|
||||||
|
{
|
||||||
|
pixel pxHead = pprotSnake->aSegments[pprotSnake->nHeadIndex];
|
||||||
|
if (random8() < 80)
|
||||||
|
{
|
||||||
|
uint8_t nNextApple = 0;
|
||||||
|
if (pApples->nAppleCount)
|
||||||
|
{
|
||||||
|
uint8_t nMinDist = UINT8_MAX;
|
||||||
|
for (uint8_t i = 0; i < pApples->nAppleCount; ++i)
|
||||||
|
{
|
||||||
|
uint8_t nDistX;
|
||||||
|
if (pxHead.x > pApples->aApples[i].x)
|
||||||
|
{
|
||||||
|
nDistX = pxHead.x - pApples->aApples[i].x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nDistX = pApples->aApples[i].x - pxHead.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t nDistY;
|
||||||
|
if (pxHead.y > pApples->aApples[i].y)
|
||||||
|
{
|
||||||
|
nDistY = pxHead.y - pApples->aApples[i].y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nDistY = pApples->aApples[i].y - pxHead.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((nDistX + nDistY) < nMinDist)
|
||||||
|
{
|
||||||
|
nMinDist = nDistX + nDistY;
|
||||||
|
nNextApple = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pprotSnake->dir ^ 0x01) // vertical direction?
|
||||||
|
{
|
||||||
|
pprotSnake->dir = pApples->aApples[nNextApple].x > pxHead.x ?
|
||||||
|
SNAKE_DIR_LEFT : SNAKE_DIR_RIGHT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pprotSnake->dir = pApples->aApples[nNextApple].y > pxHead.y ?
|
||||||
|
SNAKE_DIR_DOWN : SNAKE_DIR_UP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint8_t i = 4; i--;)
|
||||||
|
{
|
||||||
|
pixel pxTest = snake_applyDirection(pxHead, pprotSnake->dir);
|
||||||
|
if (get_pixel(pxTest))
|
||||||
|
{
|
||||||
|
for (uint8_t j = pApples->nAppleCount; j--;)
|
||||||
|
{
|
||||||
|
if ((pxTest.x == pApples->aApples[j].x) &&
|
||||||
|
(pxTest.y == pApples->aApples[j].y))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pprotSnake->dir = (pprotSnake->dir + 1) % 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Small animation that lets the dying snake disappear.
|
||||||
|
* @param pprotSnake Pointer to the dying snake.
|
||||||
|
*/
|
||||||
|
static void snake_eliminateProtagonist(snake_protagonist_t *pprotSnake)
|
||||||
|
{
|
||||||
|
while (pprotSnake->nTailIndex != pprotSnake->nHeadIndex)
|
||||||
|
{
|
||||||
|
clearpixel(pprotSnake->aSegments[pprotSnake->nTailIndex++]);
|
||||||
|
pprotSnake->nTailIndex %= SNAKE_MAX_LENGTH;
|
||||||
|
wait(SNAKE_TERMINATION_DELAY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the structure that keeps track of all currently existing apples.
|
||||||
|
* @param pApples Pointer to the apples in question.
|
||||||
|
*/
|
||||||
|
static void snake_initApples(snake_apples_t *pApples)
|
||||||
|
{
|
||||||
|
pApples->nAppleCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks for an apple at a given position and removes it if there is one.
|
||||||
|
* @param pApples The set of apples which are one the playing field
|
||||||
|
* @param pxHead The position to be tested.
|
||||||
|
* @return 0 if no apples were found, 1 otherwise
|
||||||
|
*/
|
||||||
|
static uint8_t snake_checkForApple(snake_apples_t *pApples, pixel pxHead)
|
||||||
|
{
|
||||||
|
for (uint8_t i = pApples->nAppleCount; i--;)
|
||||||
|
{
|
||||||
|
if ((pxHead.x == pApples->aApples[i].x) &&
|
||||||
|
(pxHead.y == pApples->aApples[i].y))
|
||||||
|
{
|
||||||
|
for (; i < pApples->nAppleCount; ++i)
|
||||||
|
{
|
||||||
|
pApples->aApples[i] = pApples->aApples[i + 1];
|
||||||
|
}
|
||||||
|
--pApples->nAppleCount;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates some new apples from time to time.
|
||||||
|
* @param pApples Pointer to the apple structure.
|
||||||
|
*/
|
||||||
|
static void snake_spawnApples(snake_apples_t *pApples)
|
||||||
|
{
|
||||||
|
if ((pApples->nAppleCount < SNAKE_MAX_APPLES) && (random8() < 10))
|
||||||
|
{
|
||||||
|
pixel pxApple = (pixel){(random8() % (NUM_COLS-2)) + 1,
|
||||||
|
(random8() % (NUM_ROWS - 2)) + 1};
|
||||||
|
if (!get_pixel(pxApple))
|
||||||
|
{
|
||||||
|
pApples->aApples[pApples->nAppleCount++] = pxApple;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The snake game.
|
||||||
|
*/
|
||||||
|
void snake_engine(uint8_t bDemoMode)
|
||||||
|
{
|
||||||
|
// init
|
||||||
|
snake_protagonist_t protSnake;
|
||||||
|
snake_initGameProtagonist(&protSnake);
|
||||||
|
snake_apples_t apples;
|
||||||
|
snake_initApples(&apples);
|
||||||
|
snake_dir_t dirLast = SNAKE_DIR_NONE;
|
||||||
|
|
||||||
|
// init screen
|
||||||
|
clear_screen(0);
|
||||||
|
snake_drawBorder();
|
||||||
|
|
||||||
|
for (uint8_t nAppleColor = 0; 1; nAppleColor ^= SNAKE_COLOR_APPLE)
|
||||||
|
{
|
||||||
|
// determine new direction
|
||||||
|
#if defined ANIMATION_SNAKE && defined GAME_SNAKE
|
||||||
|
if (bDemoMode)
|
||||||
|
{
|
||||||
|
snake_autoRoute(&protSnake, &apples);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
snake_userControl(&protSnake, &dirLast);
|
||||||
|
}
|
||||||
|
#elif defined ANIMATION_SNAKE
|
||||||
|
snake_autoRoute(&protSnake, &apples);
|
||||||
|
#else
|
||||||
|
snake_userControl(&protSnake, &dirLast);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// actually move head
|
||||||
|
pixel pxOldHead = protSnake.aSegments[protSnake.nHeadIndex];
|
||||||
|
protSnake.nHeadIndex = (protSnake.nHeadIndex + 1) % SNAKE_MAX_LENGTH;
|
||||||
|
protSnake.aSegments[protSnake.nHeadIndex] =
|
||||||
|
snake_applyDirection(pxOldHead, protSnake.dir);
|
||||||
|
|
||||||
|
// look if we have found an apple
|
||||||
|
if (!snake_checkForApple(&apples,
|
||||||
|
protSnake.aSegments[protSnake.nHeadIndex]))
|
||||||
|
{
|
||||||
|
// quit game if we hit something which is not an apple
|
||||||
|
if (get_pixel(protSnake.aSegments[protSnake.nHeadIndex]))
|
||||||
|
{
|
||||||
|
snake_eliminateProtagonist(&protSnake);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove last segment
|
||||||
|
clearpixel(protSnake.aSegments[protSnake.nTailIndex])
|
||||||
|
protSnake.nTailIndex = (protSnake.nTailIndex +1) % SNAKE_MAX_LENGTH;
|
||||||
|
|
||||||
|
// new apples
|
||||||
|
snake_spawnApples(&apples);
|
||||||
|
}
|
||||||
|
// draw new head
|
||||||
|
setpixel(protSnake.aSegments[protSnake.nHeadIndex],
|
||||||
|
SNAKE_COLOR_PROTAGONIST);
|
||||||
|
|
||||||
|
// draw apples
|
||||||
|
for (uint8_t i = apples.nAppleCount; i--;)
|
||||||
|
{
|
||||||
|
setpixel(apples.aApples[i], nAppleColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
wait(SNAKE_CYCLE_DELAY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Snake in game mode.
|
||||||
|
*/
|
||||||
|
void snake_game(void)
|
||||||
|
{
|
||||||
|
snake_engine(0);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
#ifndef SNAKE_GAME_H_
|
||||||
|
#define SNAKE_GAME_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void snake_engine(uint8_t bDemoMode);
|
||||||
|
void snake_game(void);
|
||||||
|
|
||||||
|
#endif /* SNAKE_GAME_H_ */
|
Loading…
Reference in New Issue