window下 纯c 实现 贪吃蛇 小游戏
游戏说明
按方向键上下左右(w a s d),可以实现蛇移动方向的改变。
短时间长按方向键上下左右其中之一,可实现蛇向该方向的短时间加速移动。
按空格键可实现暂停,暂停后按任意键继续游戏。
拥有计分系统
游戏效果展示
游戏实现核心思想
每一块身体都有 属于自己的行为队列 使用 队列数据结构实现
每一块新身体 都会copy 一份前一位身体 的行为队列 并在队列头添加 空行为
实现每一块身体永远比前一位慢一拍 永远执行前一位身体的上一个动作 以此实现 蛇行走位
游戏代码
#include#include #include #include #define mapX 20 #define mapY 20 int map[mapY][mapX]; typedef struct{ int x; int y; }target; typedef struct funNode{ void(*pfun)(struct bodyNode*); struct funNode*next; }shakeMove; typedef struct bodyNode{ int x; int y; shakeMove *pfun_head; shakeMove *pfun_end; struct bodyNode * pnext; }shakebody; inline void MoveUp(shakebody*pbody); inline void MoveDown(shakebody*pbody); inline void MoveLeft(shakebody*pbody); inline void MoveRight(shakebody*pbody); inline void MoveEmpty(shakebody*pbody); shakebody* copylink(const shakebody*pbefore); target tar; int flagUpAndDown =1; int flagLeftAndRight =1; int socre = 0; shakebody shake_head; shakebody *shake_head_p; shakebody *shake_end_p; void(*shake_Now)(struct bodyNode*); int main(void) { srand(time(NULL)); initMap(); initShake(); hideCursor(); createTarget(); while (1) { gotoxy(0,0); DrowShake(); DrowBg(); showSroce(); // MoveUp(&shake_head); // MoveDown(&shake_head); // MoveLeft(&shake_head); // MoveRight(&shake_head); for(int i=0;i<50;i++){ Sleep(10); if(_kbhit()){ char ch1=_getch(); char ch2; switch (ch1) { case 'w': flagUpAndDown?createAndaddShakeMove(&shake_head,MoveUp):NULL;break; case 's': flagUpAndDown?createAndaddShakeMove(&shake_head,MoveDown):NULL;break; case 'a': flagLeftAndRight?createAndaddShakeMove(&shake_head,MoveLeft):NULL;break; case 'd': flagLeftAndRight?createAndaddShakeMove(&shake_head,MoveRight):NULL;break; case ' ': _getch();break; case '1': addShakebody();break; case -32: ch2 = _getch(); switch (ch2) { case 72: createAndaddShakeMove(&shake_head,MoveUp);break; case 80: createAndaddShakeMove(&shake_head,MoveDown);break; case 75: createAndaddShakeMove(&shake_head,MoveLeft);break; case 77: createAndaddShakeMove(&shake_head,MoveRight);break; }break; } runAndrmShakeMove(&shake_head); gotoxy(0,0); DrowShake(); DrowBg(); showSroce(); } } if(shake_Now != NULL){ createAndaddShakeMove(&shake_head,shake_Now); runAndrmShakeMove(&shake_head); } // rmTarget(); } return 0; } void deadAndsorce(shakebody*pbody,int x,int y){ if(map[pbody->y + y][pbody->x + x] == 2){ addShakebody(); rmTarget(); createTarget(); }else if(map[pbody->y + y][pbody->x +x]){ gotoxy(mapX/2,mapY+1); printf("Dead"); Sleep(100000); } } void addShakebody(){ shakebody *p = copylink(shake_end_p); p->pnext = NULL; shake_end_p->pnext = p; shake_end_p = p; shake_end_p->pnext = NULL; } shakebody* copylink(const shakebody*pbefore){ shakebody* p = malloc(sizeof(shakebody)); p->x = pbefore->x; p->y = pbefore->y; if(pbefore->pfun_head ==NULL){ shakeMove *pM = malloc(sizeof(shakeMove)); pM->next = NULL; pM->pfun = MoveEmpty; p->pfun_head =pM; p->pfun_end = p->pfun_head; return p; } shakeMove *pM = malloc(sizeof(shakeMove)); shakeMove *fp = pM; shakeMove *fpcp = pbefore->pfun_head; p->pfun_head = fp; fp->pfun =MoveEmpty; pM = malloc(sizeof(shakeMove)); fp->next = pM; fp = fp->next; fp->pfun =fpcp->pfun; fp->next =NULL; while(fpcp->next!=NULL){ fpcp = fpcp->next; pM = malloc(sizeof(shakeMove)); fp->next = pM; fp = fp->next; fp->next =NULL; fp->pfun =fpcp->pfun; } p->pfun_end = fp; p->pnext =NULL; return p; } void createAndaddShakeMove(shakebody*pbody,void(*pfun)(shakebody*)){ if(pbody->pfun_head == NULL){ shakeMove*p =malloc(sizeof(shakeMove)); p->next=NULL; p->pfun = pfun; pbody->pfun_head = p; pbody->pfun_end = p; }else{ shakeMove*p =malloc(sizeof(shakeMove)); p->next=NULL; p->pfun = pfun; pbody->pfun_end->next = p; pbody->pfun_end = p; } while(pbody->pnext!=NULL){ pbody = pbody->pnext; if(pbody->pfun_head == NULL){ shakeMove*p =malloc(sizeof(shakeMove)); p->next=NULL; p->pfun = pfun; pbody->pfun_head = p; pbody->pfun_end = p; }else{ shakeMove*p =malloc(sizeof(shakeMove)); p->next=NULL; p->pfun = pfun; pbody->pfun_end->next = p; pbody->pfun_end = p; } } return 1; } void runAndrmShakeMove(shakebody*pbody){ if(pbody->pfun_head == NULL){ return; }else{ shakeMove*p = pbody->pfun_head; if(pbody->pfun_head->next == NULL){ pbody->pfun_head->pfun(pbody); shake_Now = pbody->pfun_head->pfun; pbody->pfun_head = NULL; free(p); }else{ pbody->pfun_head->pfun(pbody); shake_Now = pbody->pfun_head->pfun; pbody->pfun_head = pbody->pfun_head->next; free(p); } } while(pbody->pnext!=NULL){ pbody = pbody->pnext; if(pbody->pfun_head == NULL){ return; }else{ shakeMove*p = pbody->pfun_head; if(pbody->pfun_head->next == NULL){ pbody->pfun_head->pfun(pbody); pbody->pfun_head = NULL; free(p); }else{ pbody->pfun_head->pfun(pbody); pbody->pfun_head = pbody->pfun_head->next; free(p); } } } } void MoveRight(shakebody*pbody){ deadAndsorce(pbody,1,0); map[pbody->y][pbody->x] = 0; pbody->x++; if(pbody==shake_head_p){ flagUpAndDown =1; flagLeftAndRight =0; } } void MoveLeft(shakebody*pbody){ deadAndsorce(pbody,-1,0); map[pbody->y][pbody->x] = 0; pbody->x--; if(pbody==shake_head_p){ flagUpAndDown =1; flagLeftAndRight =0; } } void MoveUp(shakebody*pbody){ deadAndsorce(pbody,0,-1); map[pbody->y][pbody->x] = 0; pbody->y--; if(pbody==shake_head_p){ flagUpAndDown =0; flagLeftAndRight =1; } } void MoveDown(shakebody*pbody){ deadAndsorce(pbody,0,1); map[pbody->y][pbody->x] = 0; pbody->y++; if(pbody==shake_head_p){ flagUpAndDown =0; flagLeftAndRight =1; } } void MoveEmpty(shakebody*pbody){ } void DrowShake(shakebody*pbody){ shakebody * p =&shake_head; while (p->pnext!=NULL) { map[p->y][p->x] = 3; p=p->pnext; } map[p->y][p->x] = 3; } void initShake(){ shake_Now = NULL; shake_head.pnext = NULL; shake_head.pfun_head =NULL; shake_head.pfun_end = shake_head.pfun_head; shake_head_p =&shake_head; shake_end_p = shake_head_p; while(1){ shake_head.x = rand()%(mapX-3)+1; shake_head.y = rand()%(mapY-3)+1; if(map[shake_head.y][shake_head.x]==0){ map[shake_head.y][shake_head.x]=3; break; } } } void createTarget(){ while(1){ tar.x = rand()%(mapX-3)+1; tar.y = rand()%(mapY-3)+1; if(map[tar.y][tar.x]==0){ map[tar.y][tar.x]=2; break; } } } void rmTarget(){ socre ++ ; map[tar.y][tar.x]=0; } void showSroce(){ gotoxy(mapX,mapY+1); printf("Score :: %d",socre); } void initMap(){ for(int i=0;i for(int j=0;j if(i==0||j==0||i==mapY-1||j==mapX-1){ map[i][j] =1; } // printf("%d",map[i][j]); } // printf("n"); } } void DrowBg(){ for(int i=0;i for(int j=0;j if(map[i][j]==1){ printf("■"); }else if(map[i][j]==2){ printf("★"); }else if(map[i][j]==3){ printf("■"); } else{ printf(" "); } } printf("n"); } } //printf("★"); //printf("■"); void gotoxy(int x,int y) { //让printf,回到x, y点,x, y是坐标,如果打印位置到原点,x 0,y 0,,gotoxy(0, 0); int z=0x0b; HANDLE hOutput; COORD loc; loc.X = x; loc.Y=y; hOutput = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleCursorPosition(hOutput, loc); } //隐藏光标 void hideCursor() { HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_CURSOR_INFO CursorInfo; GetConsoleCursorInfo(handle, &CursorInfo);//获取控制台光标信息 CursorInfo.bVisible = 0; //隐藏控制台光标 SetConsoleCursorInfo(handle, &CursorInfo);//设置控制台光标状态 }
游戏代码详解
游戏框架构建
首先定义游戏界面的大小,定义游戏区行数和列数。
map 为游戏实际显示区域
#define mapX 20 #define mapY 20 int map[mapY][mapX];
在命令行中对光标和打印位置的一些处理
```c
void gotoxy(int x,int y)
{ //让printf,回到x, y点,x, y是坐标,如果打印位置到原点,x 0,y 0,,gotoxy(0, 0);
int z=0x0b;
HANDLE hOutput;
COORD loc;
loc.X = x; loc.Y=y;
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hOutput, loc);
}
//隐藏光标
void hideCursor()
{
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(handle, &CursorInfo);//获取控制台光标信息
CursorInfo.bVisible = 0; //隐藏控制台光标
SetConsoleCursorInfo(handle, &CursorInfo);//设置控制台光标状态
}
初始化 map,hake和创建目标
void initMap(){
for(int i=0;i
for(int j=0;j
if(i==0||j==0||i==mapY-1||j==mapX-1){
map[i][j] =1;
}
// printf("%d",map[i][j]);
}
// printf("n");
}
}
void initShake(){
shake_Now = NULL;
shake_head.pnext = NULL;
shake_head.pfun_head =NULL;
shake_head.pfun_end = shake_head.pfun_head;
shake_head_p =&shake_head;
shake_end_p = shake_head_p;
while(1){
shake_head.x = rand()%(mapX-3)+1;
shake_head.y = rand()%(mapY-3)+1;
if(map[shake_head.y][shake_head.x]==0){
map[shake_head.y][shake_head.x]=3;
break;
}
}
}
void createTarget(){
while(1){
tar.x = rand()%(mapX-3)+1;
tar.y = rand()%(mapY-3)+1;
if(map[tar.y][tar.x]==0){
map[tar.y][tar.x]=2;
break;
}
}
}
shake行为
void MoveRight(shakebody*pbody){
deadAndsorce(pbody,1,0);
map[pbody->y][pbody->x] = 0;
pbody->x++;
if(pbody==shake_head_p){
flagUpAndDown =1;
flagLeftAndRight =0;
}
}
void MoveLeft(shakebody*pbody){
deadAndsorce(pbody,-1,0);
map[pbody->y][pbody->x] = 0;
pbody->x--;
if(pbody==shake_head_p){
flagUpAndDown =1;
flagLeftAndRight =0;
}
}
void MoveUp(shakebody*pbody){
deadAndsorce(pbody,0,-1);
map[pbody->y][pbody->x] = 0;
pbody->y--;
if(pbody==shake_head_p){
flagUpAndDown =0;
flagLeftAndRight =1;
}
}
void MoveDown(shakebody*pbody){
deadAndsorce(pbody,0,1);
map[pbody->y][pbody->x] = 0;
pbody->y++;
if(pbody==shake_head_p){
flagUpAndDown =0;
flagLeftAndRight =1;
}
}
void MoveEmpty(shakebody*pbody){
}
删除与生成新的目标
void createTarget(){
while(1){
tar.x = rand()%(mapX-3)+1;
tar.y = rand()%(mapY-3)+1;
if(map[tar.y][tar.x]==0){
map[tar.y][tar.x]=2;
break;
}
}
}
//移除标记
void rmTarget(){
socre ++ ;
map[tar.y][tar.x]=0;
}
将蛇嵌入 map 中
void DrowShake(shakebody*pbody){
shakebody * p =&shake_head;
while (p->pnext!=NULL) {
map[p->y][p->x] = 3;
p=p->pnext;
}
map[p->y][p->x] = 3;
}
为每个身体行为队列生成与添加行为
void createAndaddShakeMove(shakebody*pbody,void(*pfun)(shakebody*)){
if(pbody->pfun_head == NULL){
shakeMove*p =malloc(sizeof(shakeMove));
p->next=NULL;
p->pfun = pfun;
pbody->pfun_head = p;
pbody->pfun_end = p;
}else{
shakeMove*p =malloc(sizeof(shakeMove));
p->next=NULL;
p->pfun = pfun;
pbody->pfun_end->next = p;
pbody->pfun_end = p;
}
while(pbody->pnext!=NULL){
pbody = pbody->pnext;
if(pbody->pfun_head == NULL){
shakeMove*p =malloc(sizeof(shakeMove));
p->next=NULL;
p->pfun = pfun;
pbody->pfun_head = p;
pbody->pfun_end = p;
}else{
shakeMove*p =malloc(sizeof(shakeMove));
p->next=NULL;
p->pfun = pfun;
pbody->pfun_end->next = p;
pbody->pfun_end = p;
}
}
return 1;
}
运行每个身体的行为队列
void runAndrmShakeMove(shakebody*pbody){
if(pbody->pfun_head == NULL){
return;
}else{
shakeMove*p = pbody->pfun_head;
if(pbody->pfun_head->next == NULL){
pbody->pfun_head->pfun(pbody);
shake_Now = pbody->pfun_head->pfun;
pbody->pfun_head = NULL;
free(p);
}else{
pbody->pfun_head->pfun(pbody);
shake_Now = pbody->pfun_head->pfun;
pbody->pfun_head = pbody->pfun_head->next;
free(p);
}
}
while(pbody->pnext!=NULL){
pbody = pbody->pnext;
if(pbody->pfun_head == NULL){
return;
}else{
shakeMove*p = pbody->pfun_head;
if(pbody->pfun_head->next == NULL){
pbody->pfun_head->pfun(pbody);
pbody->pfun_head = NULL;
free(p);
}else{
pbody->pfun_head->pfun(pbody);
pbody->pfun_head = pbody->pfun_head->next;
free(p);
}
}
}
}
添加新的身体 与copy 前一个身体行为 并在队首添加空行为
//增加新的身体
void addShakebody(){
shakebody *p = copylink(shake_end_p);
p->pnext = NULL;
shake_end_p->pnext = p;
shake_end_p = p;
shake_end_p->pnext = NULL;
}
//为新的身体添加前一个身体的行为
shakebody* copylink(const shakebody*pbefore){
shakebody* p = malloc(sizeof(shakebody));
p->x = pbefore->x;
p->y = pbefore->y;
if(pbefore->pfun_head ==NULL){
shakeMove *pM = malloc(sizeof(shakeMove));
pM->next = NULL;
pM->pfun = MoveEmpty;
p->pfun_head =pM;
p->pfun_end = p->pfun_head;
return p;
}
shakeMove *pM = malloc(sizeof(shakeMove));
shakeMove *fp = pM;
shakeMove *fpcp = pbefore->pfun_head;
p->pfun_head = fp;
fp->pfun =MoveEmpty;
pM = malloc(sizeof(shakeMove));
fp->next = pM;
fp = fp->next;
fp->pfun =fpcp->pfun;
fp->next =NULL;
while(fpcp->next!=NULL){
fpcp = fpcp->next;
pM = malloc(sizeof(shakeMove));
fp->next = pM;
fp = fp->next;
fp->next =NULL;
fp->pfun =fpcp->pfun;
}
p->pfun_end = fp;
p->pnext =NULL;
return p;
}
//添加身体行为
显示得分 与死亡
//死亡与获得分数
void deadAndsorce(shakebody*pbody,int x,int y){
if(map[pbody->y + y][pbody->x + x] == 2){
addShakebody();
rmTarget();
createTarget();
}else if(map[pbody->y + y][pbody->x +x]){
gotoxy(mapX/2,mapY+1);
printf("Dead");
Sleep(100000);
}
}



