int tick() { // Handle user input Direction in = get_direction(); if (in != NO_DIRECTION) { push_move(move_list, in); } // Handle snake movement update_direction(snake, move_list); move_snake(snake); // Draw everything draw_frame(snake, food_list); Collision collision = find_collision(snake, food_list, screen); switch(collision){ case SNAKE: case SCREEN: return 0; case FOOD: grow_snake(); new_food(); break; case NONE: break; } snake_sleep(); return 1; }
void gameloop(int nrow, int ncol) { timeout(1000 / SAMPLING_RATE); const clock_t checkpoint = (clock_t) (CLOCKS_PER_SEC/GAME_SPEED); clock_t last_update = clock(); struct snake * snake = new_snake(ncol/2, nrow/2); struct point food_pos = generate_food(nrow, ncol, snake); redraw(snake, food_pos); for (;;) { struct point tail_pos = snake->tail->pos; int ch; if ((ch = getch()) != ERR) { switch (ch) { case KEY_UP: case KEY_DOWN: case KEY_LEFT: case KEY_RIGHT: if (to_dir(ch) == reverse_dir(snake->heading)) { break; } else { snake->heading = to_dir(ch); step_snake(snake); tail_pos = snake->tail->pos; redraw(snake, food_pos); } break; default: break; } } if (clock() - last_update >= checkpoint) { step_snake(snake); tail_pos = snake->tail->pos; redraw(snake, food_pos); last_update = clock(); } if (point_equal(snake->head->pos, food_pos)) { grow_snake(snake, tail_pos); food_pos = generate_food(nrow, ncol, snake); redraw(snake, food_pos); } if (out_of_border(snake->head->pos, nrow, ncol) || eat_self(snake)) { display_lose(nrow, ncol); return; } if (snake->length == (nrow-2)*(ncol-2)) { display_win(nrow, ncol); return; } } }
void run() { int ch = 0, ich, i, current_columns, current_rows, success = 1; // some variables for the timer (inclusive the interval) struct timespec last_time = {}; struct timespec current_time = {}; long long default_interval = 40000000; long long interval = default_interval; long long res; char playername[HIGHSCORE_NAME_LENGTH] = {}; int range_counter = 0; // create the game struct GAME game = {}; // set the eat range to 1 game.snake.eat_range = 1; // helper variable to keep track of how long we've paused time_t pause_start; // get the dimensions of the terminal and store them in the GAME struct getmaxyx(stdscr, game.rows, game.columns); // clear the whole screen clear(); // draw the walls draw_border(&game); // show the newly created walls refresh(); // place the snake in the middle of the game field grow_snake(&game.snake, game.rows / 2, game.columns / 2); game.snake.dir = DIR_LEFT; // create some fruits on the screen // NOM, NOM, NOM for(i = 0; i < 50; i++) { grow_fruit(&game); } // get the time when the game started time(&game.started); // get the current time current_utc_time(&last_time); // start the event loop while((ich = getch()) && success) { // key typed? if(ich == ERR) { } else if(ich == '0') { // reset the speed interval = default_interval; } else if(ich == '8') { // speed up interval *= 1.1; } else if(ich == '9') { // slow down interval *= 0.9; } else { // use this key as a direction ch = ich; } // check if we have an overrun current_utc_time(¤t_time); // calculate the dirrence between the last snake move and the current time res = timeval_diff(&last_time, ¤t_time); // is the interval over? if(res > interval) { // has an effect on the eat_range ? if(game.snake.eat_range > 1) { // every 200th field, decrease the range range_counter = (range_counter + 1) % 150; // it turns to 0 after the 200th field if(range_counter == 0) { game.snake.eat_range--; // so, decrease it! } } // new direction? if((ch == KEY_UP || ch == 'w') && game.snake.dir != DIR_DOWN) { game.snake.dir = DIR_UP; } else if((ch == KEY_LEFT || ch == 'a') && game.snake.dir != DIR_RIGHT) { game.snake.dir = DIR_LEFT; } else if((ch == KEY_RIGHT || ch == 'd') && game.snake.dir != DIR_LEFT) { game.snake.dir = DIR_RIGHT; } else if((ch == KEY_DOWN || ch == 's') && game.snake.dir != DIR_UP) { game.snake.dir = DIR_DOWN; } // move the snake success = move_snake(&game); // refresh the screen refresh(); // display the status bar (top-right) status_display(&game); // update the time when we last moved the snake last_time = current_time; } getmaxyx(stdscr, current_rows, current_columns); // 'p' pressed || size of the terminal changed if(ich == 'p' || (current_rows != game.rows || current_columns != game.columns)) { // use the terminal new size game.rows = current_rows; game.columns = current_columns; // get the time time(&pause_start); // show the pause dialog switch(pause_dialog()) { case 2: // leave the game if '2' is pressed success = 0; default: // redraw the screen on resume game.paused += time(NULL) - pause_start; redraw_game(&game); break; } } } // get the time when the game has ended time(&game.ended); // display the highscore dialog & let the player enter his name display_highscore(&game, playername, HIGHSCORE_NAME_LENGTH); // has a name been entered? if not don't create a highscore entry if(playername[0]) { add_highscore(playername, game.highscore, game.ended - game.started - game.paused); } // free all the resources reserved in the game struct kill_game(&game); }
// move the snake int move_snake(GAME *game) { int success = 1, i; // some variables containing positions of certain things int curx, cury, tmpy, tmpx; // callbacks to check collisions int (*collision_checks[EVENTS])(GAME*, int, int) = { check_self_collision, check_extended_border_collision, check_fruit_collision }; // callbacks which will be called automaticly if a collision is detected // the callback at position 1 in the array belongs to the check-function // at position 1 from the array above int (*collision_handlers[EVENTS])(GAME*, int, int) = { check_self_collision_handler, check_border_collision_handler, check_fruit_collision_handler }; // difference on x-axis according to the direction int xdiff = game->snake.dir == DIR_LEFT ? -1 : (game->snake.dir == DIR_RIGHT ? 1 : 0); // difference on y-axis according to the direction int ydiff = game->snake.dir == DIR_UP ? -1 : (game->snake.dir == DIR_DOWN ? 1 : 0); // the position of the snake head getbegyx(game->snake.parts[0], cury, curx); // make a copy tmpy = cury; tmpx = curx; // calculate the new position and prevent from exceeding the size of the screen cury = (cury + ydiff) % game->rows; curx = (curx + xdiff) % game->columns; // the values have to be positive cury = cury < 0 ? game->rows + cury : cury; curx = curx < 0 ? game->columns + curx : curx; // check for collisons and execute the handlers if a collision occured for(i = 0; i < EVENTS && success; i++) { // collision? if((collision_checks[i](game, cury, curx))) { // should we end the game because of the collision? if(!collision_handlers[i](game, cury, curx)) { success = 0; } } } // no collisions ? if(success) { // set the direction of the head mvwprintw(game->snake.parts[0], 0, 0, "%c", game->snake.dir); // move the window mvwin(game->snake.parts[0], cury, curx); // copy values back cury = tmpy; curx = tmpx; // iterate through each part of the snake for(i = 1; i < game->snake.length; i++) { // get the position of the current part getbegyx(game->snake.parts[i], tmpy, tmpx); // move the part to the position of the previous one mvwin(game->snake.parts[i], cury, curx); // make a copy cury = tmpy; curx = tmpx; } // grow? if(game->snake.grow > 0) { // grow the snake grow_snake(&game->snake, cury, curx); // decrease the grow counter (number of times the snake will grow in the future) game->snake.grow--; } else { // is the snake head on the same position as the last part of the snake was before? getbegyx(game->snake.parts[0], tmpy, tmpx); if(!(tmpy == cury && tmpx == curx)) { // if no print a space at this position WINDOW *cur = newwin(1, 1, cury, curx); wprintw(cur, "%c", ' '); wrefresh(cur); delwin(cur); } } // redraw the snake on the screen redraw_snake(&game->snake); } else { SDL_LockAudio(); oamlPlaySfx("lose"); SDL_UnlockAudio(); } return success; }