🚀欢迎互三👉:雾狩 💎💎
🚀关注博主,后期持续更新系列文章
🚀如果有错误感谢请大家批评指出,及时修改
🚀感谢大家点赞👍收藏⭐评论✍
今天水一篇吧……😂老样子,先上效果
一、概述
本文将对“登录 + 贪吃蛇”游戏的代码进行详细剖析。该游戏实现了用户登录和注册功能,同时包含经典的贪吃蛇游戏玩法,还支持游戏存档和加载功能。代码使用了 C++ 语言,并结合了 Windows 操作系统的 API 函数,以实现窗口化的游戏界面和多媒体功能。
二、代码结构与功能模块划分
1. 头文件与命名空间
#include <windows.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <conio.h>
#include <cwchar>
#include <cctype>
#include <limits>
#include <stdio.h>
#include <cstdlib>
#include <ctime>
#include <mmsystem.h>
#pragma comment(lib, "winmm.lib")
using namespace std;
- 包含了多个标准库和 Windows 相关的头文件,以实现输入输出、文件操作、随机数生成、时间处理和多媒体功能。
using namespace std;
允许直接使用标准库中的类和函数。
2. 结构体定义
// User结构体用于存储用户的基本信息
struct User {
string username;
string password;
};
// SaveData结构体用于存储游戏的存档信息
struct SaveData {
string username;
time_t playTime;
int totalPlayTime;
int length;
int mode;
vector<int> x;
vector<int> y;
int ax, ay;
int dir;
unsigned long long tk;
};
User
结构体用于存储用户的用户名和密码。SaveData
结构体用于存储游戏的存档信息,包括用户名、存档时间、总游戏时长、蛇的长度、游戏模式、蛇的坐标、苹果的坐标、蛇的移动方向和游戏时间戳。
3. 全局变量定义
vector<User> users;
vector<SaveData> saves;
const string DATA_FILE = "users.dat";
const string SAVE_FILE = "saves.dat";
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
#define SIZE 30
#define WIDTH 20
#define FPS 10
#define SPEED 3
HWND m_hwnd;
int g_nWidth = WIDTH * SIZE + 10 + 300, g_nHeight = WIDTH * SIZE + 33;
int map[SIZE][SIZE];
std::vector<int> x, y;
int ax, ay;
int px, py;
int dir;
unsigned long long tk;
bool lock;
time_t startTime;
int currentMode;
int targetLength;
int currentSpeed;
string currentUsername;
bool isPaused = false;
bool isGameOver = false;
users
和saves
分别存储所有用户信息和游戏存档信息。DATA_FILE
和SAVE_FILE
分别是用户数据文件和游戏存档文件的名称。hConsole
用于控制控制台的输出。- 一系列宏定义了游戏地图的大小、方块宽度、帧率和初始速度。
- 其他全局变量用于存储游戏的各种状态和信息。
4. 辅助函数
4.1 时间转换函数
string getTimeStr(time_t t) {
char buffer[80];
struct tm* timeinfo = localtime(&t);
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", timeinfo);
return string(buffer);
}
- 将时间戳转换为字符串格式,方便显示存档时间。
4.2 音乐播放函数
void playBackgroundMusic() {
mciSendString("close background_music", NULL, 0, NULL);
mciSendString(R"(open "D:\Dev-cpp 作品\登录+贪吃蛇\Snake_music.mp3" type mpegvideo alias background_music)", NULL, 0, NULL);
mciSendString("play background_music repeat", NULL, 0, NULL);
isGameOver = false;
}
void playVictoryMusic() {
mciSendString("close background_music", NULL, 0, NULL);
mciSendString("close fail_music", NULL, 0, NULL);
mciSendString(R"(open "D:\Dev-cpp 作品\登录+贪吃蛇\Snake_victory.mp3" type mpegvideo alias victory_music)", NULL, 0, NULL);
mciSendString("play victory_music", NULL, 0, NULL);
isGameOver = true;
}
void playFailMusic() {
mciSendString("close background_music", NULL, 0, NULL);
mciSendString("close victory_music", NULL, 0, NULL);
mciSendString(R"(open "D:\Dev-cpp 作品\登录+贪吃蛇\Snake_fail.mp3" type mpegvideo alias fail_music)", NULL, 0, NULL);
mciSendString("play fail_music", NULL, 0, NULL);
isGameOver = true;
}
void pauseAllMusic() {
mciSendString("close background_music", NULL, 0, NULL);
mciSendString("close victory_music", NULL, 0, NULL);
mciSendString("close fail_music", NULL, 0, NULL);
}
- 分别用于播放背景音乐、胜利音乐、失败音乐和暂停所有音乐,使用
mciSendString
函数进行多媒体操作。
4.3 文件操作函数
bool fileExists(const string& filename) {
ifstream file(filename);
return file.good();
}
bool loadUsers() {
if (!fileExists(DATA_FILE)) {
return true;
}
ifstream file(DATA_FILE, ios::binary);
if (!file) {
return false;
}
char header[4];
file.read(header, 4);
if (string(header, 4) != "USR1") {
file.close();
return false;
}
size_t count;
file.read(reinterpret_cast<char*>(&count), sizeof(count));
users.clear();
for (size_t i = 0; i < count; i++) {
User user;
size_t len;
file.read(reinterpret_cast<char*>(&len), sizeof(len));
user.username.resize(len);
file.read(&user.username[0], len);
file.read(reinterpret_cast<char*>(&len), sizeof(len));
user.password.resize(len);
file.read(&user.password[0], len);
users.push_back(user);
}
file.close();
return true;
}
bool saveUsers() {
ofstream file(DATA_FILE, ios::binary);
if (!file) {
return false;
}
const char* header = "USR1";
file.write(header, 4);
size_t count = users.size();
file.write(reinterpret_cast<const char*>(&count), sizeof(count));
for (const auto& user : users) {
size_t len = user.username.length();
file.write(reinterpret_cast<const char*>(&len), sizeof(len));
file.write(user.username.c_str(), len);
len = user.password.length();
file.write(reinterpret_cast<const char*>(&len), sizeof(len));
file.write(user.password.c_str(), len);
}
file.close();
return true;
}
fileExists
用于判断文件是否存在。loadUsers
用于加载用户数据,从二进制文件中读取用户信息。saveUsers
用于保存用户数据,将用户信息写入二进制文件。
4.4 用户操作函数
bool registerUser(const string& username, const string& password) {
for (char c : username) {
if (!isalnum(c) && c != '_' && c != '.') {
return false;
}
}
User newUser;
newUser.username = username;
newUser.password = password;
users.push_back(newUser);
return saveUsers();
}
bool authenticateUser(const string& username, const string& password) {
for (const auto& user : users) {
if (user.username == username && user.password == password) {
return true;
}
}
return false;
}
string getPasswordInput() {
string password;
char ch;
while ((ch = _getch()) != '\r') {
if (ch == '\b') {
if (!password.empty()) {
password.pop_back();
cout << "\b \b";
}
} else {
password += ch;
cout << '*';
}
}
cout << endl;
return password;
}
registerUser
用于用户注册,验证用户名的合法性并将新用户信息保存到文件中。authenticateUser
用于用户登录验证,检查用户名和密码是否匹配。getPasswordInput
用于获取用户输入的密码,输入时显示星号保护隐私。
4.5 其他辅助函数
void showMessage(const string& message, const string& title, UINT style) {
MessageBox(NULL, message.c_str(), title.c_str(), style);
}
string trim(const string& str) {
size_t first = str.find_first_not_of(" \t\n\r");
if (first == string::npos)
return "";
size_t last = str.find_last_not_of(" \t\n\r");
return str.substr(first, (last - first + 1));
}
void setConsoleColor(WORD color) {
SetConsoleTextAttribute(hConsole, color);
}
void setConsoleCursorPosition(short x, short y) {
COORD coord;
coord.X = x;
coord.Y = y;
SetConsoleCursorPosition(hConsole, coord);
}
showMessage
用于显示消息框。trim
用于去除字符串前后的空格。setConsoleColor
用于设置控制台文本颜色。setConsoleCursorPosition
用于设置控制台光标位置。
5. 游戏核心函数
5.1 初始化函数
void init() {
srand((unsigned)time(NULL));
tk = 0;
dir = 2;
x.push_back(0);
y.push_back(0);
px = py = 0;
ax = -1;
memset(map, 0, sizeof(map));
map[0][0] = 1;
lock = false;
isGameOver = false;
}
- 初始化游戏的各种状态,包括随机数种子、蛇的位置、苹果的位置和游戏地图等。
5.2 游戏结束处理函数
void gameover() {
pauseAllMusic();
playFailMusic();
MessageBox(m_hwnd, "你输了", "游戏结束", MB_OK);
x.clear();
y.clear();
init();
startTime = time(NULL);
}
void youwin() {
pauseAllMusic();
playVictoryMusic();
MessageBox(m_hwnd, "你赢了", "游戏结束", MB_OK);
x.clear();
y.clear();
init();
startTime = time(NULL);
}
gameover
处理游戏失败的情况,播放失败音乐,显示消息框并重新初始化游戏。youwin
处理游戏胜利的情况,播放胜利音乐,显示消息框并重新初始化游戏。
5.3 蛇移动函数
void move(int d) {
if (d == 0 && x[0] > 0) {
x.insert(x.begin(), x[0] - 1);
px = x[x.size() - 1];
x.erase(x.begin() + x.size() - 1);
y.insert(y.begin(), y[0]);
py = y[y.size() - 1];
y.erase(y.begin() + y.size() - 1);
} else if (d == 0 && x[0] <= 0) gameover();
else if (d == 2 && x[0] < SIZE - 1) {
x.insert(x.begin(), x[0] + 1);
px = x[x.size() - 1];
x.erase(x.begin() + x.size() - 1);
y.insert(y.begin(), y[0]);
py = y[y.size() - 1];
y.erase(y.begin() + y.size() - 1);
} else if (d == 2 && x[0] >= SIZE - 1) gameover();
else if (d == 1 && y[0] > 0) {
x.insert(x.begin(), x[0]);
px = x[x.size() - 1];
x.erase(x.begin() + x.size() - 1);
y.insert(y.begin(), y[0] - 1);
py = y[y.size() - 1];
y.erase(y.begin() + y.size() - 1);
} else if (d == 1 && y[0] <= 0) gameover();
else if (d == 3 && y[0] < SIZE - 1) {
x.insert(x.begin(), x[0]);
px = x[x.size() - 1];
x.erase(x.begin() + x.size() - 1);
y.insert(y.begin(), y[0] + 1);
py = y[y.size() - 1];
y.erase(y.begin() + y.size() - 1);
} else if (d == 3 && y[0] >= SIZE - 1) gameover();
}
- 根据蛇的移动方向更新蛇的位置,如果蛇撞到边界则游戏失败。
5.4 游戏状态更新函数
void update() {
if (isPaused || isGameOver) return;
if (tk % currentSpeed == 0) {
move(dir);
lock = false;
}
if (x[0] == ax && y[0] == ay) {
x.push_back(px);
y.push_back(py);
ax = -1;
}
if (currentMode != 5 && x.size() >= static_cast<size_t>(targetLength)) {
youwin();
return;
}
if (x.size() >= SIZE * SIZE) {
youwin();
return;
}
memset(map, 0, sizeof(map));
for (size_t i = 0; i < x.size(); i++) {
if (map[x[i]][y[i]] == 0) map[x[i]][y[i]] = 1;
else {
gameover();
return;
}
}
if (ax == -1) {
ax = rand() % SIZE;
ay = rand() % SIZE;
while (map[ax][ay] == 1) {
ax = rand() % SIZE;
ay = rand() % SIZE;
}
}
map[ax][ay] = 2;
tk++;
}
- 更新游戏的状态,包括蛇的移动、吃苹果、判断游戏胜利或失败、生成新的苹果等。
5.5 窗口消息处理函数
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
switch (Message) {
case WM_DESTROY: {
PostQuitMessage(0);
break;
}
case WM_KEYDOWN: {
if (!lock && !isGameOver) {
if (wParam == VK_UP && (dir - 0) % 2 != 0) {
dir = 0;
lock = true;
} else if (wParam == VK_DOWN && (dir - 2) % 2 != 0) {
dir = 2;
lock = true;
} else if (wParam == VK_LEFT && (dir - 1) % 2 != 0) {
dir = 1;
lock = true;
} else if (wParam == VK_RIGHT && (dir - 3) % 2 != 0) {
dir = 3;
lock = true;
}
}
if (wParam == VK_ESCAPE) {
int result = MessageBox(hwnd, "确定要退出游戏吗?", "确认退出", MB_YESNO | MB_ICONQUESTION);
if (result == IDYES) {
PostQuitMessage(0);
}
}
if (wParam == VK_SPACE) {
isPaused = !isPaused;
if (isPaused) {
pauseAllMusic();
} else {
if (!isGameOver) {
playBackgroundMusic();
}
}
}
if (wParam == VK_RETURN && isGameOver) {
init();
startTime = time(NULL);
playBackgroundMusic();
}
break;
}
default:
return DefWindowProc(hwnd, Message, wParam, lParam);
}
return 0;
}
- 处理窗口的各种消息,包括窗口销毁、按键按下等。根据不同的按键操作,更新蛇的移动方向、暂停或继续游戏、退出游戏等。
5.6 游戏画面渲染函数
void render() {
HDC hDC = GetDC(m_hwnd);
HDC memDC = CreateCompatibleDC(0);
HBITMAP bmpBack = CreateCompatibleBitmap(hDC, g_nWidth, g_nHeight);
SelectObject(memDC, bmpBack);
HPEN penBack = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
SelectObject(memDC, penBack);
HBRUSH brushBack = CreateSolidBrush(RGB(255, 255, 255));
SelectObject(memDC, brushBack);
RECT rcClient;
GetClientRect(m_hwnd, &rcClient);
FillRect(memDC, &rcClient, brushBack);
HBRUSH brushHead = CreateSolidBrush(RGB(255, 0, 0));
HBRUSH brushBody = CreateSolidBrush(RGB(0, 128, 0));
HBRUSH brushApple = CreateSolidBrush(RGB(0, 0, 255));
int dw = WIDTH;
int rows = SIZE;
int cols = SIZE;
for (int r = 0; r < rows; ++r) {
for (int c = 0; c < cols; ++c) {
if (map[r][c] == 1) {
if (r == x[0] && c == y[0]) {
SelectObject(memDC, brushHead);
} else {
SelectObject(memDC, brushBody);
}
} else if (map[r][c] == 2) {
SelectObject(memDC, brushApple);
} else {
SelectObject(memDC, brushBack);
}
Rectangle(memDC, c * dw, r * dw, (c + 1)*dw, (r + 1)*dw);
}
}
time_t currentTime = time(NULL);
int elapsedTime = static_cast<int>(currentTime - startTime);
int hours = elapsedTime / 3600;
int minutes = (elapsedTime % 3600) / 60;
int seconds = elapsedTime % 60;
char info[200];
sprintf(info, "蛇的长度: %u\n游戏时长: %02d:%02d:%02d\n难度: %d\n目标长度: %d\n\n规则:\n",
static_cast<unsigned>(x.size()), hours, minutes, seconds, currentMode, targetLength);
switch (currentMode) {
case 1:
strcat(info, "简单模式:蛇的长度达到15即可通关。\n");
break;
case 2:
strcat(info, "普通模式:蛇的长度达到30即可通关。\n");
break;
case 3:
strcat(info, "困难模式:蛇的长度达到60即可通关。\n");
break;
case 4:
strcat(info, "地狱模式:蛇的长度达到80即可通关。\n");
break;
case 5:
strcat(info, "无尽模式:蛇占满全屏即可通关。\n");
break;
}
strcat(info, "\n操作步骤:\n");
strcat(info, "方向键:控制蛇的移动方向。\n");
strcat(info, "Space键:暂停/继续游戏。\n");
strcat(info, "Esc键:退出游戏。\n");
if (isGameOver) {
strcat(info, "\n游戏已结束,按Enter键重新开始。\n");
}
SetBkMode(memDC, TRANSPARENT);
SetTextColor(memDC, RGB(0, 0, 0));
RECT infoRect = {SIZE * WIDTH + 20, 20, g_nWidth - 20, g_nHeight - 20};
DrawText(memDC, info, -1, &infoRect, DT_LEFT | DT_TOP);
DeleteObject(brushHead);
DeleteObject(brushBody);
DeleteObject(brushApple);
BitBlt(hDC, 0, 0, g_nWidth, g_nHeight, memDC, 0, 0, SRCCOPY);
DeleteObject(penBack);
DeleteObject(brushBack);
DeleteObject(bmpBack);
DeleteDC(memDC);
ReleaseDC(m_hwnd, hDC);
}
- 渲染游戏画面,包括绘制蛇、苹果、游戏地图和显示游戏信息。使用双缓冲技术,避免画面闪烁。
5.7 游戏循环线程函数
DWORD WINAPI startLoop(LPVOID) {
while (1) {
update();
render();
Sleep(1000 / FPS);
}
return 0L;
}
- 游戏的主循环,不断更新游戏状态和渲染画面,通过
Sleep
函数控制游戏帧率。
6. 游戏模式和存档相关函数
6.1 选择游戏模式函数
int selectGameMode(const string&) {
int mode;
system("cls");
setConsoleColor(FOREGROUND_BLUE | FOREGROUND_GREEN);
setConsoleCursorPosition(15, 3);
cout << "===== 选择游戏模式 =====" << endl;
setConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
setConsoleCursorPosition(15, 5);
cout << "1. 简单模式 (长度达到15通关)" << endl;
setConsoleCursorPosition(15, 6);
cout << "2. 普通模式 (长度达到30通关)" << endl;
setConsoleCursorPosition(15, 7);
cout << "3. 困难模式 (长度达到60通关)" << endl;
setConsoleCursorPosition(15, 8);
cout << "4. 地狱模式 (长度达到80通关)" << endl;
setConsoleCursorPosition(15, 9);
cout << "5. 无尽模式 (占满全屏通关)" << endl;
setConsoleColor(FOREGROUND_BLUE | FOREGROUND_GREEN);
setConsoleCursorPosition(15, 11);
cout << "=======================" << endl;
setConsoleCursorPosition(15, 13);
cout << "请选择: ";
while (!(cin >> mode) || mode < 1 || mode > 5) {
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
showMessage("输入无效,请输入1 - 5之间的数字!", "错误", MB_ICONERROR);
setConsoleCursorPosition(15, 13);
cout << "请选择: ";
}
cin.ignore();
return mode;
}
- 让用户选择游戏模式,根据用户输入返回相应的模式编号。
6.2 选择游戏存档函数
int selectSaveGame(const string& username) {
vector<SaveData> userSaves;
if (fileExists(SAVE_FILE)) {
ifstream file(SAVE_FILE, ios::binary);
if (file) {
char header[4];
file.read(header, 4);
if (string(header, 4) == "SAV1") {
size_t count;
file.read(reinterpret_cast<char*>(&count), sizeof(count));
saves.clear();
for (size_t i = 0; i < count; i++) {
SaveData save;
size_t len;
file.read(reinterpret_cast<char*>(&len), sizeof(len));
save.username.resize(len);
file.read(&save.username[0], len);
file.read(reinterpret_cast<char*>(&save.playTime), sizeof(save.playTime));
file.read(reinterpret_cast<char*>(&save.totalPlayTime), sizeof(save.totalPlayTime));
file.read(reinterpret_cast<char*>(&save.length), sizeof(save.length));
file.read(reinterpret_cast<char*>(&save.mode), sizeof(save.mode));
file.read(reinterpret_cast<char*>(&len), sizeof(len));
save.x.resize(len);
for (int& val : save.x) {
file.read(reinterpret_cast<char*>(&val), sizeof(val));
}
file.read(reinterpret_cast<char*>(&len), sizeof(len));
save.y.resize(len);
for (int& val : save.y) {
file.read(reinterpret_cast<char*>(&val), sizeof(val));
}
file.read(reinterpret_cast<char*>(&save.ax), sizeof(save.ax));
file.read(reinterpret_cast<char*>(&save.ay), sizeof(save.ay));
file.read(reinterpret_cast<char*>(&save.dir), sizeof(save.dir));
file.read(reinterpret_cast<char*>(&save.tk), sizeof(save.tk));
saves.push_back(save);
}
}
file.close();
}
}
for (const auto& save : saves) {
if (save.username == username) {
userSaves.push_back(save);
}
}
if (userSaves.empty()) {
showMessage("没有可用的存档,将开始新游戏。", "提示", MB_ICONINFORMATION);
return -1;
}
system("cls");
setConsoleColor(FOREGROUND_BLUE | FOREGROUND_GREEN);
setConsoleCursorPosition(15, 3);
cout << "===== 选择存档 =====" << endl;
for (size_t i = 0; i < userSaves.size(); i++) {
setConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
setConsoleCursorPosition(15, static_cast<short>(5 + i));
cout << i + 1 << ". 存档时间: " << getTimeStr(userSaves[i].playTime)
<< " 游玩总时长: " << userSaves[i].totalPlayTime << " 秒"
<< " 长度: " << userSaves[i].length
<< " 模式: " << userSaves[i].mode << endl;
}
setConsoleColor(FOREGROUND_BLUE | FOREGROUND_GREEN);
setConsoleCursorPosition(15, static_cast<short>(6 + userSaves.size()));
cout << "0. 开始新游戏" << endl;
setConsoleColor(FOREGROUND_BLUE | FOREGROUND_GREEN);
setConsoleCursorPosition(15, static_cast<short>(8 + userSaves.size()));
cout << "=======================" << endl;
setConsoleCursorPosition(15, static_cast<short>(10 + userSaves.size()));
cout << "请选择: ";
int choice;
while (!(cin >> choice) || choice < 0 || static_cast<size_t>(choice) > userSaves.size()) {
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
showMessage("输入无效,请输入正确的存档编号!", "错误", MB_ICONERROR);
setConsoleCursorPosition(15, static_cast<short>(10 + userSaves.size()));
cout << "请选择: ";
}
cin.ignore();
if (choice == 0) {
return -1;
} else {
x = userSaves[choice - 1].x;
y = userSaves[choice - 1].y;
ax = userSaves[choice - 1].ax;
ay = userSaves[choice - 1].ay;
dir = userSaves[choice - 1].dir;
tk = userSaves[choice - 1].tk;
currentMode = userSaves[choice - 1].mode;
startTime = time(NULL) - userSaves[choice - 1].totalPlayTime;
switch (currentMode) {
case 1: targetLength = 15; currentSpeed = 5; break;
case 2: targetLength = 30; currentSpeed = 3; break;
case 3: targetLength = 60; currentSpeed = 2; break;
case 4: targetLength = 80; currentSpeed = 1; break;
case 5: targetLength = SIZE * SIZE; currentSpeed = 3; break;
}
return choice - 1;
}
}
- 让用户选择游戏存档,如果有可用存档,显示存档信息供用户选择;如果没有可用存档,提示用户开始新游戏。选择存档后,加载存档信息。
6.3 保存游戏存档函数
void saveGame(const string& username) {
int result = MessageBox(m_hwnd, "是否要保存存档?", "保存存档", MB_YESNO | MB_ICONQUESTION);
if (result == IDYES) {
time_t currentTime = time(NULL);
int elapsedTime = static_cast<int>(currentTime - startTime);
SaveData save;
save.username = username;
save.playTime = currentTime;
save.totalPlayTime = elapsedTime;
save.length = static_cast<int>(x.size());
save.mode = currentMode;
save.x = x;
save.y = y;
save.ax = ax;
save.ay = ay;
save.dir = dir;
save.tk = tk;
for (auto it = saves.begin(); it != saves.end(); ) {
if (it->username == username) {
it = saves.erase(it);
} else {
++it;
}
}
saves.push_back(save);
// 后续应添加将saves保存到文件的代码
}
}
- 询问用户是否保存存档,如果用户选择是,创建一个新的存档对象并保存到
saves
向量中,同时删除该用户的旧存档。
三、完整代码
下载地址
解压后,跟着操作步骤.txt
下载源代码
四、总结
该代码实现了一个功能丰富的登录 + 贪吃蛇游戏,包括用户注册、登录、游戏存档和加载、多种游戏模式等功能。通过合理的结构体定义和函数封装,代码具有较好的模块化和可维护性。同时,使用 Windows API 实现了窗口化的游戏界面和多媒体功能,提升了游戏的用户体验。不过,代码中保存游戏存档的部分还未完成将 saves
向量保存到文件的操作,需要进一步完善。