C语言实现字符界面贪吃蛇

使用c语言实现字符界面贪吃蛇。

亲测可以在Windows Terminal下运行。

直接上源码。

欢迎交流。

 效果图

C语言实现字符界面贪吃蛇

 

C语言实现字符界面贪吃蛇

C语言实现字符界面贪吃蛇

 

 

#include <windows.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//每个位置的状态是什么
#define Nothing 0 //空
#define Wall 1 //墙
#define Food 2 //食物
#define Head 3 //蛇头
#define Body 4 //蛇身
//方向
#define Left 5 //左移
#define Right 6 //右移
#define Up 7 //上移
#define Down 8 //下移

HANDLE consoleHandle; // 操作控制台需要的一个变量
int w, h; // 高度,宽度,对应 y 和 x
int score = 0;//记录得分
int status[3000][120] = {{0}};//记录每个位置的状态是什么
int flag_death = 0;//判断是否死亡
int flag_q = 0;//判断是否退出游戏
//结构体:蛇头
struct snack_head
{
    int len;
    int x;
    int y;
    int dir;
    //分别为蛇长(不包括蛇头),蛇头横坐标,纵坐标,方向
}snack;
//结构体,蛇身
struct snack_body
{
    int x;
    int y;
    //蛇身中一节的横坐标
}body[10086];//用二维数组是一样的
//结构体,食物
struct FOOD
{
    int x;
    int y;
}food;
// 打印输入的一个字符
void mvaddch(int y, int x, char ch) { //y表示高度,x表示宽度
    COORD co = (COORD) { .X = x, .Y = y };
    SetConsoleCursorPosition(consoleHandle, co);
    putchar(ch);
}
//打印一个字符串
void mvaddstr(int y, int x, char *s) {
    int len = strlen(s);
    for (int i = 0; i < len; ++i)
        mvaddch(y, x + i, *(s + i));//y表示高度,x表示宽
}
// 清屏(全屏空格)
void ClearScr() {
    for (int i = 1; i <= h; ++i)
        for (int j = 1; j <= w; ++j)
            mvaddch(i, j, ' ');
}
//开始游戏的面板
void EnterGame() {
    mvaddstr(12, 50, "         Welcome !      ");
    mvaddstr(16, 50, "Press any key to start !");
}
//初始化面板
void PrintBoard() {//宽为30~90  高为1~28
    for (int i = 1; i <= 28; ++i)
        for (int j = 30; j <= 90; j++)
            status[i][j] = Nothing;
    for (int i = 30; i <= 90; ++i){
        mvaddch(1, i, '-');
        status[0][i] = Wall;
    }
    for (int i = 30; i <= 90; ++i) {
        mvaddch(28, i, '-');
        status[29][i] = Wall;
    }
    for (int i = 1; i <= 28; ++i) {
        mvaddch(i, 29, '|');
        status[i][28] = Wall;
    }
    for (int i = 1; i <= 28; ++i) {
        mvaddch(i, 91, '|');
        status[i][92] = Wall;
    }
    mvaddstr(12,94,"press 'p' to pause");
    mvaddstr(13,94, "press 'space' to continue");
}
//打印得分
void PrintScore(int y,int x, int score_) {
    COORD co = (COORD) {.X = x, .Y = y};
    SetConsoleCursorPosition(consoleHandle, co);
    printf("score:%d", score_);
}
//游戏失败时候的界面
void Game_Defeat() {
    flag_death = 1;
    PrintScore(h / 2 - 2, w / 2 - 3, score);
    mvaddstr(h / 2 - 1, w / 2 - 3, "Good game!");
    mvaddstr(h / 2, w / 2 - 10, "Press any key to restart.");
    score = 0;
}
void InitSnack() {//初始化蛇
    snack.len = 1;//蛇身初始长度为一节
    snack.x = 60;
    snack.y = 16;//y指的蛇头高度
    snack.dir = Right;//蛇头的初始横纵坐标及方向
    body[0].x = 59;
    body[0].y = 16;//第一节蛇身的横纵坐标
}
void GenerateFood() {//随机产生一个食物,注意食物的那个位置在这之前必须是空的
    srand((unsigned ) time(NULL));
    do {
        food.x = rand() % 59 + 31;
        food.y = rand() % 26 + 2;
    } while (status[food.y][food.x] != Nothing);
    status[food.y][food.x] = Food;
    mvaddch(food.y, food.x, '*');
}
//判断得分和是否结束,x,y分别指左移或右移的距离,如果吃到食物根据方向做相应的处理
void judge() {
    if (snack.dir == Up) {
        if (snack.x == food.x && snack.y - 1 == food.y) {
            status[snack.y][snack.x] = Body;
            status[food.y][food.x] = Head;
            mvaddch(snack.y, snack.x, '#');
            mvaddch(food.y, food.x, '@');
            for (int i = snack.len; i >= 1; i--)
                body[i] = body[i - 1];
            body[0].x = snack.x;
            body[0].y = snack.y;
            snack.len++;
            snack.y--;
            score++;
            GenerateFood();
        } else if (status[snack.y - 1][snack.x] == Wall || status[snack.y - 1][snack.x] == Body || status[snack.y][snack.x - 1] == Wall || status[snack.y][snack.x+1] == Wall) {
            Game_Defeat();
        }
    } else if (snack.dir == Down) {
        if (snack.x == food.x && snack.y + 1 == food.y) {
            status[snack.y][snack.x] = Body;
            status[food.y][food.x] = Head;
            mvaddch(snack.y, snack.x, '#');
            mvaddch(food.y, food.x, '@');
            for (int i = snack.len; i >= 1; i--)
                body[i] = body[i - 1];
            body[0].x = snack.x;
            body[0].y = snack.y;
            snack.len++;
            snack.y--;
            score++;
            GenerateFood();
        } else if (status[snack.y + 1][snack.x] == Wall || status[snack.y + 1][snack.x] == Body||status[snack.y][snack.x - 1] == Wall || status[snack.y][snack.x+1] == Wall) {
            Game_Defeat();
        }
    } else if (snack.dir == Left) {
        if (snack.x - 1 == food.x && snack.y == food.y) {
            status[snack.y][snack.x] = Body;
            status[food.y][food.x] = Head;
            mvaddch(snack.y, snack.x, '#');
            mvaddch(food.y, food.x, '@');
            for (int i = snack.len; i >= 1; i--)
                body[i] = body[i - 1];
            body[0].x = snack.x;
            body[0].y = snack.y;
            snack.len++;
            snack.x = snack.x - 1;
            score++;
            GenerateFood();
        } else if (status[snack.y][snack.x - 1] == Wall||status[snack.y][snack.x - 1] == Body||status[snack.y+1][snack.x+1] == Wall||status[snack.y -1][snack.x]==Wall) {
            Game_Defeat();
        }
    } else if (snack.dir == Right) {
        if (snack.x + 1 == food.x && snack.y == food.y) {
            status[snack.y][snack.x] = Body;
            status[food.y][food.x] = Head;
            mvaddch(snack.y, snack.x, '#');
            mvaddch(food.y, food.x, '@');
            for (int i = snack.len; i >= 1; i--)
                body[i] = body[i - 1];
            body[0].x = snack.x;
            body[0].y = snack.y;
            snack.len++;
            snack.x = snack.x + 1;
            score++;
            GenerateFood();
        } else if (status[snack.y][snack.x + 1] == Wall||status[snack.y][snack.x + 1] == Body||status[snack.y+1][snack.x+1] == Wall||status[snack.y -1][snack.x]==Wall) {
            Game_Defeat();
        }
    }
}
void Clear_Snack() {//更新蛇之前先擦掉蛇
    mvaddch(snack.y, snack.x,' ');
    status[snack.y][snack.x] = Nothing;
    for (int i = 0 ;i < snack.len; i++) {
        mvaddch(body[i].y, body[i].x, ' ');
        status[body[i].y][body[i].x] = Nothing;
    }
}
void Draw_Snack() {//画蛇
    status[snack.y][snack.x] = Head;
    mvaddch(snack.y, snack.x, '@');
    for (int i = 0; i  < snack.len; i++) {
        status[body[i].y][body[i].x] = Body;
        mvaddch(body[i].y, body[i].x, '#');
    }
}
void Dir_Change() {//根据输入调整方向
    if (_kbhit()) {
        switch (_getch()) {
            case 'q':
            case 'Q':
                flag_q = 1;
                break;
            case 'W':
            case 'w':
                if (snack.dir != Down) {
                    snack.dir = Up;
                    break;
                } else {
                    Game_Defeat();
                    break;
                }
            case 'S':
            case 's':
                if (snack.dir != Up) {
                    snack.dir = Down;
                    break;
                } else {
                    Game_Defeat();
                    break;
                }
            case 'A':
            case 'a':
                if (snack.dir != Right) {
                    snack.dir = Left;
                    break;
                } else {
                    Game_Defeat();
                    break;
                }
            case 'D':
            case 'd':
                if (snack.dir != Left) {
                    snack.dir = Right;
                    break;
                } else {
                    Game_Defeat();
                    break;
                }
            case 'p':
            case 'P':
                while (1){
                    if (_getch() == ' ') {
                        break;
                    }
                }
        }
    }
}
void MoveSnack() {//改变坐标
    for (int i = snack.len - 1; i >= 0; i--) {
        if ( i != 0) {
            body[i] = body[i - 1];
        } else {
            body[i].x = snack.x;
            body[i].y = snack.y;
        }
    }
    switch (snack.dir) {
        case Up:
            snack.y--;
            break;
        case Down:
            snack.y++;
            break;
        case Left:
            snack.x = snack.x - 1;
            break;
        case Right:
            snack.x = snack.x + 1;
            break;
    }
}
int main(){
    consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE); // 初始化这个操作器
    CONSOLE_SCREEN_BUFFER_INFO csbi; // 屏幕的信息
    GetConsoleScreenBufferInfo(consoleHandle, &csbi); // 获取屏幕信息
    w = csbi.dwSize.X;
    h = csbi.dwSize.Y; // 得到宽度高度
    // 游戏里面,如果一直有输入的光标,就有点不好看。我们可以让它不显示
    CONSOLE_CURSOR_INFO cci; // 光标信息
    cci.dwSize = 100;
    cci.bVisible = FALSE; // 不可见
    SetConsoleCursorInfo(consoleHandle, &cci); // 将光标特性应用到控制台
    // 到这里,闪烁的光标就消失了。

    ClearScr();
    EnterGame();//调出开始界面
    getch();
    ClearScr();
    PrintBoard();
    InitSnack();
    GenerateFood();

    while (1){
        if (flag_q == 1) {
            goto end;
        }
        MoveSnack();
        Draw_Snack();
        if (score <= 3){
            Sleep(160);
        } else if (score <= 7) {
            Sleep(190);
        } else if (score <= 12) {
            Sleep(210);
        } else {
            Sleep(250);
        }
        PrintScore(10, 94, score);
        Dir_Change();
        if (flag_death == 1) {
            flag_death = 0;
            getch();
            main();
        }
        judge();
        if (flag_death == 1) {
            flag_death = 0;
            getch();
            main();
        }
        Clear_Snack();
    }

    end :cci.bVisible = TRUE; // 可见
    SetConsoleCursorInfo(consoleHandle, &cci); // 重新设置
}

上一篇:队列的基本操作的实现


下一篇:【新功能】开放搜索多路召回技术解读