栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

从零开始的c语言之旅 (1) 贪吃蛇

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

从零开始的c语言之旅 (1) 贪吃蛇


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);
    }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1018071.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号