闲暇游戏——贪吃蛇

请事先下载DevC++

#include <windows.h>
#include <conio.h>
#include <bits/stdc++.h>
#define frame_width 50
#define frame_height 25
#define _CRT_SECURE_NO_WARNINGS
using namespace std;
HANDLE hOut;    // 是控制台输出句柄,对控制台进行输入输出操作,比如设置光标位置、设置文本颜色等。
HWND myconsole; // 对窗口操作
HDC hdc;        // 设备环境句柄

CONSOLE_SCREEN_BUFFER_INFO cinfo; // 包含有关控制台屏幕缓冲区的信息

typedef struct
{
    int x, y;
} Food; // 食物坐标
typedef struct
{
    int x[100], y[100], len, state;
} Snake; // 贪吃蛇的位置,长度,移动方向

void gotoxy(int x, int y); // 最重要的一个函数,控制光标的位置
void print_map();          // 绘制地图
void get_newfood();        // 生成新食物
bool check_foodinsnake();  // 检查新食物有没有在蛇身上
void move_snake();         // 移动食物
void check_foodeating();   // 是否吃到食物
bool check_snakealive();   // 贪吃蛇是否还存活

// 需要用到的全局变量
int score;   // 分数
Snake snake; // 贪吃蛇
Food food;   // 食物
bool check_eaten;
int aim = 2;                 // 目标分数
char color[10] = "color 0b"; // 文字颜色
char colo[10] = "color 0B";  // 贪吃蛇背景颜色

void set_snake()
{
    system(colo);
    do
    {
        printf("1:start\t2:exit\n");
        char com2;
        cin >> com2;
        if (com2 == '2')
            break;

        system("cls");
        score = 0, check_eaten = 0;
        print_map();
        // 贪吃蛇的每回合运行控制
        while (1)
        {
            check_foodeating();
            if (score == aim)
            {
                return;
            }
            move_snake();
            Sleep(max(50,150 - score)); // 控制速度(与长度呈反比)
            if (!check_snakealive())
                break;
        }
        printf("Game Over!\n");
    } while (1);
}

void gotoxy(int x, int y) // 移动光标
{
    COORD pos;                                    // COORD是一种自带结构体,表示一个字符在控制台屏幕上的坐标
    HANDLE han = GetStdHandle(STD_OUTPUT_HANDLE); // 从标准输出设备里取出一个句柄
    pos.X = y, pos.Y = x;
    SetConsoleCursorPosition(han, pos); // 定位光标的函数
}

char author[105]; // 作者
void print_map()
{
    // 打印墙壁
    for (int i = 0; i < frame_height; i++)
    {
        gotoxy(i, 0);
        printf("#");
        gotoxy(i, frame_width); // 因为这个标记是长度,从零开始所以最后要减1
        printf("#");
    }
    for (int i = 0; i < frame_width; i++)
    {
        gotoxy(0, i);
        printf("#");
        gotoxy(frame_height, i);
        printf("#");
    }

    // 蛇身初始化
    snake.len = 3;
    snake.state = 'w';
    snake.x[1] = frame_height / 2;
    snake.y[1] = frame_width / 2;
    gotoxy(snake.x[1], snake.y[1]);
    printf("@");
    for (int i = 2; i <= snake.len; i++)
    {
        snake.x[i] = snake.x[i - 1] + 1;
        snake.y[i] = snake.y[i - 1];
        gotoxy(snake.x[i], snake.y[i]);
        printf("@");
    }

    // 打印初始食物
    get_newfood();

    // 打印右边状态栏
    gotoxy(2, frame_width + 3);
    printf("WELCOME TO THE GAME OF RETRO SNAKE");
    gotoxy(4, frame_width + 3);
    printf("UP:   w");
    gotoxy(6, frame_width + 3);
    printf("DOWN: s");
    gotoxy(8, frame_width + 3);
    printf("LEFT: a");
    gotoxy(10, frame_width + 3);
    printf("RIGHT:d");
    gotoxy(12, frame_width + 3);
    printf("Your score:%d", score);
    gotoxy(28, frame_width + 3);
    printf("Made by %s", author);
}

