犀哥教你用C写贪吃蛇

一,涉及知识点:
    结构体链表,动态分配内存,键盘输入检测,设置光标。
二,实现逻辑
    1,可以设置光标,就能实现制定位置打印制定符号。
    2,涉及一个结构体,包含两个元素坐标元素和一个结构体指针。
    3,结构体串联形成链表,遍历获取成员坐标,打印符号得到蛇身。
    4,不断的加头,去尾,重新遍历坐标,再打印形成蛇的移动。
    5,食物产生的位置判定,不能越界,也不能与蛇身体重合。
    6,蛇的转向判定,一条规则,不允许倒退。
    7,转向的实现,跟行进方向决定新的关节坐标(当前头的上下左右)
    8,死亡检测,是否头节点坐标是否与墙壁重合,是否与身体其他关节重合。
    9,加速减速,设置刷新休眠时间实现。

pragma comment(lib, “user32.lib”)
上面这句代码不加的话用VS的开发人员命令提示编译时不通过
这里写图片描述

具体这个东西是干嘛的,参考下面这位仁兄的博客:
//http://blog.csdn.net/jiary5201314/article/details/9011203

源码,拿走不谢

#pragma comment(lib, "user32.lib")  //http://blog.csdn.net/jiary5201314/article/details/9011203
#include<stdio.h>
#include<time.h>
#include<windows.h>
#include<stdlib.h>

#define U 1  //上
#define D 2  //下
#define L 3  //左
#define R 4  //右

typedef struct Node
{
    int x;
    int y;
    struct Node *next;
} Node;

Node *head,*food,*index;  //蛇头,食物,游标
void snake_create();      //生成蛇
void wall_create();       //生成墙壁
void Pos(int, int);       //设置光标位置
void game_description();  //游戏说明界面
void snake_move();        //蛇的移动
void game_control();      //游戏控制
void start_game();        //开始游戏
void pause_game();        //暂停游戏
void exit_game();         //退出游戏
void isbitself();         //吃到自己
void isbitwall();         //撞到墙壁
void spawn_food();        //生成食物
int score = 0,            //得分
    add = 10,             //加分
    death_type,           //死亡类型
    direction = R,        //前进方向
    sleeptime = 200;      //正常速度

//设置光标位置
void Pos(int x, int y)
{
    COORD pos;
    HANDLE hOutput;
    pos.X = x;
    pos.Y = y;
    hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(hOutput, pos);
}

//游戏说明界面
void game_description()
{
    Pos(40, 14);
    printf("欢迎进入贪吃蛇游戏!\n\n");
    system("pause");
    system("color 5e");
    system("cls");
    Pos(10, 14);
    printf("您将通过键盘控制蛇的移动: 上↑  下↓  左 ←  右→  加速F1  减速F2  暂停space  退出Esc");
    Pos(10, 15);
    printf("吃到食物身体会变长\n");
    Pos(10, 16);
    printf("撞到身体或墙壁游戏都会结束\n");
    system("pause");
    system("cls");
    wall_create();     //生成墙壁
    snake_create();    //初始化蛇
    spawn_food();      //生成食物
}

//生成墙壁
void wall_create()
{
    int i;
    for (i = 0; i<58; i += 2)//打印上下边框
    {
        Pos(i, 0);
        printf("▓");
        Pos(i, 26);
        printf("▓");
    }
    for (i = 1; i<26; i++)//打印左右边框
    {
        Pos(0, i);
        printf("▓");
        Pos(56, i);
        printf("▓");
    }
    Pos(70, 10);
    printf("当前分数"); 
}

//初始化蛇
void snake_create()
{
    Node *tail;
    int i;
    tail = (Node*)malloc(sizeof(Node));   //从蛇尾开始,头插法,以x,y设定开始的位置
    tail->x = 24;
    tail->y = 5;
    tail->next = NULL;
    for (i = 1; i <= 4; i++)
    {
        head = (Node*)malloc(sizeof(Node));
        head->next = tail;
        head->x = 24 + 2 * i;
        head->y =5;
        tail = head;
    }
    while (tail != NULL)  //从头到为,输出蛇身
    {
        Pos(tail->x, tail->y);
        printf("◆");
        tail = tail->next;
    }
}


