Blame snake.c

e4ee97
e4ee97
#include <helianthus.h></helianthus.h>
e4ee97
e4ee97
#define SIZE 32
e4ee97
#define WIDTH 16
e4ee97
#define HEIGHT 16
e4ee97
#define MAXLEN (WIDTH*HEIGHT+1)
e4ee97
#define MAXFOOD 5
e4ee97
#define FRAMERATE 24
e4ee97
e4ee97
e4ee97
enum TileType {
e4ee97
  NONE,
e4ee97
  WALL,
e4ee97
  FOOD,
e4ee97
  SNAKE
e4ee97
};
e4ee97
e4ee97
enum GameMode {
e4ee97
  MENU,
e4ee97
  START,
e4ee97
  PLAY,
e4ee97
  GAMEOVER
e4ee97
};
e4ee97
e4ee97
e4ee97
int grid[WIDTH][HEIGHT];
e4ee97
Sprite sprites[WIDTH][HEIGHT];
348218
Group gridGroup;
e4ee97
e4ee97
Sound nom, cut;
e4ee97
e4ee97
int snake[MAXLEN][2];
e4ee97
int len;
e4ee97
int foodCount;
e4ee97
int dx, dy;
e4ee97
int framesRemain;
e4ee97
e4ee97
int optStop;
e4ee97
int optCut;
e4ee97
double optWalls;
e4ee97
int optStepFrames;
e4ee97
e4ee97
int difficulty;
e4ee97
e4ee97
int mode;
e4ee97
7effb5
Animation tileWall;
7effb5
Animation tileFood;
7effb5
Animation tileHead;
7effb5
Animation tileBody;
7effb5
Animation tileBend;
7effb5
Animation tileTail;
7effb5
7effb5
Font font;
e4ee97
e4ee97
e4ee97
void putFood() {
e4ee97
  for(int i = 0; i < 100 && foodCount < MAXFOOD; ++i) {
e4ee97
    int x = randomNumber(0, WIDTH-1);
e4ee97
    int y = randomNumber(0, HEIGHT-1);
e4ee97
    if (grid[x][y] == NONE) {
e4ee97
      grid[x][y] = FOOD;
e4ee97
      spriteSetAnimation(sprites[x][y], tileFood);
e4ee97
      ++foodCount;
e4ee97
    }
e4ee97
  }
e4ee97
}
e4ee97
e4ee97
e4ee97
void setSnakeTile(int i) {
e4ee97
  int x = snake[i][0];
e4ee97
  int y = snake[i][1];
e4ee97
  Sprite s = sprites[x][y];
7effb5
  Animation tile = tileBody;
e4ee97
  double rotation = 0;
e4ee97
e4ee97
  int left   = FALSE;
e4ee97
  int right  = FALSE;
e4ee97
  int top    = FALSE;
e4ee97
  int bottom = FALSE;
e4ee97
  if (i > 0) {
e4ee97
    left   = left   || snake[i-1][0] < x;
e4ee97
    right  = right  || snake[i-1][0] > x;
e4ee97
    top    = top    || snake[i-1][1] < y;
e4ee97
    bottom = bottom || snake[i-1][1] > y;
e4ee97
  }
e4ee97
  if (i < len-1) {
e4ee97
    left   = left   || snake[i+1][0] < x;
e4ee97
    right  = right  || snake[i+1][0] > x;
e4ee97
    top    = top    || snake[i+1][1] < y;
e4ee97
    bottom = bottom || snake[i+1][1] > y;
e4ee97
  }
e4ee97
e4ee97
  if (i == 0) {
e4ee97
    tile = tileHead;
e4ee97
    if (top)    rotation =  90;
e4ee97
    if (bottom) rotation = -90;
e4ee97
    if (right)  rotation = 180;
e4ee97
  } else
e4ee97
  if (i == len-1) {
e4ee97
    tile = tileTail;
e4ee97
    if (top)    rotation = -90;
e4ee97
    if (bottom) rotation =  90;
e4ee97
    if (left)   rotation = 180;
e4ee97
  } else
e4ee97
  if (left && top) {
e4ee97
    tile = tileBend;
e4ee97
    rotation = 180;
e4ee97
  } else
e4ee97
  if (left && bottom) {
e4ee97
    tile = tileBend;
e4ee97
    rotation = 90;
e4ee97
  } else
e4ee97
  if (right && top) {
e4ee97
    tile = tileBend;
e4ee97
    rotation = -90;
e4ee97
  } else
e4ee97
  if (right && bottom) {
e4ee97
    tile = tileBend;
e4ee97
    rotation = 0;
e4ee97
  } else
e4ee97
  if (top) {
e4ee97
    rotation = 90;
e4ee97
  }
e4ee97
e4ee97
  spriteSetAnimation(s, tile);
e4ee97
  spriteSetRotation(s, rotation);
e4ee97
}
e4ee97
e4ee97
e4ee97
void resetTile(int x, int y) {
e4ee97
  grid[x][y] = NONE;
e4ee97
  Sprite s = sprites[x][y];
e4ee97
  spriteSetNoAnimation(s);
e4ee97
  spriteSetRotation(s, 0);
e4ee97
}
e4ee97
e4ee97
e4ee97
void moveSnake() {
e4ee97
  int x = snake[0][0] + dx;
e4ee97
  int y = snake[0][1] + dy;
e4ee97
  int cell = grid[x][y];
e4ee97
e4ee97
  if (cell == WALL) {
e4ee97
    if (!optStop) mode = GAMEOVER;
e4ee97
    dx = snake[0][0] - snake[1][0];
e4ee97
    dy = snake[0][1] - snake[1][1];
e4ee97
    return;
e4ee97
  }
e4ee97
e4ee97
  if (cell == SNAKE) {
e4ee97
    if (!optCut) { mode = GAMEOVER; return; }
e4ee97
    int prevLen = len;
e4ee97
    for(int i = 0; i < len; ++i)
e4ee97
      if (snake[i][0] == x && snake[i][1] == y)
e4ee97
        { len=i; setSnakeTile(len-1); break; }
e4ee97
    for(int i = len; i < prevLen; ++i)
e4ee97
      resetTile(snake[i][0], snake[i][1]);
e4ee97
    soundPlay(cut, FALSE);
e4ee97
  }
e4ee97
e4ee97
  if (cell != NONE && cell != FOOD && cell != SNAKE)
e4ee97
    { mode = GAMEOVER; return; }
e4ee97
e4ee97
  for(int i = len; i > 0; --i) {
e4ee97
    snake[i][0] = snake[i-1][0];
e4ee97
    snake[i][1] = snake[i-1][1];
e4ee97
  }
e4ee97
  snake[0][0] = x;
e4ee97
  snake[0][1] = y;
e4ee97
e4ee97
  if (cell == FOOD || cell == SNAKE) {
e4ee97
    grid[x][y] = SNAKE;
e4ee97
    ++len;
e4ee97
    setSnakeTile(0);
e4ee97
    setSnakeTile(1);
e4ee97
  } else {
e4ee97
    grid[x][y] = SNAKE;
e4ee97
    setSnakeTile(0);
e4ee97
    setSnakeTile(1);
e4ee97
    setSnakeTile(len-1);
e4ee97
    resetTile(snake[len][0], snake[len][1]);
e4ee97
  }
e4ee97
e4ee97
  if (cell == FOOD) {
e4ee97
    --foodCount;
e4ee97
    soundPlay(nom, FALSE);
e4ee97
    putFood();
e4ee97
  }
e4ee97
}
e4ee97
e4ee97
e4ee97
void restart() {
e4ee97
  optStepFrames = 12;
e4ee97
  optWalls = 0;
e4ee97
  optCut = TRUE;
e4ee97
  optStop = TRUE;
e4ee97
  switch(difficulty) {
e4ee97
  case 2:
e4ee97
    optStepFrames = 12;
e4ee97
    optWalls = 0.01;
e4ee97
    break;
e4ee97
  case 3:
e4ee97
    optStepFrames = 10;
e4ee97
    optWalls = 0.02;
e4ee97
    optCut = FALSE;
e4ee97
    break;
e4ee97
  case 4:
e4ee97
    optStepFrames = 8;
e4ee97
    optWalls = 0.04;
e4ee97
    optCut = FALSE;
e4ee97
    optStop = FALSE;
e4ee97
    break;
e4ee97
  case 5:
e4ee97
    optStepFrames = 6;
e4ee97
    optWalls = 0.06;
e4ee97
    optCut = FALSE;
e4ee97
    optStop = FALSE;
e4ee97
    break;
e4ee97
  };
e4ee97
e4ee97
e4ee97
  for(int x = 0; x < WIDTH; ++x) {
e4ee97
    for(int y = 0; y < HEIGHT; ++y) {
e4ee97
      grid[x][y] = NONE;
e4ee97
      Sprite s = sprites[x][y];
e4ee97
      spriteSetRotation(s, 0);
e4ee97
      spriteSetNoAnimation(s);
e4ee97
      if ( x == 0 || y == 0
e4ee97
        || x == WIDTH-1 || y == HEIGHT-1
e4ee97
        || randomFloat() < optWalls )
e4ee97
      {
e4ee97
        grid[x][y] = WALL;
e4ee97
        spriteSetAnimation(s, tileWall);
e4ee97
      }
e4ee97
    }
e4ee97
  }
e4ee97
e4ee97
  len = 2;
e4ee97
  snake[0][0] = WIDTH/2;
e4ee97
  snake[0][1] = HEIGHT/2;
e4ee97
  snake[1][0] = snake[0][0] - 1;
e4ee97
  snake[1][1] = snake[0][1];
e4ee97
  for(int i = 0; i < len; ++i)
e4ee97
    grid[ snake[i][0] ][ snake[i][1] ] = SNAKE;
e4ee97
  for(int i = 0; i < len; ++i)
e4ee97
    setSnakeTile(i);
e4ee97
e4ee97
  dx = 1;
e4ee97
  dy = 0;
e4ee97
e4ee97
  foodCount = 0;
e4ee97
  putFood();
e4ee97
e4ee97
  framesRemain = optStepFrames;
e4ee97
  mode = START;
e4ee97
}
e4ee97
e4ee97
e4ee97
void init() {
7effb5
  tileWall = createAnimation("data/sprite/bricks.png");
7effb5
  tileFood = createAnimation("data/sprite/apple.png");
7effb5
  tileHead = createAnimation("data/sprite/snake/head.png");
7effb5
  tileBody = createAnimation("data/sprite/snake/body.png");
7effb5
  tileBend = createAnimation("data/sprite/snake/bend.png");
7effb5
  tileTail = createAnimation("data/sprite/snake/tail.png");
7effb5
7effb5
  font = createFont("data/fonts/blackcry.ttf");
7effb5
  textFont(font);
e4ee97
e4ee97
  gridGroup = createGroup();
e4ee97
  for(int x = 0; x < WIDTH; ++x) {
e4ee97
    for(int y = 0; y < HEIGHT; ++y) {
348218
      Sprite s = createSprite((x + 0.5)*SIZE, (y + 0.5)*SIZE, SIZE, SIZE);
7effb5
      spriteSetShapeColor(s, colorByName("transparent"));
e4ee97
      groupAdd(gridGroup, s);
e4ee97
      sprites[x][y] = s;
e4ee97
    }
e4ee97
  }
e4ee97
e4ee97
  nom = createSound("data/sound/beep.ogg");
e4ee97
  cut = createSound("data/sound/nom.ogg");
e4ee97
e4ee97
  mode = MENU;
e4ee97
}
e4ee97
e4ee97
e4ee97
void draw() {
ef1455
  double cx = windowGetWidth()/2.0;
ef1455
  double cy = windowGetHeight()/2.0;
e4ee97
e4ee97
  if (mode == PLAY) {
e4ee97
    int prevdx = snake[0][0] - snake[1][0];
e4ee97
    int prevdy = snake[0][1] - snake[1][1];
e4ee97
e4ee97
    if      (keyWentDown("left")  && (prevdx !=  1 || prevdy !=  0)) { dx = -1; dy =  0; framesRemain = 0; }
e4ee97
    else if (keyWentDown("right") && (prevdx != -1 || prevdy !=  0)) { dx =  1; dy =  0; framesRemain = 0; }
e4ee97
    else if (keyWentDown("up")    && (prevdx !=  0 || prevdy !=  1)) { dx =  0; dy = -1; framesRemain = 0; }
e4ee97
    else if (keyWentDown("down")  && (prevdx !=  0 || prevdy != -1)) { dx =  0; dy =  1; framesRemain = 0; }
e4ee97
    if (--framesRemain <= 0) {
e4ee97
      moveSnake();
e4ee97
      framesRemain = optStepFrames;
e4ee97
    }
e4ee97
    drawSprites();
e4ee97
    if (keyWentDown("escape")) mode = MENU;
e4ee97
  } else
e4ee97
  if (mode == GAMEOVER) {
e4ee97
    drawSprites();
e4ee97
7effb5
    fill(colorByRGBA(1, 1, 1, 0.25));
ef1455
    rect(0, 0, windowGetWidth(), windowGetHeight());
e4ee97
7effb5
    noFill();
e4ee97
    textAlign(HALIGN_CENTER, HALIGN_CENTER);
e4ee97
    textSize(24);
ef1455
    text(cx, cy, "Game Over");
e4ee97
    textSize(12);
ef1455
    text(cx, cy + 24, "Game Over");
e4ee97
    if (keyWentDown("return")) mode = MENU;
e4ee97
    if (keyWentDown("escape")) mode = MENU;
e4ee97
  } else
e4ee97
  if (mode == START) {
e4ee97
    drawSprites();
e4ee97
7effb5
    fill(colorByRGBA(1, 1, 1, 0.25));
ef1455
    rect(0, 0, windowGetWidth(), windowGetHeight());
e4ee97
7effb5
    noFill();
e4ee97
    textAlign(HALIGN_CENTER, VALIGN_CENTER);
e4ee97
    textSize(24);
ef1455
    text(cx, cy, "Press enter to start");
e4ee97
    if (keyWentDown("return")) mode = PLAY;
e4ee97
    if (keyWentDown("escape")) mode = MENU;
e4ee97
  } else
e4ee97
  if (mode == MENU) {
7effb5
    noFill();
e4ee97
    textAlign(HALIGN_LEFT, VALIGN_CENTER);
e4ee97
    textSize(24);
e4ee97
    int x = cx - 100;
e4ee97
    int y = cy - 24*3;
ef1455
    text(x, y, "Select difficulty level:"); y += 24;
ef1455
    text(x, y, "1 - very easy"           ); y += 24;
ef1455
    text(x, y, "2 - easy"                ); y += 24;
ef1455
    text(x, y, "3 - medium"              ); y += 24;
ef1455
    text(x, y, "4 - hard"                ); y += 24;
ef1455
    text(x, y, "5 - very hard"           ); y += 24;
e4ee97
    difficulty = 0;
133cca
    if (keyWentDown("any 1")) difficulty = 1;
133cca
    if (keyWentDown("any 2")) difficulty = 2;
133cca
    if (keyWentDown("any 3")) difficulty = 3;
133cca
    if (keyWentDown("any 4")) difficulty = 4;
133cca
    if (keyWentDown("any 5")) difficulty = 5;
e4ee97
    if (difficulty) restart();
ef1455
    if (keyWentDown("escape")) windowStop();
e4ee97
  }
e4ee97
}
e4ee97
e4ee97
int main() {
ef1455
  windowSetTitle("Snake");
ef1455
  windowSetWidth(SIZE * WIDTH);
ef1455
  windowSetHeight(SIZE * HEIGHT);
ef1455
  windowSetFrameRate(FRAMERATE);
ef1455
  windowSetInit(&init);
ef1455
  windowSetDraw(&draw);
ef1455
  windowRun();
2af670
  return 0;
e4ee97
}