|
|
#define _CRT_SECURE_NO_WARNINGS
|
|
|
#include <stdio.h>
|
|
|
#include <Windows.h>
|
|
|
#include <stdlib.h>
|
|
|
#include <time.h>
|
|
|
#include <conio.h>
|
|
|
#include <math.h>
|
|
|
|
|
|
#define ROW 22 // 游戏区行数
|
|
|
#define COL 42 // 游戏区列数
|
|
|
|
|
|
#define KONG 0 // 标记空
|
|
|
#define WALL 1 // 标记墙
|
|
|
#define FOOD 2 // 标记普通食物
|
|
|
#define HEAD 3 // 标记蛇头
|
|
|
#define BODY 4 // 标记蛇身
|
|
|
#define OBSTACLE 5 // 标记障碍物
|
|
|
#define SPECIAL_FOOD 6 // 标记特殊食物
|
|
|
|
|
|
#define UP 72 // 方向键:上
|
|
|
#define DOWN 80 // 方向键:下
|
|
|
#define LEFT 75 // 方向键:左
|
|
|
#define RIGHT 77 // 方向键:右
|
|
|
#define SPACE 32 // 暂停
|
|
|
#define ESC 27 // 退出
|
|
|
#define ENTER 13 // 回车键
|
|
|
|
|
|
// 蛇头
|
|
|
struct Snake
|
|
|
{
|
|
|
int len; // 记录蛇身长度
|
|
|
int x; // 蛇头横坐标
|
|
|
int y; // 蛇头纵坐标
|
|
|
} snake;
|
|
|
|
|
|
// 蛇身
|
|
|
struct Body
|
|
|
{
|
|
|
int x; // 蛇身横坐标
|
|
|
int y; // 蛇身纵坐标
|
|
|
} body[ROW * COL]; // 开辟足以存储蛇身的结构体数组
|
|
|
|
|
|
int face[ROW][COL]; // 标记游戏区各个位置的状态
|
|
|
|
|
|
// 隐藏光标
|
|
|
void HideCursor();
|
|
|
// 光标跳转
|
|
|
void CursorJump(int x, int y);
|
|
|
// 初始化界面
|
|
|
void InitInterface();
|
|
|
// 颜色设置
|
|
|
void color(int c);
|
|
|
// 从文件读取最高分
|
|
|
void ReadGrade();
|
|
|
// 更新最高分到文件
|
|
|
void WriteGrade();
|
|
|
// 初始化蛇
|
|
|
void InitSnake();
|
|
|
// 随机生成食物
|
|
|
void RandFood();
|
|
|
// 随机生成障碍物
|
|
|
void RandObstacles(int count);
|
|
|
// 判断得分与结束
|
|
|
int JudgeFunc(int x, int y); // 修改:返回游戏状态
|
|
|
// 打印蛇与覆盖蛇
|
|
|
void DrawSnake(int flag);
|
|
|
// 移动蛇
|
|
|
void MoveSnake(int x, int y);
|
|
|
// 执行按键
|
|
|
void run(int x, int y);
|
|
|
// 游戏主体逻辑函数
|
|
|
void Game();
|
|
|
// 显示开始菜单
|
|
|
void ShowMenu();
|
|
|
// 显示游戏结束界面
|
|
|
void ShowGameOver();
|
|
|
// 显示帮助信息
|
|
|
void ShowHelp();
|
|
|
// 改变游戏速度
|
|
|
void ChangeSpeed(int delta);
|
|
|
// 添加特殊食物
|
|
|
void AddSpecialFood();
|
|
|
// 移除特殊食物
|
|
|
void RemoveSpecialFood();
|
|
|
// 绘制游戏边框
|
|
|
void DrawBorder();
|
|
|
// 更新分数显示
|
|
|
void UpdateScoreDisplay();
|
|
|
// 移动障碍物
|
|
|
void MoveObstacles();
|
|
|
// 保存游戏
|
|
|
void SaveGame();
|
|
|
// 加载游戏
|
|
|
void LoadGame();
|
|
|
|
|
|
int max, grade; // 全局变量
|
|
|
int game_speed = 300; // 游戏速度(毫秒)- 修改:降低初始速度
|
|
|
int obstacles_mode = 0; // 障碍物模式:0-无,1-固定障碍物,2-移动障碍物
|
|
|
int obstacles_count = 0; // 当前障碍物数量
|
|
|
int special_food_active = 0; // 特殊食物是否激活
|
|
|
int special_food_x, special_food_y; // 特殊食物位置
|
|
|
int game_paused = 0; // 游戏是否暂停
|
|
|
int game_started = 0; // 游戏是否开始
|
|
|
int pass_wall = 0; // 是否开启穿墙模式
|
|
|
time_t start_time; // 游戏开始时间
|
|
|
int last_move_time; // 上一次移动障碍物的时间
|
|
|
int special_food_timer = 0; // 特殊食物计时器
|
|
|
|
|
|
int main()
|
|
|
{
|
|
|
max = 0, grade = 0; // 初始化变量
|
|
|
system("title 贪吃蛇完美版"); // 设置cmd窗口的名字
|
|
|
system("mode con cols=84 lines=23"); // 设置cmd窗口的大小
|
|
|
HideCursor(); // 隐藏光标
|
|
|
ReadGrade(); // 从文件读取最高分到max变量
|
|
|
|
|
|
while (1) {
|
|
|
ShowMenu(); // 显示开始菜单
|
|
|
InitInterface(); // 初始化界面
|
|
|
InitSnake(); // 初始化蛇
|
|
|
srand((unsigned int)time(NULL)); // 设置随机数生成起点
|
|
|
RandFood(); // 随机生成食物
|
|
|
|
|
|
if (obstacles_mode == 1 || obstacles_mode == 2) {
|
|
|
RandObstacles(10); // 生成10个障碍物
|
|
|
}
|
|
|
|
|
|
DrawSnake(1); // 打印蛇
|
|
|
Game(); // 开始游戏
|
|
|
|
|
|
// 游戏结束后询问是否返回主菜单
|
|
|
char ch;
|
|
|
CursorJump(COL, ROW / 2 + 6);
|
|
|
printf("返回主菜单?(y/n):");
|
|
|
ch = _getch();
|
|
|
if (ch == 'n' || ch == 'N') {
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
// 重置游戏状态
|
|
|
game_speed = 300; // 重置为初始速度
|
|
|
obstacles_mode = 0;
|
|
|
obstacles_count = 0;
|
|
|
special_food_active = 0;
|
|
|
game_paused = 0;
|
|
|
game_started = 0;
|
|
|
pass_wall = 0;
|
|
|
grade = 0;
|
|
|
special_food_timer = 0;
|
|
|
system("cls");
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
// 隐藏光标
|
|
|
void HideCursor()
|
|
|
{
|
|
|
CONSOLE_CURSOR_INFO curInfo;
|
|
|
curInfo.dwSize = 1;
|
|
|
curInfo.bVisible = FALSE;
|
|
|
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
|
SetConsoleCursorInfo(handle, &curInfo);
|
|
|
}
|
|
|
|
|
|
// 光标跳转
|
|
|
void CursorJump(int x, int y)
|
|
|
{
|
|
|
COORD pos;
|
|
|
pos.X = x;
|
|
|
pos.Y = y;
|
|
|
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
|
SetConsoleCursorPosition(handle, pos);
|
|
|
}
|
|
|
|
|
|
// 绘制游戏边框
|
|
|
void DrawBorder()
|
|
|
{
|
|
|
color(6); // 土黄色边框
|
|
|
for (int i = 0; i < ROW; i++)
|
|
|
{
|
|
|
for (int j = 0; j < COL; j++)
|
|
|
{
|
|
|
if (j == 0 || j == COL - 1)
|
|
|
{
|
|
|
face[i][j] = WALL;
|
|
|
CursorJump(2 * j, i);
|
|
|
printf("■");
|
|
|
}
|
|
|
else if (i == 0 || i == ROW - 1)
|
|
|
{
|
|
|
face[i][j] = WALL;
|
|
|
CursorJump(2 * j, i);
|
|
|
printf("■");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
face[i][j] = KONG;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 初始化界面
|
|
|
void InitInterface()
|
|
|
{
|
|
|
// 清空游戏区域
|
|
|
for (int i = 0; i < ROW; i++)
|
|
|
{
|
|
|
for (int j = 0; j < COL; j++)
|
|
|
{
|
|
|
face[i][j] = KONG;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 绘制边框
|
|
|
DrawBorder();
|
|
|
|
|
|
// 绘制分数和状态信息
|
|
|
color(7); // 白色
|
|
|
CursorJump(0, ROW);
|
|
|
printf("当前得分: %d", grade);
|
|
|
CursorJump(COL, ROW);
|
|
|
printf("最高得分: %d", max);
|
|
|
CursorJump(COL * 2 - 10, ROW);
|
|
|
printf("速度: %d", 4000 / game_speed);
|
|
|
|
|
|
// 显示控制提示
|
|
|
CursorJump(0, ROW + 1);
|
|
|
printf("控制: ←→↑↓ 移动 | SPACE 暂停 | ESC 退出 | S 保存 | L 加载");
|
|
|
}
|
|
|
|
|
|
// 更新分数显示
|
|
|
void UpdateScoreDisplay()
|
|
|
{
|
|
|
color(7);
|
|
|
CursorJump(10, ROW);
|
|
|
printf("%d", grade);
|
|
|
CursorJump(COL + 10, ROW);
|
|
|
printf("%d", max);
|
|
|
CursorJump(COL * 2 - 4, ROW);
|
|
|
printf("%d", 4000 / game_speed);
|
|
|
}
|
|
|
|
|
|
// 颜色设置
|
|
|
void color(int c)
|
|
|
{
|
|
|
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), c);
|
|
|
}
|
|
|
|
|
|
// 从文件读取最高分
|
|
|
void ReadGrade()
|
|
|
{
|
|
|
FILE* pf = fopen("snake_max_score.dat", "rb");
|
|
|
if (pf == NULL)
|
|
|
{
|
|
|
pf = fopen("snake_max_score.dat", "wb");
|
|
|
if (pf) {
|
|
|
fwrite(&max, sizeof(int), 1, pf);
|
|
|
fclose(pf);
|
|
|
pf = fopen("snake_max_score.dat", "rb");
|
|
|
}
|
|
|
}
|
|
|
if (pf) {
|
|
|
fread(&max, sizeof(int), 1, pf);
|
|
|
fclose(pf);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 更新最高分到文件
|
|
|
void WriteGrade()
|
|
|
{
|
|
|
FILE* pf = fopen("snake_max_score.dat", "wb");
|
|
|
if (pf) {
|
|
|
fwrite(&max, sizeof(int), 1, pf);
|
|
|
fclose(pf);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 初始化蛇
|
|
|
void InitSnake()
|
|
|
{
|
|
|
snake.len = 2;
|
|
|
snake.x = COL / 2;
|
|
|
snake.y = ROW / 2;
|
|
|
|
|
|
body[0].x = COL / 2 - 1;
|
|
|
body[0].y = ROW / 2;
|
|
|
body[1].x = COL / 2 - 2;
|
|
|
body[1].y = ROW / 2;
|
|
|
|
|
|
face[snake.y][snake.x] = HEAD;
|
|
|
face[body[0].y][body[0].x] = BODY;
|
|
|
face[body[1].y][body[1].x] = BODY;
|
|
|
}
|
|
|
|
|
|
// 随机生成食物
|
|
|
void RandFood()
|
|
|
{
|
|
|
int i, j, attempts = 0;
|
|
|
|
|
|
do {
|
|
|
i = rand() % (ROW - 2) + 1;
|
|
|
j = rand() % (COL - 2) + 1;
|
|
|
attempts++;
|
|
|
if (attempts > 100) return; // 防止死循环
|
|
|
} while (face[i][j] != KONG);
|
|
|
|
|
|
face[i][j] = FOOD;
|
|
|
color(12); // 红色
|
|
|
CursorJump(2 * j, i);
|
|
|
printf("●");
|
|
|
}
|
|
|
|
|
|
// 随机生成障碍物
|
|
|
void RandObstacles(int count)
|
|
|
{
|
|
|
for (int c = 0; c < count; c++)
|
|
|
{
|
|
|
int i, j, attempts = 0;
|
|
|
|
|
|
do {
|
|
|
i = rand() % (ROW - 2) + 1;
|
|
|
j = rand() % (COL - 2) + 1;
|
|
|
attempts++;
|
|
|
if (attempts > 100) return;
|
|
|
} while (face[i][j] != KONG);
|
|
|
|
|
|
face[i][j] = OBSTACLE;
|
|
|
color(8); // 灰色
|
|
|
CursorJump(2 * j, i);
|
|
|
printf("■");
|
|
|
obstacles_count++;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 移动障碍物
|
|
|
void MoveObstacles()
|
|
|
{
|
|
|
static int move_count = 0;
|
|
|
move_count++;
|
|
|
|
|
|
// 每10次移动一次障碍物
|
|
|
if (obstacles_mode == 2 && move_count % 10 == 0)
|
|
|
{
|
|
|
// 创建临时障碍物数组
|
|
|
int temp_obs[ROW * COL][2];
|
|
|
int count = 0;
|
|
|
|
|
|
// 收集所有障碍物位置
|
|
|
for (int i = 1; i < ROW - 1; i++)
|
|
|
{
|
|
|
for (int j = 1; j < COL - 1; j++)
|
|
|
{
|
|
|
if (face[i][j] == OBSTACLE)
|
|
|
{
|
|
|
temp_obs[count][0] = i;
|
|
|
temp_obs[count][1] = j;
|
|
|
count++;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 移动每个障碍物
|
|
|
for (int idx = 0; idx < count; idx++)
|
|
|
{
|
|
|
int i = temp_obs[idx][0];
|
|
|
int j = temp_obs[idx][1];
|
|
|
|
|
|
// 随机选择移动方向
|
|
|
int dir = rand() % 4;
|
|
|
int ni = i, nj = j;
|
|
|
|
|
|
switch (dir)
|
|
|
{
|
|
|
case 0: ni--; break; // 上
|
|
|
case 1: ni++; break; // 下
|
|
|
case 2: nj--; break; // 左
|
|
|
case 3: nj++; break; // 右
|
|
|
}
|
|
|
|
|
|
// 检查目标位置是否有效
|
|
|
if (ni > 0 && ni < ROW - 1 && nj > 0 && nj < COL - 1 &&
|
|
|
face[ni][nj] == KONG)
|
|
|
{
|
|
|
// 清除原位置
|
|
|
face[i][j] = KONG;
|
|
|
CursorJump(2 * j, i);
|
|
|
printf(" ");
|
|
|
|
|
|
// 设置新位置
|
|
|
face[ni][nj] = OBSTACLE;
|
|
|
color(8);
|
|
|
CursorJump(2 * nj, ni);
|
|
|
printf("■");
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 添加特殊食物
|
|
|
void AddSpecialFood()
|
|
|
{
|
|
|
if (special_food_active) return;
|
|
|
|
|
|
int i, j, attempts = 0;
|
|
|
|
|
|
do {
|
|
|
i = rand() % (ROW - 2) + 1;
|
|
|
j = rand() % (COL - 2) + 1;
|
|
|
attempts++;
|
|
|
if (attempts > 100) return;
|
|
|
} while (face[i][j] != KONG);
|
|
|
|
|
|
face[i][j] = SPECIAL_FOOD;
|
|
|
special_food_x = j;
|
|
|
special_food_y = i;
|
|
|
special_food_active = 1;
|
|
|
special_food_timer = 0;
|
|
|
|
|
|
color(14); // 黄色
|
|
|
CursorJump(2 * j, i);
|
|
|
printf("★");
|
|
|
}
|
|
|
|
|
|
// 移除特殊食物
|
|
|
void RemoveSpecialFood()
|
|
|
{
|
|
|
if (!special_food_active) return;
|
|
|
|
|
|
face[special_food_y][special_food_x] = KONG;
|
|
|
special_food_active = 0;
|
|
|
|
|
|
CursorJump(2 * special_food_x, special_food_y);
|
|
|
printf(" ");
|
|
|
}
|
|
|
|
|
|
// 判断得分与结束 (修改:返回游戏状态)
|
|
|
int JudgeFunc(int x, int y)
|
|
|
{
|
|
|
int new_x = snake.x + x;
|
|
|
int new_y = snake.y + y;
|
|
|
|
|
|
// 穿墙模式处理
|
|
|
if (pass_wall)
|
|
|
{
|
|
|
if (new_x == 0) new_x = COL - 2;
|
|
|
else if (new_x == COL - 1) new_x = 1;
|
|
|
if (new_y == 0) new_y = ROW - 2;
|
|
|
else if (new_y == ROW - 1) new_y = 1;
|
|
|
}
|
|
|
|
|
|
// 检查边界
|
|
|
if (new_x <= 0 || new_x >= COL - 1 || new_y <= 0 || new_y >= ROW - 1)
|
|
|
{
|
|
|
if (!pass_wall) // 非穿墙模式撞墙结束游戏
|
|
|
{
|
|
|
return 1; // 游戏结束
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 检查新位置
|
|
|
switch (face[new_y][new_x])
|
|
|
{
|
|
|
case FOOD:
|
|
|
snake.len++;
|
|
|
grade += 10;
|
|
|
UpdateScoreDisplay();
|
|
|
RandFood();
|
|
|
|
|
|
// 每100分增加一个特殊食物
|
|
|
if (grade % 100 == 0 && !special_food_active)
|
|
|
{
|
|
|
AddSpecialFood();
|
|
|
}
|
|
|
return 0; // 继续游戏
|
|
|
|
|
|
case SPECIAL_FOOD:
|
|
|
grade += 50;
|
|
|
UpdateScoreDisplay();
|
|
|
RemoveSpecialFood();
|
|
|
|
|
|
// 增加游戏速度
|
|
|
if (game_speed > 500)
|
|
|
{
|
|
|
ChangeSpeed(-200);
|
|
|
}
|
|
|
return 0; // 继续游戏
|
|
|
|
|
|
case OBSTACLE:
|
|
|
case BODY:
|
|
|
return 1; // 游戏结束
|
|
|
|
|
|
default:
|
|
|
return 0; // 继续游戏
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 打印蛇与覆盖蛇
|
|
|
void DrawSnake(int flag)
|
|
|
{
|
|
|
if (flag == 1) // 打印蛇
|
|
|
{
|
|
|
color(10); // 绿色蛇头
|
|
|
CursorJump(2 * snake.x, snake.y);
|
|
|
printf("■");
|
|
|
|
|
|
for (int i = 0; i < snake.len; i++)
|
|
|
{
|
|
|
// 蛇身颜色渐变
|
|
|
color(2 + (i % 6));
|
|
|
CursorJump(2 * body[i].x, body[i].y);
|
|
|
printf("□");
|
|
|
}
|
|
|
}
|
|
|
else // 覆盖蛇
|
|
|
{
|
|
|
if (body[snake.len - 1].x != 0)
|
|
|
{
|
|
|
CursorJump(2 * body[snake.len - 1].x, body[snake.len - 1].y);
|
|
|
printf(" ");
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 移动蛇
|
|
|
void MoveSnake(int x, int y)
|
|
|
{
|
|
|
DrawSnake(0);
|
|
|
face[body[snake.len - 1].y][body[snake.len - 1].x] = KONG;
|
|
|
face[snake.y][snake.x] = BODY;
|
|
|
|
|
|
// 更新蛇身位置
|
|
|
for (int i = snake.len - 1; i > 0; i--)
|
|
|
{
|
|
|
body[i].x = body[i - 1].x;
|
|
|
body[i].y = body[i - 1].y;
|
|
|
}
|
|
|
|
|
|
body[0].x = snake.x;
|
|
|
body[0].y = snake.y;
|
|
|
|
|
|
// 更新蛇头位置
|
|
|
snake.x += x;
|
|
|
snake.y += y;
|
|
|
|
|
|
// 穿墙处理
|
|
|
if (pass_wall)
|
|
|
{
|
|
|
if (snake.x == 0) snake.x = COL - 2;
|
|
|
else if (snake.x == COL - 1) snake.x = 1;
|
|
|
if (snake.y == 0) snake.y = ROW - 2;
|
|
|
else if (snake.y == ROW - 1) snake.y = 1;
|
|
|
}
|
|
|
|
|
|
// 标记新的蛇头位置
|
|
|
face[snake.y][snake.x] = HEAD;
|
|
|
|
|
|
DrawSnake(1);
|
|
|
}
|
|
|
|
|
|
// 改变游戏速度
|
|
|
void ChangeSpeed(int delta)
|
|
|
{
|
|
|
game_speed += delta;
|
|
|
if (game_speed < 100) game_speed = 100; // 设置最小速度
|
|
|
if (game_speed > 1000) game_speed = 1000; // 设置最大速度
|
|
|
UpdateScoreDisplay();
|
|
|
}
|
|
|
|
|
|
// 保存游戏
|
|
|
void SaveGame()
|
|
|
{
|
|
|
FILE* pf = fopen("snake_save.dat", "wb");
|
|
|
if (pf == NULL) return;
|
|
|
|
|
|
// 保存游戏状态
|
|
|
fwrite(&grade, sizeof(int), 1, pf);
|
|
|
fwrite(&snake, sizeof(struct Snake), 1, pf);
|
|
|
fwrite(body, sizeof(struct Body), snake.len, pf);
|
|
|
fwrite(face, sizeof(int), ROW * COL, pf);
|
|
|
fwrite(&obstacles_mode, sizeof(int), 1, pf);
|
|
|
fwrite(&pass_wall, sizeof(int), 1, pf);
|
|
|
fwrite(&game_speed, sizeof(int), 1, pf);
|
|
|
fwrite(&special_food_active, sizeof(int), 1, pf);
|
|
|
|
|
|
if (special_food_active)
|
|
|
{
|
|
|
fwrite(&special_food_x, sizeof(int), 1, pf);
|
|
|
fwrite(&special_food_y, sizeof(int), 1, pf);
|
|
|
}
|
|
|
|
|
|
fclose(pf);
|
|
|
|
|
|
// 提示保存成功
|
|
|
CursorJump(COL, ROW + 2);
|
|
|
color(10);
|
|
|
printf("游戏已保存!");
|
|
|
Sleep(1000);
|
|
|
CursorJump(COL, ROW + 2);
|
|
|
printf(" ");
|
|
|
}
|
|
|
|
|
|
// 加载游戏
|
|
|
void LoadGame()
|
|
|
{
|
|
|
FILE* pf = fopen("snake_save.dat", "rb");
|
|
|
if (pf == NULL) return;
|
|
|
|
|
|
// 清除当前游戏状态
|
|
|
system("cls");
|
|
|
InitInterface();
|
|
|
|
|
|
// 加载游戏状态
|
|
|
fread(&grade, sizeof(int), 1, pf);
|
|
|
fread(&snake, sizeof(struct Snake), 1, pf);
|
|
|
fread(body, sizeof(struct Body), snake.len, pf);
|
|
|
fread(face, sizeof(int), ROW * COL, pf);
|
|
|
fread(&obstacles_mode, sizeof(int), 1, pf);
|
|
|
fread(&pass_wall, sizeof(int), 1, pf);
|
|
|
fread(&game_speed, sizeof(int), 1, pf);
|
|
|
fread(&special_food_active, sizeof(int), 1, pf);
|
|
|
|
|
|
if (special_food_active)
|
|
|
{
|
|
|
fread(&special_food_x, sizeof(int), 1, pf);
|
|
|
fread(&special_food_y, sizeof(int), 1, pf);
|
|
|
}
|
|
|
|
|
|
fclose(pf);
|
|
|
|
|
|
// 重新绘制游戏界面
|
|
|
for (int i = 0; i < ROW; i++)
|
|
|
{
|
|
|
for (int j = 0; j < COL; j++)
|
|
|
{
|
|
|
switch (face[i][j])
|
|
|
{
|
|
|
case WALL:
|
|
|
color(6);
|
|
|
CursorJump(2 * j, i);
|
|
|
printf("■");
|
|
|
break;
|
|
|
|
|
|
case FOOD:
|
|
|
color(12);
|
|
|
CursorJump(2 * j, i);
|
|
|
printf("●");
|
|
|
break;
|
|
|
|
|
|
case OBSTACLE:
|
|
|
color(8);
|
|
|
CursorJump(2 * j, i);
|
|
|
printf("■");
|
|
|
break;
|
|
|
|
|
|
case SPECIAL_FOOD:
|
|
|
color(14);
|
|
|
CursorJump(2 * j, i);
|
|
|
printf("★");
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
DrawSnake(1);
|
|
|
UpdateScoreDisplay();
|
|
|
|
|
|
// 提示加载成功
|
|
|
CursorJump(COL, ROW + 2);
|
|
|
color(10);
|
|
|
printf("游戏已加载!");
|
|
|
Sleep(1000);
|
|
|
CursorJump(COL, ROW + 2);
|
|
|
printf(" ");
|
|
|
}
|
|
|
|
|
|
// 显示帮助信息
|
|
|
void ShowHelp()
|
|
|
{
|
|
|
system("cls");
|
|
|
color(11); // 浅蓝色
|
|
|
CursorJump(COL / 2 - 10, 2);
|
|
|
printf("========== 贪吃蛇游戏帮助 ==========");
|
|
|
|
|
|
color(10); // 绿色
|
|
|
CursorJump(COL / 4, 4);
|
|
|
printf("控制方式:");
|
|
|
CursorJump(COL / 4, 5);
|
|
|
printf("方向键: 控制蛇的移动方向");
|
|
|
CursorJump(COL / 4, 6);
|
|
|
printf("空格键: 暂停/继续游戏");
|
|
|
CursorJump(COL / 4, 7);
|
|
|
printf("ESC键: 退出游戏");
|
|
|
CursorJump(COL / 4, 8);
|
|
|
printf("S键: 保存游戏");
|
|
|
CursorJump(COL / 4, 9);
|
|
|
printf("L键: 加载游戏");
|
|
|
|
|
|
CursorJump(COL / 4, 11);
|
|
|
printf("游戏规则:");
|
|
|
CursorJump(COL / 4, 12);
|
|
|
printf("1. 吃到红色食物 ● 得10分,蛇身变长");
|
|
|
CursorJump(COL / 4, 13);
|
|
|
printf("2. 吃到黄色食物 ★ 得50分,增加速度");
|
|
|
CursorJump(COL / 4, 14);
|
|
|
printf("3. 撞到墙壁、障碍物或自身游戏结束");
|
|
|
|
|
|
CursorJump(COL / 4, 16);
|
|
|
printf("特殊功能:");
|
|
|
CursorJump(COL / 4, 17);
|
|
|
printf("穿墙模式: 可以穿过墙壁");
|
|
|
CursorJump(COL / 4, 18);
|
|
|
printf("障碍物模式: 无、固定障碍物、移动障碍物");
|
|
|
|
|
|
color(14); // 黄色
|
|
|
CursorJump(COL / 2 - 10, ROW - 2);
|
|
|
printf("按任意键返回主菜单...");
|
|
|
_getch(); // 添加等待按键
|
|
|
}
|
|
|
|
|
|
// 显示游戏结束界面
|
|
|
void ShowGameOver()
|
|
|
{
|
|
|
system("cls");
|
|
|
color(12); // 红色
|
|
|
CursorJump(COL / 2 - 10, ROW / 2 - 3);
|
|
|
|
|
|
// 计算游戏时间
|
|
|
time_t end_time = time(NULL);
|
|
|
int game_time = (int)difftime(end_time, start_time);
|
|
|
int minutes = game_time / 60;
|
|
|
int seconds = game_time % 60;
|
|
|
|
|
|
// 显示得分信息
|
|
|
if (grade > max)
|
|
|
{
|
|
|
printf("恭喜打破记录!新纪录: %d", grade);
|
|
|
max = grade;
|
|
|
WriteGrade();
|
|
|
}
|
|
|
else if (grade == max)
|
|
|
{
|
|
|
printf("平最高记录!得分: %d", grade);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
printf("当前得分: %d (最高: %d)", grade, max);
|
|
|
}
|
|
|
|
|
|
// 显示游戏信息
|
|
|
CursorJump(COL / 2 - 10, ROW / 2);
|
|
|
printf("游戏时间: %02d:%02d", minutes, seconds);
|
|
|
CursorJump(COL / 2 - 10, ROW / 2 + 2);
|
|
|
printf("G A M E O V E R");
|
|
|
|
|
|
// 显示选项
|
|
|
color(14); // 黄色
|
|
|
CursorJump(COL / 2 - 10, ROW / 2 + 4);
|
|
|
printf("按任意键返回主菜单...");
|
|
|
_getch(); // 添加等待按键
|
|
|
}
|
|
|
|
|
|
// 游戏主体逻辑函数
|
|
|
void Game()
|
|
|
{
|
|
|
// 游戏主循环
|
|
|
int key = 0;
|
|
|
int dx = 1, dy = 0; // 初始向右移动
|
|
|
int last_dx = dx, last_dy = dy; // 记录上一次移动方向
|
|
|
int game_over = 0; // 游戏结束标志
|
|
|
DWORD last_move_time = GetTickCount(); // 记录上次移动时间
|
|
|
|
|
|
while (!game_over)
|
|
|
{
|
|
|
// 处理输入
|
|
|
if (_kbhit())
|
|
|
{
|
|
|
key = _getch();
|
|
|
switch (key)
|
|
|
{
|
|
|
case UP:
|
|
|
if (last_dy == 0) { dx = 0; dy = -1; }
|
|
|
break;
|
|
|
case DOWN:
|
|
|
if (last_dy == 0) { dx = 0; dy = 1; }
|
|
|
break;
|
|
|
case LEFT:
|
|
|
if (last_dx == 0) { dx = -1; dy = 0; }
|
|
|
break;
|
|
|
case RIGHT:
|
|
|
if (last_dx == 0) { dx = 1; dy = 0; }
|
|
|
break;
|
|
|
case SPACE:
|
|
|
game_paused = !game_paused;
|
|
|
if (game_paused) {
|
|
|
CursorJump(COL, ROW + 2);
|
|
|
color(12);
|
|
|
printf("游戏暂停中...");
|
|
|
}
|
|
|
else {
|
|
|
CursorJump(COL, ROW + 2);
|
|
|
printf(" ");
|
|
|
}
|
|
|
break;
|
|
|
case ESC:
|
|
|
return; // 退出游戏
|
|
|
case 's':
|
|
|
case 'S':
|
|
|
SaveGame();
|
|
|
break;
|
|
|
case 'l':
|
|
|
case 'L':
|
|
|
LoadGame();
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (game_paused)
|
|
|
{
|
|
|
Sleep(100);
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
// 更新特殊食物计时器
|
|
|
if (special_food_active)
|
|
|
{
|
|
|
special_food_timer++;
|
|
|
if (special_food_timer > 100)
|
|
|
{
|
|
|
RemoveSpecialFood();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 移动障碍物
|
|
|
if (obstacles_mode == 2)
|
|
|
{
|
|
|
DWORD current_time = GetTickCount();
|
|
|
if (current_time - last_move_time > 500) { // 每500毫秒移动一次
|
|
|
MoveObstacles();
|
|
|
last_move_time = current_time;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 定时移动蛇
|
|
|
DWORD current_time = GetTickCount();
|
|
|
if (current_time - last_move_time > game_speed)
|
|
|
{
|
|
|
last_move_time = current_time;
|
|
|
|
|
|
// 判断是否结束
|
|
|
if (JudgeFunc(dx, dy))
|
|
|
{
|
|
|
game_over = 1;
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
// 移动蛇
|
|
|
MoveSnake(dx, dy);
|
|
|
|
|
|
// 保存当前移动方向
|
|
|
last_dx = dx;
|
|
|
last_dy = dy;
|
|
|
}
|
|
|
|
|
|
// 小延迟,减少CPU占用
|
|
|
Sleep(10);
|
|
|
}
|
|
|
|
|
|
// 游戏结束处理
|
|
|
ShowGameOver();
|
|
|
}
|
|
|
|
|
|
// 显示开始菜单
|
|
|
void ShowMenu()
|
|
|
{
|
|
|
system("cls");
|
|
|
color(11);
|
|
|
CursorJump(COL / 2 - 5, ROW / 4);
|
|
|
printf(" 小张版贪吃蛇");
|
|
|
color(10);
|
|
|
CursorJump(COL / 2 - 5, ROW / 4 + 2);
|
|
|
printf("1. 开始游戏");
|
|
|
CursorJump(COL / 2 - 5, ROW / 4 + 3);
|
|
|
printf("2. 游戏设置");
|
|
|
CursorJump(COL / 2 - 5, ROW / 4 + 4);
|
|
|
printf("3. 游戏帮助");
|
|
|
CursorJump(COL / 2 - 5, ROW / 4 + 5);
|
|
|
printf("4. 退出游戏");
|
|
|
|
|
|
color(14);
|
|
|
CursorJump(COL / 2 - 5, ROW / 4 + 7);
|
|
|
printf("请选择: ");
|
|
|
|
|
|
char choice = _getch();
|
|
|
switch (choice)
|
|
|
{
|
|
|
case '1': // 开始游戏
|
|
|
game_started = 1;
|
|
|
start_time = time(NULL);
|
|
|
break;
|
|
|
|
|
|
case '2': // 游戏设置
|
|
|
{
|
|
|
system("cls");
|
|
|
color(11);
|
|
|
CursorJump(COL / 2 - 5, ROW / 4);
|
|
|
printf("★ 游戏设置 ★");
|
|
|
|
|
|
int setting = 1;
|
|
|
while (setting)
|
|
|
{
|
|
|
color(10);
|
|
|
CursorJump(COL / 2 - 10, ROW / 4 + 2);
|
|
|
printf("a. 游戏速度: %d", 4000 / game_speed);
|
|
|
CursorJump(COL / 2 - 10, ROW / 4 + 3);
|
|
|
printf("b. 障碍物模式: %s",
|
|
|
obstacles_mode == 0 ? "无" :
|
|
|
obstacles_mode == 1 ? "固定障碍物" : "移动障碍物");
|
|
|
CursorJump(COL / 2 - 10, ROW / 4 + 4);
|
|
|
printf("c. 穿墙模式: %s", pass_wall ? "开启" : "关闭");
|
|
|
CursorJump(COL / 2 - 10, ROW / 4 + 5);
|
|
|
printf("d. 返回主菜单");
|
|
|
|
|
|
color(14);
|
|
|
CursorJump(COL / 2 - 10, ROW / 4 + 7);
|
|
|
printf("请选择: ");
|
|
|
|
|
|
char option = _getch();
|
|
|
switch (option)
|
|
|
{
|
|
|
case 'a': // 调整速度
|
|
|
system("cls");
|
|
|
color(11);
|
|
|
CursorJump(COL / 2 - 5, ROW / 4);
|
|
|
printf("★ 设置游戏速度 ★");
|
|
|
color(10);
|
|
|
CursorJump(COL / 2 - 10, ROW / 4 + 2);
|
|
|
printf("当前速度: %d", 4000 / game_speed);
|
|
|
CursorJump(COL / 2 - 10, ROW / 4 + 3);
|
|
|
printf("按 + 加速,按 - 减速");
|
|
|
CursorJump(COL / 2 - 10, ROW / 4 + 4);
|
|
|
printf("按回车返回");
|
|
|
|
|
|
while (1)
|
|
|
{
|
|
|
char speedKey = _getch();
|
|
|
if (speedKey == '+') ChangeSpeed(-100);
|
|
|
else if (speedKey == '-') ChangeSpeed(100);
|
|
|
else if (speedKey == ENTER) break;
|
|
|
|
|
|
CursorJump(COL / 2, ROW / 4 + 2);
|
|
|
printf("%d ", 4000 / game_speed);
|
|
|
}
|
|
|
system("cls");
|
|
|
break;
|
|
|
|
|
|
case 'b': // 障碍物模式
|
|
|
obstacles_mode = (obstacles_mode + 1) % 3;
|
|
|
break;
|
|
|
|
|
|
case 'c': // 穿墙模式
|
|
|
pass_wall = !pass_wall;
|
|
|
break;
|
|
|
|
|
|
case 'd': // 返回
|
|
|
setting = 0;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
system("cls");
|
|
|
ShowMenu();
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
case '3': // 游戏帮助
|
|
|
ShowHelp();
|
|
|
system("cls");
|
|
|
ShowMenu();
|
|
|
break;
|
|
|
|
|
|
case '4': // 退出游戏
|
|
|
exit(0);
|
|
|
|
|
|
default:
|
|
|
ShowMenu();
|
|
|
break;
|
|
|
}
|
|
|
} |