//生成食物
void spawn_food()
{
    if (food != NULL)   //避免食物重复生成
    {
        return;
    }
    Node* food_1 = (Node*)malloc(sizeof(Node));
    food_1->x = rand() % 52 + 2;
    food_1->y = rand() % 24 + 1;     //确保食物在蛇的活动范围以内
    while ((food_1->x) % 2 != 0)
    {
        food_1->x = rand() % 50 + 2;
    }
    index = head;
    while (index != NULL)
    {
        if (food_1->x == index->x && food_1->y == index->y)   //如果过食物位置与蛇身重合,就重新生成。
        {
            free(food_1);  //重新生成前记得释放旧的
            spawn_food();
            break;        //不然就相当于递归,下面的代码会导致报错
        }
        index = index->next;
    }
    food = food_1;
    Pos(food->x, food->y);   
    printf("●");
}

//蛇的移动
void snake_move()
{
    isbitwall();
    Node *nexthead = (Node*)malloc(sizeof(Node));
    switch (direction)
    {
    case U:
        nexthead->x = head->x;
        nexthead->y = head->y - 1;   //注意  坐标轴的原点是在命令框的左上角
        break;
    case D:
        nexthead->x = head->x;
        nexthead->y = head->y + 1;
        break;
    case L:
        nexthead->x = head->x - 2;   //我们使用的符号是占三个字节,需要用到两个字宽才能正常显示
        nexthead->y = head->y;
        break;
    case R:
        nexthead->x = head->x + 2;
        nexthead->y = head->y;
        break;
    }
    nexthead->next = head;
    head = nexthead;
    index = head;
    isbitself();
    if (nexthead->x == food->x  && nexthead->y == food->y)   //如果吃到食物就增加一节
    {
        while (index != NULL)
        {
            Pos(index->x,index->y);
            printf("◆");
            index = index->next;
        }
        score += add;
        free(food);
        food = NULL;   //如果吃到食物记得将食物指针赋空   
        spawn_food();
    }
    else   //否则就正常前进
    {
        while (index->next->next != NULL)
        {
            Pos(index->x, index->y);
            printf("◆");
            index = index->next;    
        }   
        Pos(index->next->x, index->next->y);
        printf(" ");    //前进的方式就是不断在头部增加关节,然后删除尾部。
        free(index->next);
        index->next = NULL;
    }
}

//蛇的控制
void game_control()
{
    Pos(64, 15);
    printf("不能穿墙,不能咬到自己\n");
    Pos(64, 16);
    printf("用↑ ↓ ← → 控制蛇的移动.");
    Pos(64, 17);
    printf("F1 为加速,F2 为减速\n");
    Pos(64, 18);
    printf("ESC :退出游戏    space:暂停游戏.");
    direction = R;
    while (1)
    {
        Pos(64, 10);
        printf("得分:%d ", score);
        Pos(64, 11);
        printf("当前食物分值:%d分", add);
        if (GetAsyncKeyState(VK_UP) && direction != D)
        {
            direction = U;
        }
        else if (GetAsyncKeyState(VK_DOWN) && direction != U)
        {
            direction = D;
        }
        else if (GetAsyncKeyState(VK_RIGHT) && direction != L)
        {
            direction = R;
        }
        else if (GetAsyncKeyState(VK_LEFT) && direction != R)
        {
            direction = L;
        }
        else if (GetAsyncKeyState(VK_ESCAPE))
        {
            death_type = 3;
            break;
        }
        else if (GetAsyncKeyState(VK_SPACE))
        {
            pause_game();
        }
        else if (GetAsyncKeyState(VK_F1))   //加速
        {
            if (sleeptime > 50)
            {
                sleeptime -= 30;
                add = add + 2;
                if (sleeptime == 320)
                {
                    add = 2;//防止减到1之后再加回来有错
                }
            }
        }
        else if (GetAsyncKeyState(VK_F2))   //减速
        {
            if (sleeptime<350)
            {
                sleeptime = sleeptime + 30;
                add = add - 2;
                if (sleeptime == 350)
                {
                    add = 1; //保证最低分为1
                }
            }
        }
        Sleep(sleeptime);
        snake_move();
    }
}

