一直渴望写一个自己的贪吃蛇游戏,看完国外网友的代码后发现,自己的能力还是不足以“手写”出这样一个属于自己的程序。这段代码存在github上已经3周了,尽管我想等自己完全能够手写出自己的程序,但却还是不想把这篇早该完成的博客留在明年。
这里要用到cursers库以管理基于文本的屏幕(http://heather.cs.ucdavis.edu/~matloff/UnixAndC/CLanguage/Curses.pdf)
1.各项初始化工作:
void init() { initscr();//屏幕控制初始化,如果成功,返回一个只想stdscr结构的指针 raw(); //关闭特殊字符的处理 noecho();//关闭输入字符的回显功能 keypad(stdscr, TRUE); curs_set(0); nodelay(stdscr, TRUE); }
int keypad(WINDOW *window_ptr, bool keypad_on);
2.用结构体表示snack和food:
struct Snack { int x[100]; int y[100]; int node; int life; int direction; } snack;
struct Food { int X, Y; int set; } food;
3.打印出snack和food:
void draw() { snack.x[0] = 6; snack.y[0] = 3; snack.x[1] = 5; snack.y[1] = 3; snack.x[2] = 4; snack.y[2] = 3; snack.life = 0; snack.node = 3; snack.direction = 4; food.set = 0; color(); d_e(); for (i = 0; i < snack.node; i++) mvprintw(snack.y[i], snack.x[i], "*"); refresh(); timer = time(NULL); }
mvprintw()函数:
int myprintw(int y, int x, char *format, ...)在指定的位置打印(x,y)字符串format. 随机生成food:
if (food.set == 0) { food.X = rand() % 50; while (food.X == 0 || food.X == 49) food.X = rand() % 50; food.Y = rand() % 20; while (food.Y == 0 || food.Y == 19) food.Y = rand() % 20; food.set = 1; }
4.打印四面墙
void color() { start_color(); init_pair(1, COLOR_GREEN, COLOR_RED); attron(COLOR_PAIR(1)); for (i = 0; i < 50; i++) mvaddch(0, i, '*'); for (i = 0; i < 20; i++) mvaddch(i, 0, '*'); for (i = 49; i >= 0; i--) mvaddch(19, i, '*'); for (i = 19; i >= 0; i--) mvaddch(i, 49, '*'); //box(stdscr,'*','*'); attroff(COLOR_PAIR(1)); }
start_color()函数对curses的颜色例程进行初始化
init_pair()函数对准备使用的颜色组合进行初始化
attron()函数在不影响其他属性的前提下启用制定的属性
5.判断前进方向:
void judge() { if (snack.direction == 1) //up snack.y[0]--; else if (snack.direction == 2)//down snack.y[0]++; else if (snack.direction == 3)//left snack.x[0]--; else //right snack.x[0]++; }
ch = getch(); switch (ch) { case (KEY_UP): if (snack.direction == 3 || snack.direction == 4) { snack.y[0]--; snack.direction = 1; } else if (snack.direction == 1) snack.y[0]--; else snack.y[0]++; break; case (KEY_DOWN): if (snack.direction == 3 || snack.direction == 4) { snack.y[0]++; snack.direction = 2; } else if (snack.direction == 1) snack.y[0]--; else snack.y[0]++; break; case (KEY_LEFT): if (snack.direction == 1 || snack.direction == 2) { snack.x[0]--; snack.direction = 3; } else if (snack.direction == 3) snack.x[0]--; else snack.x[0]++; break; case (KEY_RIGHT): if (snack.direction == 1 || snack.direction == 2) { snack.x[0]++; snack.direction = 4; } else if (snack.direction == 3) snack.x[0]--; else snack.x[0]++; break;
if (snack.x[0] == food.X && snack.y[0] == food.Y) { food.set = 0; snack.node++; score += 10; for (i = snack.node - 1; i > 0; i--) { snack.x[i] = snack.x[i - 1]; snack.y[i] = snack.y[i - 1]; } judge(); }
7.游戏结束的判断
if ((snack.x[0] == snack.x[i] && snack.y[0] == snack.y[i]) || snack.x[0] == 0 || snack.y[0] == 0 || snack.x[0] == 49 || snack.y[0] == 19) { for (i = 1; i < snack.node; i++) { snack.x[i - 1] = snack.x[i]; snack.y[i - 1] = snack.y[i]; } snack.y[snack.node - 1] = tem[0]; snack.x[snack.node - 1] = tem[1]; for (i = 0; i < snack.node; i++) mvprintw(snack.y[i], snack.x[i], "*"); mvaddch(food.Y, food.X, '*'); start_attr(); mvprintw(10, 10, "You lose!"); mvprintw(11, 10, "Do you want again?(y/n)"); output(); snack.life = 1; //sleep(1); break; }
完整程序如下:(编译命令:gcc snack.c -lcurses -o snack)
#include<curses.h> #include<stdlib.h> #include<unistd.h> #include<time.h> struct Snack { int x[100], y[100]; int node; int life; int direction; } snack; struct Food { int X, Y; int set; } food; struct timespec delay; struct timespec dummy; time_t timer; int TIME = 0; long Time, Time1 = 0, Time2 = 0; int ptime[100]; int score = 0; int i, tem[2], k = 0; void color(); void init(); void draw(); void start_attr(); void output(); void play(); void judge(); int pause_time(int, int *); void d_e(); int main(int argc, char **argv) { init(); draw(); play(); return 0; } void d_e() { int location = 18; int ch2 = KEY_LEFT, which = 0; char str[2][5] = { "Easy", "Hard" }; while (ch2 != '\n') { switch (ch2) { case (KEY_LEFT): if (location != 18) { location -= 10; which = 0; } break; case (KEY_RIGHT): if (location == 18) { location += 10; which = 1; } break; } mvprintw(8, 10, "Please choose the difficulty!"); mvprintw(10, 23, "^_^"); mvprintw(12, 18, "Easy"); mvprintw(12, 28, "Hard"); attron(A_REVERSE); mvprintw(12, location, "%s", str[which]); attroff(A_REVERSE); refresh(); ch2 = getch(); } /*Time2=time(NULL); ptime[k]=Time2-Time1; k++; */ if (location == 28) delay.tv_nsec = 100000000; else delay.tv_nsec = 200000000; } int pause_time(int k, int *PTIME) { int j; int sum = 0; for (j = 0; j < k; j++) sum = sum + ptime[j]; return sum; } void judge() { if (snack.direction == 1) snack.y[0]--; else if (snack.direction == 2) snack.y[0]++; else if (snack.direction == 3) snack.x[0]--; else snack.x[0]++; } void color() { start_color(); init_pair(1, COLOR_GREEN, COLOR_RED); attron(COLOR_PAIR(1)); for (i = 0; i < 50; i++) mvaddch(0, i, '*'); for (i = 0; i < 20; i++) mvaddch(i, 0, '*'); for (i = 49; i >= 0; i--) mvaddch(19, i, '*'); for (i = 19; i >= 0; i--) mvaddch(i, 49, '*'); //box(stdscr,'*','*'); attroff(COLOR_PAIR(1)); } void init() { initscr(); raw(); noecho(); keypad(stdscr, TRUE); curs_set(0); nodelay(stdscr, TRUE); } void draw() { snack.x[0] = 6; snack.y[0] = 3; snack.x[1] = 5; snack.y[1] = 3; snack.x[2] = 4; snack.y[2] = 3; snack.life = 0; snack.node = 3; snack.direction = 4; food.set = 0; color(); d_e(); for (i = 0; i < snack.node; i++) mvprintw(snack.y[i], snack.x[i], "*"); refresh(); timer = time(NULL); } void output() { color(); mvprintw(20, 0, "Score=%d", score); mvprintw(20, 43, "Node=%d", snack.node); mvprintw(21, 0, "Time=%ds", TIME); attroff(A_REVERSE); refresh(); } void start_attr() { attron(A_REVERSE); } void play() { while (1) { Time = time(NULL); TIME = Time - timer - pause_time(k, ptime); clear(); if (food.set == 0) { food.X = rand() % 50; while (food.X == 0 || food.X == 49) food.X = rand() % 50; food.Y = rand() % 20; while (food.Y == 0 || food.Y == 19) food.Y = rand() % 20; food.set = 1; } tem[0] = snack.y[snack.node - 1]; tem[1] = snack.x[snack.node - 1]; for (i = snack.node - 1; i > 0; i--) { snack.x[i] = snack.x[i - 1]; snack.y[i] = snack.y[i - 1]; } int ch = 0; ch = getch(); switch (ch) { case (KEY_UP): if (snack.direction == 3 || snack.direction == 4) { snack.y[0]--; snack.direction = 1; } else if (snack.direction == 1) snack.y[0]--; else snack.y[0]++; break; case (KEY_DOWN): if (snack.direction == 3 || snack.direction == 4) { snack.y[0]++; snack.direction = 2; } else if (snack.direction == 1) snack.y[0]--; else snack.y[0]++; break; case (KEY_LEFT): if (snack.direction == 1 || snack.direction == 2) { snack.x[0]--; snack.direction = 3; } else if (snack.direction == 3) snack.x[0]--; else snack.x[0]++; break; case (KEY_RIGHT): if (snack.direction == 1 || snack.direction == 2) { snack.x[0]++; snack.direction = 4; } else if (snack.direction == 3) snack.x[0]--; else snack.x[0]++; break; case 'p': case 'P': Time1 = time(NULL); judge(); for (i = 0; i < snack.node; i++) mvprintw(snack.y[i], snack.x[i], "*"); mvaddch(food.Y, food.X, '*'); start_attr(); mvprintw(9, 10, "Pause!Press 'p' to continue!"); output(); while (getch() != 'p') ; Time2 = time(NULL); ptime[k] = Time2 - Time1; k++; break; case 'q': case 'Q': Time1 = time(NULL); judge(); for (i = 0; i < snack.node; i++) mvprintw(snack.y[i], snack.x[i], "*"); mvaddch(food.Y, food.X, '*'); start_attr(); mvprintw(10, 22, "Quit!"); output(); int location = 18; int ch2 = KEY_LEFT, which = 0; char str[2][5] = { "No", "Yes" }; while (ch2 != '\n') { switch (ch2) { case (KEY_LEFT): if (location != 18) { location -= 10; which = 0; } break; case (KEY_RIGHT): if (location == 18) { location += 10; which = 1; } break; } mvprintw(12, 18, "No"); mvprintw(12, 28, "Yes"); attron(A_REVERSE); mvprintw(12, location, "%s", str[which]); attroff(A_REVERSE); refresh(); ch2 = getch(); } Time2 = time(NULL); ptime[k] = Time2 - Time1; k++; if (location == 18) break; else { clear(); endwin(); exit(1); } default: judge(); break; } for (i = 1; i < snack.node; i++) if ((snack.x[0] == snack.x[i] && snack.y[0] == snack.y[i]) || snack.x[0] == 0 || snack.y[0] == 0 || snack.x[0] == 49 || snack.y[0] == 19) { for (i = 1; i < snack.node; i++) { snack.x[i - 1] = snack.x[i]; snack.y[i - 1] = snack.y[i]; } snack.y[snack.node - 1] = tem[0]; snack.x[snack.node - 1] = tem[1]; for (i = 0; i < snack.node; i++) mvprintw(snack.y[i], snack.x[i], "*"); mvaddch(food.Y, food.X, '*'); start_attr(); mvprintw(10, 10, "You lose!"); mvprintw(11, 10, "Do you want again?(y/n)"); output(); snack.life = 1; //sleep(1); break; } if (snack.x[0] == food.X && snack.y[0] == food.Y) { food.set = 0; snack.node++; score += 10; for (i = snack.node - 1; i > 0; i--) { snack.x[i] = snack.x[i - 1]; snack.y[i] = snack.y[i - 1]; } judge(); } if (snack.life == 0) { ; for (i = 0; i < snack.node; i++) mvprintw(snack.y[i], snack.x[i], "*"); //attron(A_INVIS); mvaddch(food.Y, food.X, '*'); //sleep(1); //attroff(A_INVIS); start_attr(); output(); nanosleep(&delay, &dummy); //sleep(2); } else { char ch1; while (ch1 = getch()) if (ch1 == 'y' || ch1 == 'Y') { clear(); for (i = 0; i < snack.node; i++) snack.x[i] = snack.y[i] = -1; TIME = Time1 = Time2 = k = 0; score = 0; draw(); snack.life = 0; break; } else if (ch1 == 'n' || ch1 == 'N') { endwin(); exit(1); } else continue; } } }
附一张程序运行图:
------------------------------------------------------------------------------------------------------------------------------
本文还需完善。