Blame example/snake.c

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