//暂停
void pause_game()
{
    while(1)
    {
        Sleep(300);
        if (GetAsyncKeyState(VK_SPACE))
        {
            break;
        }
    }
}

//是否撞墙
void isbitwall()
{
    if (head->x == 0 || head->x == 56 || head->y == 0 || head->y == 26)
    {
        death_type = 1;
        exit_game();
    }
}

//是否吃到自己
void isbitself()
{
    Node *self = head->next;  //拿除头部以外的关节跟头关节对比
    while (self != NULL)
    {
        if (self->x == head->x && self->y == head->y)  
        {
            death_type = 2;
            exit_game();
        }
        self = self->next;
    }
}

//退出游戏
void exit_game()
{
    system("cls");
    Pos(24, 12);
    if (death_type == 1)
    {
        printf("对不起,您撞到墙了。游戏结束.");
    }
    else if (death_type == 2)
    {
        printf("对不起,您咬到自己了。游戏结束.");
    }
    else if (death_type == 3)
    {
        printf("您已经结束了游戏。");
    }
    Pos(24, 13);
    printf("您的得分是%d\n", score);
    getchar();
    exit(0);
}

//主函数
void main()
{
    system("title ★★贪吃蛇★★");   //改变命令窗口名字
    system("mode con cols=100 lines=30");   //调整命令窗口的大小
    game_description();
    game_control();
    system("pause");
}

运行效果截图:

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