bool check_foodinsnake()
{
    for (int i = 1; i <= snake.len; i++)
        if (snake.x[i] == food.x && snake.y[i] == food.y)
            return 1;
    return 0;
}

void get_newfood() // 更新食物位置
{
    do
    {
        srand(time(0));
        food.x = rand() % (frame_height - 3) + 2;
        food.y = rand() % (frame_width - 3) + 2;
    } while (check_foodinsnake());
    gotoxy(food.x, food.y);
    cout << "$" << endl;
}

void move_snake()
{
    char com = 'n';
    while (_kbhit())    // 键盘有输入
        com = _getch(); // 从控制台读取一个字符,但不显示在屏幕上
    // 没有吃到去除蛇尾
    if (!check_eaten)
    {
        gotoxy(snake.x[snake.len], snake.y[snake.len]);
        printf(" ");
    }
    // 将除蛇头外的其他部分向前移动
    for (int i = snake.len; i > 1; i--)
        snake.x[i] = snake.x[i - 1],
        snake.y[i] = snake.y[i - 1];
    // 移动蛇头
    switch (com)
    {
    case 'w':
    {
        if (snake.state == 's') // 如果命令与当前方向相反不起作用
            snake.x[1]++;
        else
            snake.x[1]--, snake.state = 'w';
        break;
    }
    case 's':
    {
        if (snake.state == 'w')
            snake.x[1]--;
        else
            snake.x[1]++, snake.state = 's';
        break;
    }
    case 'a':
    {
        if (snake.state == 'd')
            snake.y[1]++;
        else
            snake.y[1]--, snake.state = 'a';
        break;
    }
    case 'd':
    {
        if (snake.state == 'a')
            snake.y[1]--;
        else
            snake.y[1]++, snake.state = 'd';
        break;
    }
    default: // 按其余键保持状态前进
    {
        if (snake.state == 's')
            snake.x[1]++;
        else if (snake.state == 'w')
            snake.x[1]--;
        else if (snake.state == 'd')
            snake.y[1]++;
        else if (snake.state == 'a')
            snake.y[1]--;
        break;
    }
    }
    gotoxy(snake.x[1], snake.y[1]);
    printf("@");
    check_eaten = 0;
    gotoxy(frame_height, 0);
}

void check_foodeating()
{
    if (snake.x[1] == food.x && snake.y[1] == food.y)
    {
        score += 10;
        check_eaten = 1;
        gotoxy(12, frame_width + 3);
        printf("Your score:%d", score);
        snake.len++;
        get_newfood();
    }
}

bool check_snakealive()
{
    // 检查有没有撞到墙
    if (snake.x[1] == 0 || snake.x[1] == frame_height - 1 || snake.y[1] == 0 || snake.y[1] == frame_width - 1) // 撞墙
        return 0;
    // 检查有没有吃到自己
    for (int i = 2; i <= snake.len; i++)
        if (snake.x[i] == snake.x[1] && snake.y[i] == snake.y[1])
            return 0;
    return 1;
}

typedef struct // 记录雨滴的结构体
{
    int x, y;
    char ch;
} RAINDROP;

const int BUFFER_SIZE = 100;
int WIDTH = 80;
int HEIGHT = 30;
const int RAIN_LENGTH = 18;

RAINDROP raindropLine[BUFFER_SIZE];
HANDLE HOUT = GetStdHandle(STD_OUTPUT_HANDLE); // 获得标准输出的句柄

void gotoxy1(int x, int y)
{
    COORD pos; // 定义表示一个字符在控制台屏幕上的坐标的对象
    pos.X = x;
    pos.Y = y;
    SetConsoleCursorPosition(HOUT, pos); // 设置控制台标准输出光标位置
}

void show_cursor(BOOL hide)
{
    CONSOLE_CURSOR_INFO cciCursor;
    if (GetConsoleCursorInfo(HOUT, &cciCursor)) // 获得光标信息
    {
        cciCursor.bVisible = hide;              // 隐藏光标
        SetConsoleCursorInfo(HOUT, &cciCursor); // 重新设置光标
    }
}

