本文把游戏区域就行编号,第一行从0到WIDTH-1,…… 到HEIGHT-1 到 WIDTH*HEIGHT-1(二维数组)。并用trace[LEN]数组保存snake移动的轨迹(保存的是数值,数值就能表现出所在的行和列),(trace[0]始终为snake的头部),根据display()函数绘图,延时,在绘图,达到刷新屏幕的效果。
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <time.h>
#include <conio.h>
#define HEIGHT 10
#define WIDTH 10
#define LEN HEIGHT*WIDTH/2
#define SPEED 800
enum moveState{
UP = -1*WIDTH, DOWN = WIDTH, LEFT = -1, RIGHT = 1
};
int x, y; /* rand point */
int trace[LEN] = {0}; /* trace the snake */
moveState ms = UP; /* default UP */
int len = 1; /* snake length */
void display();
void gotoxy(int x, int y);
void automove();
void randpoint();
void gameover();
void keyinput();
int merge();
int main(void)
{
srand(time(0));
x = rand()%WIDTH;
while((y = rand()%HEIGHT) == 0) // y != 0
;
trace[0] = y*WIDTH + x;
display();
randpoint();
while(1){
keyinput();
}
return 0;
}
/* goto (x, y) point oisition */
void gotoxy(int x, int y)
{
HANDLE hOut;
COORD pos={x, y}; // windows API, 光标位置
hOut=GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hOut,pos); // set
//SetConsoleTextAttribute(hOut,0x00|0x05);
}
void display()
{
int i, j;
gotoxy(0,0);
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 0x00|0x05); // API, set color
/* display the bound */
for(i = 0; i < HEIGHT+2; i++){
for(j = 0; j < WIDTH+2; j++){
if(i == 0 || i == HEIGHT+1 || j == 0 || j == WIDTH+1)
printf("□"); /* 2 char */
else
printf(" ");
}
printf("\n");
}
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 0x00|0x06); // API, set color
gotoxy(WIDTH*2+4, HEIGHT/3);
printf("\t ↑ ← ↓ → space");
gotoxy(WIDTH*2+4, HEIGHT/5*3);
printf("\t score: %d", len*100);
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 0x00|0x07); // API, set color
/* display the rand point */
gotoxy(2*x+2, y+1); // include bound
printf("■"); // 2 char
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 0x00|0x02); // API, set color
/* display the snake */
for(i = 0; i < len; i++){
gotoxy(trace[i]%WIDTH*2+2, trace[i]/WIDTH+1);
printf("■");
}
Sleep(SPEED); // delay SPEED ms
}
/* 根据ms的方向进行移位,保存新的路径 */
void automove()
{
int i;
/* shift bit */
for(i = len-1; i > 0; i--){
trace[i] = trace[i-1];
}
trace[i] += ms; /* i = 0 */
}
/* 合并新的随机点 */
int merge()
{
int i;
int temp = y*WIDTH + x;
if(temp == trace[0]){
/* shift bit */
len++;
for(i = len-1; i > 0; i--){
trace[i] = trace[i-1];
}
trace[i] += ms; /* i = 0 */
return 1;
}
return 0;
}
/* born randpoint */
void randpoint()
{
int i;
while(1){
x = rand()%WIDTH;
y = rand()%HEIGHT;
for(i = 0; i < len; i++)
if(y*WIDTH+x == trace[i])
break;
if(i == len)
return;
}
}
void keyinput()
{
int i;
while(!kbhit()){ // no keyboard input
automove();
if(trace[0] < 1 || trace[0] > HEIGHT*WIDTH || trace[0]%WIDTH == WIDTH-1 && ms == LEFT
|| trace[0]%WIDTH == 0 && ms == RIGHT)
gameover();
for(i = 1; i < len; i++)
if(trace[0] == trace[i])
gameover();
if(merge() == 1)
randpoint();
display();
}
int key = getch(); //获取键盘输入
if(key == 27)
exit(0);
else if(key == ' '){ // space for Pause
while(getch() != ' ')
;
}
else if(key == 0xE0){ //方向键会产生2个字符
key = getch();
switch(key){
case 0x48: //up
ms = UP;
break;
case 0x4B: //left
ms = LEFT;
break;
case 0x4D: //right
ms = RIGHT;
break;
case 0x50: //down
ms = DOWN;
break;
}
}
automove();
/* judge out of the bound */
if(trace[0] < 1 || trace[0] > HEIGHT*WIDTH || trace[0]%WIDTH == WIDTH-1 && ms == LEFT
|| trace[0]%WIDTH == 0 && ms == RIGHT)
gameover();
/* judge head touched the body */
for(i = 1; i < len; i++)
if(trace[0] == trace[i])
gameover();
if(merge() == 1)
randpoint();
display();
}
void gameover()
{
gotoxy(WIDTH/2, HEIGHT/2);
printf("you are lost!\n");
gotoxy(0, HEIGHT+2);
exit(0);
}