#include <stdio.h> #include <windows.h> #include <conio.h> #include <time.h> //游戏窗口 #define FrameX 4 //游戏窗口左上角的X轴坐标 #define FrameY 4 //游戏窗口左上角的Y轴坐标 #define Frame_height 20 //游戏窗口的高度 #define Frame_width 20 //游戏窗口的宽度 //定义全局变量 int i,j; int a[2]; //用于记住蛇尾坐标,其中a[0]、a[1]分别表示横、竖坐标 //声明蛇的结构体 struct Snake { int x[100]; //蛇的横坐标,其中x[0]表示蛇尾的横坐标,x[N-1]表示蛇头的横坐标 int y[100]; //蛇的竖坐标,其中y[0]表示蛇尾的竖坐标,y[N-1]表示蛇头的竖坐标 int count; //蛇吃食物的个数 int length; //蛇的长度 int speed; //蛇的速度 }; //声明食物的结构体 struct Food { int x; //食物的横坐标 int y; //食物的竖坐标 }; /******光标移到指定位置**************************************************************/ void gotoxy(HANDLE hOut, int x, int y) //UNKNOW { COORD pos; pos.X = x; //横坐标 pos.Y = y; //纵坐标 SetConsoleCursorPosition(hOut, pos); } /******设置文本为绿色*****************************************************************/ void Set_TextColor_Green (void) { HANDLE Handle = GetStdHandle(STD_OUTPUT_HANDLE); //UNKNOW SetConsoleTextAttribute(Handle, FOREGROUND_INTENSITY | FOREGROUND_GREEN); //UNKNOW } /******制作游戏窗口******************************************************************/ void make_frame() { HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); //定义显示器句柄变量 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+13); //打印选择菜单 printf("Esc 退出游戏"); gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+15); printf("长按方向键:加速"); gotoxy(hOut,FrameX,FrameY); //打印框角 printf("╔"); gotoxy(hOut,FrameX+2*Frame_width-2,FrameY); printf("╗"); gotoxy(hOut,FrameX,FrameY+Frame_height); printf("╚"); gotoxy(hOut,FrameX+2*Frame_width-2,FrameY+Frame_height); printf("╝"); for(i=2;i<2*Frame_width-2;i+=2) { gotoxy(hOut,FrameX+i,FrameY); printf("═"); //打印上横框 } for(i=2;i<2*Frame_width-2;i+=2) { gotoxy(hOut,FrameX+i,FrameY+Frame_height); printf("═"); //打印下横框 } for(i=1;i<Frame_height;i++) { gotoxy(hOut,FrameX,FrameY+i); printf("║"); //打印左竖框 } for(i=1;i<Frame_height;i++) { gotoxy(hOut,FrameX+2*Frame_width-2,FrameY+i); printf("║"); //打印右竖框 } gotoxy(hOut,FrameX+Frame_width-5,FrameY-2); //打印游戏名称 Set_TextColor_Green (); //设置蛇为绿色 printf("贪吃蛇游戏"); } /******结束菜单*******************************************************************/ void over_game() { system("cls"); printf("\n\n\n\n\n\n\n\n\t\t\t\t游戏结束\n\n\n"); Sleep(2000); getch(); } /******菜单信息***************************************************************/ void print_information(HANDLE hOut,struct Snake *snake,struct Food *food) { gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+1); printf("level : %d",snake->count/5+1); //打印游戏等级 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+3); printf("score : %d",10*snake->count); //打印游戏得分 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+5); printf("eat food : %d",snake->count); //打印产生食物个数 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+7); printf("speed : %dms",snake->speed); //打印游戏速度 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+9); printf("foodX : %d",food->x); //打印食物的横坐标 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+11); printf("foodY : %d",food->y); //打印食物的竖坐标 } /******初始化蛇**********************************************************************/ void init_snake(struct Snake *snake) { snake->x[0]=FrameX+2; //初始化蛇的横坐标 snake->y[0]=FrameY+Frame_height/2; //初始化蛇的竖坐标 snake->speed=300; //初始化蛇的速度为300ms snake->length=3; //初始化蛇的长度为3节 snake->count=0; //初始化蛇吃的个数为0 for(i=1;i<snake->length;i++) {/* 依次得到蛇身、蛇头的坐标 */ snake->x[i]=snake->x[i-1]+2; snake->y[i]=snake->y[i-1]; } } /******移动蛇*************************************************************************/ void move_snake(HANDLE hOut,struct Snake *snake) { gotoxy(hOut,snake->x[0],snake->y[0]); printf(" "); /* 清除蛇尾*/ for(i=1;i<snake->length;i++) {/* 后一节的坐标依次取代前一节的坐标 */ snake->x[i-1]=snake->x[i]; snake->y[i-1]=snake->y[i]; } } /******打印蛇*************************************************************************/ void print_snake(HANDLE hOut,struct Snake *snake) { for(i=0;i<snake->length;i++) { gotoxy(hOut,snake->x[i],snake->y[i]); if(i==0) { printf("○"); //打印蛇尾 } else if(i==snake->length-1) { printf("¤"); //打印蛇头 } else { printf("⊙"); //打印蛇身 } } } /******随机产生食物*******************************************************************/ void get_food(HANDLE hOut,struct Snake *snake,struct Food *food) { srand((unsigned)time(NULL)); //初始化随机数 while(1) {/* 产生食物的条件:1.在游戏窗口内 2.不在蛇的身上 */ food->x = rand() % (Frame_width-1); food->y = rand() % Frame_height; if( food->x==0 || food->y==0 ) { continue; } food->x = 2*food->x + FrameX; //得到食物的横坐标 food->y+=FrameY; //得到食物的竖坐标 for(i=0;i<snake->length;i++) {/* 判断食物是否在蛇的身上,如果在蛇身上,则重新产生;否则,打印蛇身 */ if( food->x==snake->x[i] && food->y==snake->y[i] ) { break; } } if(i==snake->length) { gotoxy(hOut,food->x,food->y); printf("⊙"); break; } } } /******吃食物***************************************************************************/ void eat_food(HANDLE hOut,struct Snake *snake,struct Food *food) { if( snake->x[snake->length-1]==food->x && snake->y[snake->length-1]==food->y ) {/* 如果蛇头位置与食物位置相同,吃食物 */ snake->length++; //吃一个食物,蛇身增长一节 for(i=snake->length-1;i>=1;i--) {/* 蛇后节坐标依次赋值给蛇前一节的坐标,依次得到蛇身及蛇头的坐标 */ snake->x[i]=snake->x[i-1]; snake->y[i]=snake->y[i-1]; } snake->x[0]=a[0]; //得到蛇尾移动前的横坐标 snake->y[0]=a[1]; //得到蛇尾移动前的竖坐标 get_food(hOut,snake,food); //重新产生食物 snake->count++; //食物的个数增1 if( snake->count%5==0 ) {/* 当蛇吃Up_level个食物时,速度加快Up_speed毫秒并且升一级 */ snake->speed-=50; } } } /******穿墙**********************************************************************************/ void through_wall(HANDLE hOut,struct Snake *snake,char ch) { if( ch==72 && snake->y[snake->length-1]==FrameY) { snake->y[snake->length-1] = FrameY+Frame_height-1; //如果蛇在上框且向上移动,穿墙 } if( ch==80 && snake->y[snake->length-1]==FrameY+Frame_height ) { snake->y[snake->length-1] = FrameY+1; //如果蛇在下框且向下移动,穿墙 } if( ch==75 && snake->x[snake->length-1]==FrameX ) { snake->x[snake->length-1] = FrameX+2*Frame_width-4; //如果蛇在左框且向左移动,穿墙 } if( ch==77 && snake->x[snake->length-1]==FrameX+2*Frame_width-2 ) { snake->x[snake->length-1] = FrameX+2; //如果蛇在右框且向右移动,穿墙 } } /******判断蛇是否死**************************************************************************/ int if_die(struct Snake *snake) {/* 当蛇头碰到自身时,蛇死 ,返回值为0 */ for(i=0;i<snake->length-1;i++) { if( snake->x[snake->length-1]==snake->x[i] && snake->y[snake->length-1]==snake->y[i] ) { return 0; } } return 1; } /******开始游戏*******************************************************************************/ void start_game() { unsigned char ch=77; //定义用于接收键盘输入的字符变量 HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); //定义显示器句柄变量 struct Snake s,*snake=&s; //定义蛇的结构体指针并指向蛇的结构体 struct Food f,*food=&f; //定义食物的结构体指针并指向食物的结构体 make_frame(); //制作游戏窗口 init_snake(snake); //初始化蛇 get_food(hOut,snake,food); //随机产生食物 while(1) { print_information(hOut,snake,food); //打印菜单信息 a[0]=snake->x[0]; //记住蛇尾的横坐标 a[1]=snake->y[0]; //记住蛇尾的竖坐标 j=0; if(kbhit()) //unknow {/* 判断是否按下键盘,如果按下,ch接收键盘输入 */ ch=getch(); if(kbhit()) {/* 如果长按键盘,则加速 */ Sleep(20); //unknow j=1; } } switch(ch) { case 72: {/* 向上移动 */ move_snake(hOut,snake); //移动蛇 snake->y[snake->length-1]-=1; //蛇头的竖坐标向上移,即减1 break; } case 80: {/* 向下移动 */ move_snake(hOut,snake); //移动蛇 snake->y[snake->length-1]+=1; //蛇头的竖坐标向下移,即加1 break; } case 75: {/* 向左移动 */ move_snake(hOut,snake); //移动蛇 snake->x[snake->length-1]-=2; //蛇头的横坐标向左移,即减2 break; } case 77: {/* 向右移动 */ move_snake(hOut,snake); //移动蛇 snake->x[snake->length-1]+=2; //蛇头的横坐标向右移,即加2 break; } } through_wall(hOut,snake,ch); //穿墙 eat_food(hOut,snake,food); //吃食物 print_snake(hOut,snake); //打印蛇 if( if_die(snake)==0 || ch==27 || snake->speed==50 ) {/* 游戏结束条件:1.蛇碰到自身 2.按Esc键 3.速度为50ms */ gotoxy(hOut,FrameX+Frame_width-2,FrameY+Frame_height/2-1); printf("Game Over"); Sleep(2000); break; } if(j==0) { Sleep(snake->speed); //延迟时间 } else { Sleep(10); } } } int main() { system("color 0D"); //设置文本为粉红色 start_game(); //开始游戏 over_game(); //结束游戏 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值