一直渴望写一个自己的贪吃蛇游戏,看完国外网友的代码后发现,自己的能力还是不足以“手写”出这样一个属于自己的程序。这段代码存在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);
}
keypad模式:
int keypad(WINDOW *window_ptr, bool keypad_on);
在keypad模式中,curses将接管按键转义序列的处理功能,读键盘操作不仅能够返回用户按下的键,还将返回与逻辑按键相对应的KEY_定义。
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;
6.蛇吃到食物
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;
}
完整程序如下:(编译命令:
)#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;
}
}
}
附一张程序运行图:
------------------------------------------------------------------------------------------------------------------------------
本文还需完善。