Blame example/snake.c

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