C语言版贪吃蛇

#include<stdio.h>

#include<string.h>

#include<windows.h>

#include<time.h>

#include<conio.h>

 

#define up 'w'

#define down 's'

#define left 'a'

#define right 'd'

 

#define bool int

#define true 1

#define false 0

 

void welcome();               // 开始界面

void finish();                // 结束界面

void createGraph();            // 围墙打印

void gotoxy(int x, int y);    // 光标跳转,横为X 0,1,2..

void gotoPrint(int x, int y); // 跳转打印

void gotoDelete(int x, int y);// 跳转删除

void createFood();             // 食物产生

int clickControl();           // 获取键盘信号

int judge();                  // 游戏结束判断

void movingBody();            // 蛇的移动

void eating();                // 蛇吃到东西后的操作(伸长)

void changeBody(int x, int y); // 蛇的坐标变换

 

/*全局变量 + 预处理:*/

typedef struct Snakes

{

    int x;

    int y;

    struct Snakes* next;

}snake;

 

snake* head;    // 声明蛇头指针

 

// 申明并定义食物

struct Food

{

    int x;

    int y;

}food;

 

char name[20];  // 保存用户名 有兴趣可以制作登录系统

int score = 0;  // 分数

char click = 1; // 记录敲下的键盘按键

int speed = 10;      // 速度 其实是延迟的毫秒数

 

void showCopy(){

    system("cls");

printf("\n\n\t*************************欢迎进入游戏世界***************************");

printf("\n\n\t**************************源辰信息版权所有**************************");

}

 

int main()

{

    system("color 0B"); // 设置控制台字体颜色

    welcome();          // 欢迎界面

 

    createGraph();       // 创建地图

    createFood();        // 新建食物

 

    // 捕获鼠标按键 ClickControl

    if (clickControl() == 0) return 0;

 

    return 0;

}

 

// 欢迎界面

void welcome()

{

    showCopy();

    gotoxy(26, 10);

    printf("欢迎来到贪吃蛇游戏");

    gotoxy(14, 14);

    printf("[请在英文输入法中操作,反向移动等同于吃到自己,wasd控制p暂停]");

    gotoxy(26, 18);

    printf("请输入您的昵称:");

 

    HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);

    CONSOLE_CURSOR_INFO cursor; // 获取光标

    cursor.bVisible = TRUE;  // 隐藏光标

    cursor.dwSize = sizeof(cursor);

 

    SetConsoleCursorInfo(hOutput, &cursor); // 显示光标

    scanf("%s", name);

    system("cls");

}

 

// 围墙打印

void createGraph() {

    int i;

    //  注意这里横坐标是每次+2 因为控制台字符宽高比为1:2

    for (i = 0; i < 58; i += 2)

    {

        gotoPrint(i, 0); // 顶部围墙

        gotoPrint(i, 26); // 底部围墙

    }

 

    for (i = 1; i < 26; i++)

    {

        gotoPrint(0, i); // 左边围墙

        gotoPrint(56, i); // 右边围墙

    }

 

    gotoxy(63, 8);

    printf("你好 %s, 欢迎进入游戏世界", name);

    gotoxy(63, 13);

    printf("当前分数:%d", score);

    gotoxy(63, 18);

    printf("源辰信息科技提供");

 

    // 初始化蛇

    head = (snake*)malloc(sizeof(snake)); // 给蛇头申请空间

    snake* p = (snake*)malloc(sizeof(snake)); //  蛇身

    snake* q = (snake*)malloc(sizeof(snake)); // 蛇尾

 

    // 设置蛇头的坐标

    head->x = 16; // 行数

    head->y = 15; // 列数

 

    // 第一节蛇身的坐标

    p->x = 16;

    p->y = 16;

 

    // 第二节蛇身的坐标

    q->x = 16;

    q->y = 17;

 

    head->next = p; // 蛇头的下一个节点是第一节蛇身

    p->next = q; // 第一节蛇身的下一个节点是第二节蛇身

    q->next = NULL; // 第二节蛇身的下一个节点为空

}

 

// 移动光标到指定位置

void gotoxy(int x, int y)

{

    COORD pos; // 更新光标位置

    // GetStdHandle()返回标准的输入、输出或错误的设备的句柄,也就是获得输入、输出/错误的屏幕缓冲区的句柄。

    // STD_INPUT_HANDLE   标准输入的句柄

    // STD_OUTPUT_HANDLE  标准输出的句柄

    // STD_ERROR_HANDLE   标准错误的句柄

    HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);

    pos.X = x;

    pos.Y = y;

 

    SetConsoleCursorPosition(hOutput, pos); // 设置控制台(cmd)光标位置

 

    CONSOLE_CURSOR_INFO cursor; // 获取光标

    cursor.bVisible = FALSE;  // 隐藏光标

    cursor.dwSize = sizeof(cursor);

    SetConsoleCursorInfo(hOutput, &cursor); // 隐藏光标

}

 

// 输出墙砖

void gotoPrint(int x, int y)

{

    gotoxy(x, y);

    printf("■");

}

 

// 删除指定位置的内容

void gotoDelete(int x, int y)

{

    gotoxy(x, y);

    printf("  ");

}

 

// 创建食物

void createFood()

