📄 nxsnake.c
字号:
case PLAYGROUND_NIBBLE: draw_tile(TILE_NIBBLE, (x * XUNITSIZE), (y * YUNITSIZE)); /* GrSetGCForeground(gc, BLACK); */ break; }#ifdef NOTUSED GrFillRect(offscreen, gc, (x * XUNITSIZE), (y * YUNITSIZE), XUNITSIZE, YUNITSIZE);#endif#ifdef NOTUSED if (playground[y][x] == PLAYGROUND_NIBBLE && nibble.active) { GR_POINT points[4]; points[0].x = (x * XUNITSIZE) + 1; points[0].y = points[2].y = (y * YUNITSIZE) + 1 + ((YUNITSIZE - 2) / 2); points[1].x = points[3].x = (x * YUNITSIZE) + 1 + ((XUNITSIZE - 2) / 2); points[1].y = (y * YUNITSIZE) + 1; points[2].x = points[0].x + (XUNITSIZE - 2); points[3].y = points[1].y + (YUNITSIZE - 2); GrFillPoly(offscreen, gc, 4, points); } if (playground[y][x] == PLAYGROUND_NIBBLE && nibble.active) { int xpos = (x * XUNITSIZE) + (XUNITSIZE / 2); int ypos = (y * YUNITSIZE) + (YUNITSIZE / 2); GrSetGCForeground(gc, YELLOW); GrFillEllipse(offscreen, gc, xpos, ypos, (XUNITSIZE / 2) - 1, (YUNITSIZE / 2) - 1); }#endif } /* If we have background clear up to the edge, handle that here */ if (bstart != -1) { GrSetGCForeground(gc, BGCOLOR); GrFillRect(offscreen, gc, (bstart * XUNITSIZE), (y * YUNITSIZE), (bend - bstart + 1) * XUNITSIZE, YUNITSIZE); bend = bstart = 0; } } GrDestroyGC(gc);}voiddraw_nibble(void){ /* If there is no nibble assigned, then pick an new spot */ if (!nibble.active) { while (1) { int x = 0 + (int) (rand() % (XUNITS - 1)); int y = 0 + (int) (rand() % (YUNITS - 1)); if (playground[y][x] != PLAYGROUND_EMPTY) continue; if (y > 0 && playground[y - 1][x] != PLAYGROUND_EMPTY) continue; if (y < (YUNITS - 1) && playground[y + 1][x] != PLAYGROUND_EMPTY) continue; if (x > 0 && playground[y][x - 1] != PLAYGROUND_EMPTY) continue; if (x < (XUNITS - 1) && playground[y][x + 1] != PLAYGROUND_EMPTY) continue; /* For now, make sure that the nibble doesn't */ /* show up near the border */ nibble.x = x; nibble.y = y; nibble.active = 1; break; } } playground[nibble.y][nibble.x] = PLAYGROUND_NIBBLE;}voiddraw_border(void){#ifdef NOTUSED int y = 0; /* FIXME: This should be more dynamic, eh? */ /* For now, just a square box */ memset(&playground[0][0], PLAYGROUND_BORDER, XUNITS); memset(&playground[YUNITS - 1][0], PLAYGROUND_BORDER, XUNITS); for (y = 0; y < YUNITS; y++) { playground[y][0] = PLAYGROUND_BORDER; playground[y][XUNITS - 1] = PLAYGROUND_BORDER; }#endif memcpy(playground, level[current_level].bitmap, XUNITS * YUNITS);}/* This just draws the snake into the matrix *//* draw_playground() actually puts it on the screen */voiddraw_snake(void){ int i = 0; int sx = global_snake.headx; int sy = global_snake.heady; int ex = 0; int ey = 0; int pos = 0; while (global_snake.body[pos]) { unsigned char dir = GET_SNAKE_DIRECTION(global_snake.body[pos]); unsigned short off = GET_SNAKE_OFFSET(global_snake.body[pos]); switch (dir) { case SNAKE_DIR_RIGHT: if (sx - off < 0) { int remainder; /* Split the line */ memset(&playground[sy][0], PLAYGROUND_SNAKE, sx); remainder = off - sx - 1; memset(&playground[sy][XUNITS - remainder], PLAYGROUND_SNAKE, remainder); ex = XUNITS - 1 - remainder; } else { /* We can just memset the line, because it goes horizontal */ memset(&playground[sy][sx - off], PLAYGROUND_SNAKE, off); ex = sx - off; } ey = sy; break; case SNAKE_DIR_LEFT: if (sx + off > (XUNITS - 1)) { int remainder; /* Split the line */ memset(&playground[sy][sx], PLAYGROUND_SNAKE, XUNITS - sx); remainder = off - ((XUNITS - 1) - sx) - 1; memset(&playground[sy][0], PLAYGROUND_SNAKE, remainder); ex = remainder; } else { /* We can just memset the line, because it goes horizontal */ memset(&playground[sy][sx], PLAYGROUND_SNAKE, off); ex = sx + off; } ey = sy; break; case SNAKE_DIR_DOWN: ex = sx; if (sy - off < 0) { int remainder; remainder = off - sy - 1; ey = YUNITS - 1 - remainder; for (i = 0; i <= sy; i++) playground[i][sx] = PLAYGROUND_SNAKE; for (i = ey; i <= YUNITS - 1; i++) playground[i][sx] = PLAYGROUND_SNAKE; } else { ey = sy - off; for (i = ey; i <= sy; i++) playground[i][sx] = PLAYGROUND_SNAKE; } break; case SNAKE_DIR_UP: ex = sx; if (sy + off > (YUNITS - 1)) { int remainder; for (i = sy; i <= YUNITS - 1; i++) playground[i][sx] = PLAYGROUND_SNAKE; remainder = off - ((YUNITS - 1) - sy) - 1; for (i = 0; i <= remainder; i++) playground[i][sx] = PLAYGROUND_SNAKE; ey = remainder; } else { ey = sy + off; for (i = sy; i <= ey; i++) playground[i][sx] = PLAYGROUND_SNAKE; } break; } sx = ex; sy = ey; pos++; }}voiddraw_score(void){ int tw, th, tb; char text[100]; GR_GC_ID gc = GrNewGC(); GR_FONT_ID font = GrCreateFont((GR_CHAR *) GR_FONT_GUI_VAR, 0, 0); GrSetGCForeground(gc, BGCOLOR); GrFillRect(offscreen, gc, 0, PHEIGHT + 1, WWIDTH, WHEIGHT - PHEIGHT); GrSetGCFont(gc, font); GrSetGCBackground(gc, BGCOLOR); GrSetGCForeground(gc, TXTCOLOR); sprintf(text, "Level: %d", current_level + 1); GrGetGCTextSize(gc, text, -1, GR_TFTOP, &tw, &th, &tb); GrText(offscreen, gc, 10, PHEIGHT + ((WHEIGHT - PHEIGHT) / 2) - (th / 2), text, -1, GR_TFTOP); sprintf(text, "Snakes: %d", global_snake.lives); GrGetGCTextSize(gc, text, -1, GR_TFTOP, &tw, &th, &tb); GrText(offscreen, gc, (WWIDTH / 2) - (tw / 2), PHEIGHT + ((WHEIGHT - PHEIGHT) / 2) - (th / 2), text, -1, GR_TFTOP); sprintf(text, "Score: %d", global_snake.score); GrGetGCTextSize(gc, text, -1, GR_TFTOP, &tw, &th, &tb); GrText(offscreen, gc, (WWIDTH - 10 - tw), PHEIGHT + ((WHEIGHT - PHEIGHT) / 2) - (th / 2), text, -1, GR_TFTOP); GrDestroyFont(font); GrDestroyGC(gc);}voiddo_frame(int full){ /* Clear it out */ memset(playground, PLAYGROUND_EMPTY, XUNITS * YUNITS); /* Fill the matrix */ draw_border(); draw_snake(); draw_nibble(); /* Only draw the score if we need to */ /* draw_score(); */ /* Draw it to the offscreen buffer */ draw_screen(full); /* And finally, show it on the screen */ show_buffer(); if (draw_fullscreen) draw_fullscreen = 0;}voidstart_level(int l){ init_level(l); /* Initalize the snake */ game_state = SNAKE_PLAYING; nibble.active = 0; nibble.x = 0; nibble.y = 0; /* Construct a clip mask to avoid drawing the border so many times */ make_clipmask(l); /* Set us up to draw the full screen at least once */ draw_fullscreen = 1; draw_score();}voidstart_game(void){ srand(time(0)); current_level = 0; global_snake.lives = 3; global_snake.score = 0; game_speed = start_speed; start_level(current_level); draw_score(); do_frame(1);}voidend_game(void){ game_state = SNAKE_DONE; /* draw_score(); */ draw_string((char *) welcome, 1); show_buffer();}voiddo_snake_advance(void){ switch (advance_snake()) { case MOVE_LEGAL: do_frame(0); break; case MOVE_NIBBLE: if ((global_snake.score % LEVEL_SCORE) == 0) { current_level++; game_state = SNAKE_NEXTLEVEL; draw_string((char *) nextlevel, 2); show_buffer(); } else { draw_score(); } break; case MOVE_ILLEGAL: global_snake.lives--; if (!global_snake.lives) end_game(); else { game_state = SNAKE_NEXTLEVEL; draw_string((char *) snakedied, 2); show_buffer(); } break; }}voidhandle_event(GR_EVENT * event){ switch (event->type) { case GR_EVENT_TYPE_KEY_DOWN: /* Allow Q to quit no matter where we are */ if (event->keystroke.ch == 'Q' || event->keystroke.ch == 'q') { GrClose(); exit(0); } switch (game_state) { case SNAKE_START: case SNAKE_INSTRUCTIONS: case SNAKE_DONE: switch (event->keystroke.ch) { case 'I': case 'i': case MWKEY_APP1: if (game_state != SNAKE_INSTRUCTIONS) { game_state = SNAKE_INSTRUCTIONS; draw_string((char *) instructions, 1); show_buffer(); break; } default: start_game(); break; } break; case SNAKE_PAUSED: if (event->keystroke.ch == 'p' || event->keystroke.ch == 'P') { draw_score(); do_frame(1); game_state = SNAKE_PLAYING; } break; case SNAKE_NEXTLEVEL: if (current_level >= LEVELCOUNT) current_level = 0; start_level(current_level); draw_score(); do_frame(1); /* and show the first frame */ break; case SNAKE_PLAYING: if (event->keystroke.ch == 'p' || event->keystroke.ch == 'P' || event->keystroke.ch == MWKEY_RECORD) { game_state = SNAKE_PAUSED; break; } if (redirect_snake(event->keystroke)) do_snake_advance(); break; } break; case GR_EVENT_TYPE_EXPOSURE: show_buffer(); break; }}voidhandle_idle(){ switch (game_state) { case SNAKE_START: case SNAKE_INSTRUCTIONS: case SNAKE_DONE: case SNAKE_NEXTLEVEL: case SNAKE_PAUSED: /* nothing to do here */ break; case SNAKE_PLAYING: do_snake_advance(); break; }}intmain(int argc, char **argv){ extern char *optarg; while (1) { signed char c = getopt(argc, argv, "s::"); if (c == -1) break; if (c == 's') { start_speed = atoi(optarg); game_speed = start_speed; printf("Setting the start speed to %ld\n", start_speed); } } if (GrOpen() < 0) exit(-1); load_tileset("snake.xpm"); game_state = SNAKE_START; /* Make the window */ swindow = GrNewWindowEx(WM_PROPS, "Pixil Snake", GR_ROOT_WINDOW_ID, 0, 0, WWIDTH, WHEIGHT, BGCOLOR); GrSelectEvents(swindow, GR_EVENT_MASK_EXPOSURE | GR_EVENT_MASK_CLOSE_REQ | GR_EVENT_MASK_KEY_DOWN); offscreen = GrNewPixmap(WWIDTH, WHEIGHT, 0); GrMapWindow(swindow); /* Draw the instructions into the buffer */ draw_string((char *) welcome, 1); while (1) { GR_EVENT event; /* We start at 130ms, but it goes down every */ /* time a nibble is eaten */ /* If they get this far, then they rock! */ if (game_speed < 1) game_speed = 1; GrGetNextEventTimeout(&event, game_speed); switch (event.type) { case GR_EVENT_TYPE_EXPOSURE: case GR_EVENT_TYPE_KEY_DOWN: handle_event(&event); break; case GR_EVENT_TYPE_TIMEOUT: handle_idle(); break; case GR_EVENT_TYPE_CLOSE_REQ: GrClose(); exit(0); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -