请事先下载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;
}