{

    // 随机产生一个食物

    bool flag = false; // 标记食物是否已经吃了

 

    while (!flag) // 如果食物已经吃了

    {

        flag = true;

        // srand函数是随机数发生器的初始化函数

        // time(t) 是指返回自 Unix 纪元(January 1 1970 00:00:00 GMT)起的当前时间的秒数的函数,主要用来获取当前的系统时间,返回的结果是一个time_t类型。

        // 如果t是空指针,直接返回当前时间。如果t不是空指针,返回当前时间的同时,将返回值赋予t指向的内存空间。

        srand((int)time(NULL));

 

        // 随机生成食物的坐标

        food.y = rand() % 25 + 1;

        food.x = rand() % (54 - 1) + 2;

 

        if (food.x % 2 != 0)

        {

            food.x = food.x + 1;

        }

 

        snake* judge = head; // 定义指针judge指向蛇头

       
        // 遍历蛇,保证生成的这个食物不在蛇身上

        while (1)  // 遍历排除蛇身重复

        {

            if (judge->next == NULL) break; // 说明遍历结束

            if (food.x == judge->x && food.y == judge->y)  // 说明生成的食物在蛇身上,则需要重新生成食物

            {

                flag = false;
                break;

            }

            judge = judge->next;  // 否则判断是否在下一个蛇身节点上

        }

    }

    gotoxy(food.x, food.y); // 移动光标到食物位置

    printf("⊙"); // 输出食物

}

 

// 捕获鼠标 游戏主循环

int clickControl()

{

    while (1)

    {

        if (judge() == 0) return 0; // 如果游戏已经结束

 

        if (kbhit()) // kbhit()是一个C和C++函数,用于非阻塞地响应键盘输入事件 ,检查当前是否有键盘输入,若有则返回一个非0值,否则返回0。

        {

            click = getch(); // 获取键盘输入

        }

 

        movingBody(); // 移动蛇

        eating(); // 吃食物

    }

 

    return 1;

}

 

// 移动蛇

void movingBody() {

    // 获取蛇头的位置

    int x = head->x, y = head->y;

    snake* p = head;

 

    // 通过先清空后打印实现动画效果

    // 移动p让其指向蛇尾

    while (p->next != NULL) {

        p = p->next;

    }

 

    gotoDelete(p->x, p->y); // 消除尾节点

    switch (click)

    {

    case up:

        y -= 1;

        break;

    case down:

        y += 1;

        break;

    case left:

        x -= 2;

        break;

    case right:

        x += 2;

        break;

    default:

        break;

    }

 

    if (x != head->x || y != head->y) {

        // 改变坐标时更新蛇的位置

        changeBody(x, y);

    }

 

    p = head; // 修改p指向新的舌头

 

    gotoPrint(p->x, p->y);  // 打印蛇头

 

    // 蛇速度控制,分数越高,速度越快

    int count = score / 10;

    if (count <= 10) speed = 150;

    else if (count > 10 && count <= 20) speed = 100;

    else if (count > 20 && count <= 40) speed = 50;

    else speed = 10;

    Sleep(speed);

}

 

// 吃到食物处理 添加一个尾巴

void eating()

{

    if (head->x == food.x && head->y == food.y) // 如果舌头跟食物的位置重合

    {

        createFood(); // 创建一个新的食物

 

        snake* _new = (snake*)malloc(sizeof(snake)); // 申请一个蛇身空间

        snake* p;

        p = head;

        while (1)

        {

            if (p->next == NULL) break;

            p = p->next;

        }

        // 在蛇尾添加一节

        p->next = _new;

        _new->next = NULL;

 

        score += 10; // 得分 +10

        gotoxy(72, 13); // 修改得分

        printf("%d", score);

    }

}

 

// 更新蛇体坐标 只需要消除尾结点 然后把新坐标结点置为头结点即可

void changeBody(int x, int y)

{

    snake* p = head;

    while (p->next->next != NULL) { // 移动p都蛇尾的上一个

        p = p->next;

    }

    free(p->next); // 释放蛇尾的空间

    p->next = NULL; // 丢弃蛇尾

    snake* new_head = (snake*)malloc(sizeof(snake)); // 申请一个新的蛇头空间

 

    // 设置蛇头的坐标为刚才移动的位置坐标

    new_head->x = x;

    new_head->y = y;

 

    // 改变蛇头

    new_head->next = head;

    head = new_head;

}

 

// 判断是否游戏结束

int judge()

{

    // 如果撞墙了

    if (head->x == 0 || head->x == 56 || head->y == 0 || head->y == 26)

    {

        finish();

        return 0;

    }

 

    snake* p = head->next;

    while (1)

    {

        if (p == NULL) break;

        if (head->x == p->x && head->y == p->y) // 如果咬到自己了

        {

            finish();

            return 0;

        }

        p = p->next;

    }

    return 1;

}

 

void finish()

{

    system("cls");

    showCopy();

    gotoxy(20, 10);

    printf("欢迎来到贪吃蛇游戏");

    gotoxy(20, 14);

    printf("游戏结束...");

    gotoxy(20, 18);

    printf("最终得分为: %d", score);

    gotoxy(20, 22);

    // 释放空间

    snake* p = head, * q;

    while (p != NULL) {

        q = p->next;

        free(p);

        p = q;

    }

    system("pause");

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值