基于C语言的双人贪吃蛇游戏程序设计
实现目标
制作一个两个两个人一起同时玩的双人贪吃蛇游戏,有比分并记录历史成绩
(1) 打开游戏时能够自动播放背景音乐
(2) 开始菜单,显示历史用户名及其对应的成绩
(3) 开始菜单可以输入两人的用户名
(4) P1 可以通过w,s,a,d来控制蛇1的移动
(5) P2 可以通过小键盘的“上,下,左,右”来控制蛇2的移动
(6) 食物在每次被吃后都会随机出现在地图
(7) 贪吃蛇吃到食物后长度会增加1
(8) 撞墙和撞到自己就会结束游戏,下一界面能够输出死因
(9) 随着分数增加,蛇移动会越来越快
(10) 每一场的两人的分数及用户名都会被记录
系统三大界面功能示意图
函数功能设计
函数名 | 函数功能 |
---|---|
welcome | 打印开始界面 |
Finish | 打印结束界面,清空贪吃蛇结构占用的内存 |
creatgraph | 打印围墙 |
gotoxy | 移动光标 |
color | 设置颜色 |
gotoprintboundary | 跳转打印边界 |
gotoprintsnake | 打印贪吃蛇结构 |
gotodelete | 跳转删除 |
creatsnake | 初始化蛇 |
creatfood | 产生食物 |
ClickControl | 获取键盘信号 |
Judge | 判断蛇是否死亡 |
MovingBody | 控制蛇的移动 |
Eating | 蛇吃到食物后的操作 |
ChangeBody1 | 蛇1的坐标变换 |
ChangeBody2 | 蛇2的坐标变换 |
record | 文件操作记录成绩 |
printrecord | 读取文件,输出成绩 |
各函数调用关系如图所示:
该程序中的数据结构与算法
- 结构体:
struct Food
{
int x;
int y;
} food;
//这是产生食物的结构体
- 结构体数组:
typedef struct
{
char name[10];
int score;
} Rank;
Rank rank[2];
//这是保存用户名及其对应分数的结构体数组
- 链表:
typedef struct Snakes
{
int x;
int y;
struct Snakes* next;
} snake;
snake* head;
snake* head2;
//本程序中两条蛇的产生及控制均使用链表存储
- 文件输入操作:
void record()
{
FILE *fp;
fp = fopen("data.txt", "a");
for (int i = 0; i < 2; i++)
{
fprintf(fp, "%85s|%10d\n", (rank + i)->name, (rank + i)->score);
}
fclose(fp);
}
//这是创建文件,并且保存用户的用户名及相应的分数
- 文件读取操作:
int printrecord()
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY);
gotoxy(75, 15);
printf("%10s|%10s\n", "玩家", "分数");
FILE *pfile = fopen("data.txt", "rb");
if (pfile == NULL) {
return 0;
}
//读取文件长度,读完后把文件指针复位到开头
fseek(pfile, 0, SEEK_END);
int file_length = ftell(pfile);
rewind(pfile);
//申请一段内存空间用来放文件中的文本内容,并置零
int text_length = file_length * sizeof(char) + 1;
char* text_buffer = (char*)malloc(text_length);
memset(text_buffer, 0, text_length);
//把文件文本内容读到申请的内存空间中
int read_length = fread(text_buffer, 1, file_length, pfile);
if (read_length != file_length) {
return 0;
}
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_INTENSITY);
//打印文件文本内容,释放申请的内存空间,关闭文件流
printf(text_buffer);
free(text_buffer);
fclose(pfile);
return 0;
}
//这是读取文件
用到了多种数据结构
- 添加音效
#include <mmsystem.h>
#pragma comment (lib, "winmm.lib")
//分别使用这两个头文件和外部库文件
PlaySound("music.wav", NULL, SND_FILENAME | SND_ASYNC | SND_LOOP);
//使用PlaySound函数播放音乐
- 使用了链表的尾插法操作
函数流程图举例
- 蛇移动函数的流程图:
- 判断蛇是否死亡的流程图:
部分结构的测试案例
-
左侧提示输入两个人的用户名,按空格确定。右侧在第一次未创建成绩文件是为空,不会输出乱码
-
两位玩家的“wasd”、“上下左右”都可以成功控制方向
-
在输出与蛇运动方向相反的按键时,蛇保持原来方向运动
-
食物被吃后自动再生成,蛇边长,并且分数增加显示在下面
-
蛇撞墙后死亡,显示死因
-
蛇撞到自己后死亡,显示死因。
-
在非第一次玩此游戏时,打开游戏会在右下角输出历史用户及成绩:
宏定义、头文件、全局变量及调用函数
#include<stdio.h>
#include<string.h>
#include<windows.h>
#include<time.h>
#include<conio.h>
#include <mmsystem.h>
#pragma comment (lib, "winmm.lib")
#define up 'w'
#define down 's'
#define left 'a'
#define right 'd'
/*地图参数*/
#define height 26
#define wide 116
void welcome(); // 开始界面
void Finish(int x); // 结束界面
void creatgraph(); // 围墙打印
//***
void gotoxy(int x, int y); // 光标跳转
void color(short x);
void gotoprintboundary(int x, int y); // 跳转打印边界
void gotoprintsnake(int x, int y); //打印蛇
void gotodelete(int x, int y); // 跳转删除蛇
void creatsnake();
//***
void creatfood(); // 食物产生
int ClickControl(); // 获取蛇1键盘信号
int Judge(); // 游戏结束判断
void MovingBody(); // 蛇的移动
void Eating(); // 蛇吃到东西后的操作(伸长)
void ChangeBody(int x, int y); // 蛇的坐标变换
void ChangeBody2(int x, int y);
void record(); //文件操作记录成绩
int printrecord(); //读取文件,打印成绩
//蛇结构体
typedef struct Snakes
{
int x;
int y;
struct Snakes* next;
} snake;
snake* head;
snake* head2;
// 申明并定义食物
struct Food
{
int x;
int y;
} food;
//用户数据
typedef struct
{
char name[10];
int score;
} Rank;
Rank rank[2];
char click = 1; // 记录敲下的键盘按键
char foreclick = 1;//键盘按键的历史记录值
char foreclick2 = 1;
char click2 = 1;
int speed; // 延迟的毫秒数
源代码下载
下载链接如下: