写在开始
上一篇博客的链接为:用C实现贪吃蛇,看看你的C学得怎样?(三)
任务清单
本次项目的任务清单暂定如下:
1.创建地图和起始界面(已完成)
2.创建蛇,食物、超级食物投放(已完成)
3.通过键盘控制蛇的移动(已完成)
4.基本功能(蛇吃食物,蛇的增长等)
5.判断游戏是否结束
6.计算游戏时长
7.加入最高纪录功能
8.游戏等级进度
9.游戏重新开始
代码实现
//1.定义头文件
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<time.h>
#include<windows.h>
//2.宏定义声明
#define X 23 //定义地图大小
#define Y 50
#define UP 0 //0为上,1为下,2为左,3为右
#define DOWN 1
#define LEFT 2
#define RIGHT 3
char map[X][Y]; //地图数组
int s[X*Y][2]; //蛇身坐标数组
int sLength; //蛇的长度
int direction; //蛇的方向
int delay = 250; //通过延迟控制蛇的行进速度
int score = 0; //得分
int level = 1;
bool eated = false; //标记是否吃到食物
//定义主函数
int main()
{
init(); //初始化
menu(); //生成界面
system("cls"); //清除屏幕内容
draw_map(); //画地图
food(); //画食物
s_food();
while (1)
{
draw_snake(); //画蛇
Sleep(delay); //等待一段时间
key();
move(); //移动蛇(主要是修改蛇身数组的数据)
if (map[s[0][0]][s[0][1]] == -1) //如果蛇头碰到食物,就重新投放食物,并且把食物点重置为0
{
eated = true; //标记已经吃到食物
score += 20;
sLength++;
if (game_level() != level)
{
delay -= 10;
level++;
}
eated = false; //设置为false,不然无限变长
food();
map[s[0][0]][s[0][1]] = 0; //去掉食物
}
if (map[s[0][0]][s[0][1]] == 2)
{
eated = true;
score += 50;
sLength += 2;
if (game_level() != level)
{
delay -= 10;
level++;
}
eated = false; //设置为false,不然无限变长
s_food();
map[s[0][0]][s[0][1]] = 0;
}
if (gameover())
{
system("cls"); //清除屏幕内容
printf("Game Over\n");
printf("最终得分:%d\n\n", score);
break;
}
}
}
//定义函数
void init() //程序开始时的初始化操作
{
CONSOLE_CURSOR_INFO cursor_info = { 1, 0 };
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info); //隐藏关标
int i, j;
for (i = 0; i<X; i++)
{
map[i][0] = 1; //让第一列为1
map[i][Y - 1] = 1; //让最后一列为1
}
for (j = 0; j<Y; j++)
{
map[0][j] = 1; //让第一行为1
map[X - 1][j] = 1; //让最后一行为1
}
sLength = 4; //让蛇的最初长度为4
s[0][0] = X / 2;
s[0][1] = Y / 2; //给蛇头坐标赋值
for (i = 1; i<4; i++)
{
s[i][0] = s[0][0] + i;
s[i][1] = s[0][1]; //给刚开始的蛇身几个初始坐标
}
}
void gotoxy(int i, int j) //移动光标
{
COORD position = { j, i };
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), position);
}
void draw_map() //创建地图
{
gotoxy(0, 0);
int i, j;
for (i = 0; i<X; i++) //两重for循环遍历数组
{
for (j = 0; j<Y; j++)
{
if (map[i][j] == 0) //为0输出空格
printf(" ");
else if(map[i][j]==1) //为1输出#
printf("#");
}
printf("\n"); //别忘了换行
}
}
void menu() //初始菜单界面
{
printf("\n\n\n\n\n\n\t\t\t********************贪吃蛇(实验版)******************\t\t\t\n\n");
printf("\t\t\t********************欢迎参与游戏测试******************\t\t\t\n\n");
printf("\t\t\t********************按任意键开始游戏******************\t\t\t\n\n");
printf("\t\t\t\t\t 职业工具人\n\n");
printf("\t\t\t\t请先确保处于英语输入法,否则无法进行游戏");
_getch(); //保持界面获取字符
}
int check(int ii, int jj) //判断这个点能不能放食物,可以放返回1,不能放返回0
{
if (map[ii][jj] == 1) //如果有障碍物,返回0
return 0;
int i;
for (i = 0; i<sLength; i++)
{
if (ii == s[i][0] && jj == s[i][1]) //如果和其中一个蛇身重合,就返回0
return 0;
}
if (ii == 0 || ii == X - 1 || jj == 0 || jj == Y - 1) //如果在边界上面,返回0
return 0;
if(map[ii][jj]==-1) //若该点有食物,则不生成超级食物
return 0;
return 1; //最后筛选 过后的是符合条件的点
}
void food() //生成食物
{
int i, j;
do
{
i = rand() % X; //生成0~X-1之间的一个数
j = rand() % Y; //生成0~Y-1之间的一个数
}
while (check(i, j) == 0); //生成点直到满足条件
map[i][j] = -1; //标记为食物
gotoxy(i, j);
printf("*"); //画出食物
}
void s_food() //生成超级食物
{
int i, j;
do
{
i = rand() % X;
j = rand() % Y;
}
while (check(i, j) == 0);
map[i][j] = 2;
gotoxy(i, j);
printf("$");
}
void draw_snake() //画蛇
{
int i;
for (i = 0; i<sLength; i++)
{
gotoxy(s[i][0], s[i][1]); //移动关标到蛇的坐标
printf("@"); //在这个位置画蛇
}
}
void key() //定义key,用于接受按键键值
{
if (_kbhit() != 0) //如果有键盘输入
{
char in;
while (!_kbhit() == 0) //如果玩家输入了多个按键,以最后一个按键为准
in = _getch();
switch (in)
{
case 'w':
case 'W':
if (direction != DOWN) //不能后退
direction = UP;
break;
case 's':
case 'S':
if (direction != UP)
direction = DOWN;
break;
case 'a':
case 'A':
if (direction != RIGHT)
direction = LEFT;
break;
case 'd':
case 'D':
if (direction != LEFT)
direction = RIGHT;
break;
}
}
}
void move() //控制蛇的移动
{
int i;
gotoxy(s[sLength - 1][0], s[sLength - 1][1]);
printf(" "); //在尾巴上面画空格以擦除尾巴
for (i = sLength - 1; i > 0; i--) //从尾巴开始,每一个点的位置等于它前面一个点的位置
{
s[i][0] = s[i - 1][0];
s[i][1] = s[i - 1][1];
}
switch (direction)
{
case UP:
s[0][0]--;
break;
case DOWN:
s[0][0]++;
break;
case LEFT:
s[0][1]--;
break;
case RIGHT:
s[0][1]++;
break;
}
}
bool gameover() //判断是不是结束游戏
{
int sX = s[0][0], sY = s[0][1]; //蛇头的x坐标和y坐标
if (sX == 0 || sX == X - 1 || sY == 0 || sY == Y - 1)
GameOver = true;
for (int i = 1; i<sLength; i++) //判断有没有吃到自己
{
if (s[i][0] == sX && s[i][1] == sY)
GameOver = true;
}
return GameOver;
}
int game_level() //速度等级构建
{
int Level = score / 100 + 1;
return Level;
}
总结
本次主要是完善了蛇的移动速度、蛇吃到食物以后的变化、游戏的终止条件,到此为止,整个贪吃蛇的基本功能已经完成了。
接下来就是完善一些细节的功能,让功能更加完善!
结语
如果说这篇文章有让你学到一定的知识的话,不妨点个赞和关注,让博主能够看到,如果讲解中有什么错误和疏忽,也劳烦在评论中指出或提问,博主会第一时间进行更新和答复,谢谢!