void set_color(int color)
{
    SetConsoleTextAttribute(HOUT, color); // 设置输出颜色
}
int tim = 50;
void set_virus()
{
    CONSOLE_SCREEN_BUFFER_INFO info;
    GetConsoleScreenBufferInfo(HOUT, &info); // 获得控制台窗体信息
    HEIGHT = info.srWindow.Bottom;           // 根据控制台的宽高设置显示的宽高
    WIDTH = info.srWindow.Right;

    show_cursor(FALSE);
    srand((unsigned int)time(NULL));
    for (int i = 0; i < BUFFER_SIZE; i++) // 随机设置雨滴下落的位置
    {
        raindropLine[i].x = rand() % WIDTH;
        raindropLine[i].y = rand() % HEIGHT;
        raindropLine[i].ch = rand() % 2 + 48; // 设置雨滴内容0或1
    }
    for (int i = 1; i <= tim; i++)
    {
        GetConsoleScreenBufferInfo(HOUT, &info); // 当窗体大小变化时,重新设置宽高信息
        HEIGHT = info.srWindow.Bottom;
        WIDTH = info.srWindow.Right;
        for (int i = 0; i < BUFFER_SIZE; ++i)
        {
            if (raindropLine[i].y <= HEIGHT)
            {
                gotoxy1(raindropLine[i].x, raindropLine[i].y);
                set_color(FOREGROUND_GREEN); // 设置雨滴颜色
                putchar(raindropLine[i].ch);
            }
            gotoxy1(raindropLine[i].x, raindropLine[i].y - RAIN_LENGTH); // 擦除过长的雨滴
            putchar(' ');
            raindropLine[i].y++;
            raindropLine[i].ch = rand() % 2 + 48;
            if (raindropLine[i].y > HEIGHT + RAIN_LENGTH)
            {
                raindropLine[i].x = rand() % WIDTH;
                raindropLine[i].y = rand() % HEIGHT;
            }
            if (raindropLine[i].y <= HEIGHT)
            {
                gotoxy1(raindropLine[i].x, raindropLine[i].y);
                set_color(FOREGROUND_GREEN | FOREGROUND_INTENSITY); // 高亮最下方的雨滴
                putchar(raindropLine[i].ch);
            }
        }
        Sleep(50);
    }
    system("cls");
}
void FullScreen()
{
    keybd_event(VK_MENU, 0x38, 0, 0);
    keybd_event(VK_RETURN, 0x1c, 0, 0);
    keybd_event(VK_RETURN, 0x1c, KEYEVENTF_KEYUP, 0);
    keybd_event(VK_MENU, 0x38, KEYEVENTF_KEYUP, 0);
} // 强制全屏

void update_snake_color(const char str[])
{
    strcpy(colo, str);
}
void update_aim(int x)
{
    aim = x;
}
void update_author(const char str[])
{
    strcpy(author, str);
}
void update_color(const char str[])
{
    strcpy(color, str);
}
void update_time(int x)
{
    tim = x;
}
void showText()
{
    system(color);
    printf("\n\n\n\n\n\n\n\n");
    printf("\n\n\n\n\n\n\n\n");
    printf("\t\t\t亲爱的母亲\n");
    printf("\t\t\t在这个特殊的日子里,\n");
    printf("\t\t\t我想对您说,\n");
    printf("\t\t\t母亲节快乐!\n");
    printf("\t\t\t祝你健健康康,万事如意!\n");
    printf("\t\t\tHAPPY Mothers Day!\n");
}
void set_gift()
{
    system("cls");
    showText(); // 显示文字
    Sleep(5000000);
}

int main()
{

    update_author("SJY1234"); // 修改作者名

    update_aim(100); // 修改贪吃蛇目标分数

    update_snake_color("color 0b"); // 修改贪吃蛇整体颜色颜色

    update_time(50); // 修改数字雨的停留时间  建议参数100-500

    update_color("color 0c"); // 修改文字颜色

    set_snake();
    system("cls");
    FullScreen();
    set_virus();
    system("cls");
    set_gift();
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值