在学习完c语言基础之后,我们就可以利用c语言来写一个小游戏----贪吃蛇
下面为所需用到的头文件
#include <stdio.h>
#include <windows.h>
#include <time.h>
#include <conio.h>
原理
贪吃蛇无非就是在一个有限的地图上进行运动,通过到达一个特定地点(吃食物)来增加体型的游戏;
- 首先,你进去得先有个场啊,不然在哪跑呢(地图初始化);
- 有场地了,肯定得有蛇啊,不然玩啥呢(蛇的初始化);
- 再还有就是吃的了,没吃的,游戏也玩不了啊(食物的更新);
- 那现在啥都有了,蛇,你得动起来啊,(蛇的运动);
- 蛇开始动了,万一,它碰到啥旮旮角角的,凉了,游戏不就结束了嘛(蛇死亡判断);
- 如果,还想来点花哨的,你也可以加个速度控制系统;
具体实现
-从第一个开始, 如何打印地图
开始使用我们的第一个函数—(光标位置函数)
void gotoxy(int x, int y)
{
HANDLE hout;
COORD cor;
hout = GetStdHandle(STD_OUTPUT_HANDLE);
cor.X = y;
cor.Y = x;
SetConsoleCursorPosition(hout, cor);
}
这里的x,y分别对应着小黑框的坐标,x代表第几行,y代表第几列;
这里的行和列与二维数组一样,都是从0开始的;
所以我们只需要利用for循环,将光标转移去合适的地方,打印出地图即可
这里我#define MAP_LEN 20;
for (int j = 0; j < MAP_LEN; j++)
{
gotoxy(0, j);
printf("#");
gotoxy(MAP_LEN - 1, j);
printf("#");
}
for (int j = 0; j < MAP_LEN; j++)
{
gotoxy(j, 0);
printf("#");
gotoxy(j, MAP_LEN - 1);
printf("#");
}
就像这样;
然后就是蛇的初始化,那蛇都有什么性质呢?
- 蛇的大小,及蛇每个节点的坐标位置;
- 蛇的长度;
- 蛇的速度;
我们可以利用struct来将其整理在一起
定义 int len 为蛇的长度
int speed 为蛇的速度
用两个数组来表示蛇每个节点的横坐标和纵坐标;
int x[MAX],y[MAX];
就像这样:
struct Snake
{
int x[50];
int y[50];
int len;
int speed;
}snake;
接着,再把蛇打印出来;
snake.x[0] = (MAP_LEN) / 2;
snake.y[0] = (MAP_LEN) / 2;
gotoxy(snake.x[0], snake.y[0]);
printf("*");
snake.len = 3;
snake.speed = 200;
for (int k = 1; k < snake.len; k++)
{
snake.x[k] = snake.x[k - 1] + 1;
snake.y[k] = snake.y[k - 1];
gotoxy(snake.x[k], snake.y[k]);
printf("*");
}
初始化写好了,不妨我们运行试一试
然后,我们开始写食物;
struct Food
{
int x;
int y;
}food;
使用rand 函数,在地图随机生成食物
srand(time(NULL));
food.x = rand() % (MAP_LEN - 5) + 2;
food.y = rand() % (MAP_LEN - 5) + 2;
gotoxy(food.x, food.y);
printf("֍");
现在,所有的初始化都已经写完了,接着看蛇的运动
snake.x[0]和snake.y[0]表示蛇头对应的坐标
这是,需要使用新的函数kbhit()
kbhit() 非阻塞的响应键盘输入时间 C++函数
功能和返回值:检查是否有键盘输入 ,有返回非0 ,无返回0
当键盘没有输入的时候,程序就会一直运行下去,
使用getch不会回显的特点来判断
if (kbhit())
ch = getch();
switch (ch)
{
case 'w':snake.x[0]--; break;
case 's':snake.x[0]++; break;
case 'a':snake.y[0]--; break;
case 'd':snake.y[0]++; break;
default:break;
}
如果我们此时没有吃到食物,那么后面一个节点就会移向前一个节点,
我们只需要将光标移动到最后一个节点,打印空格将其覆盖,这样就实现了,蛇的移动;
if (!flag)
{
gotoxy(snake.x[snake.len - 1], snake.y[snake.len - 1]);
printf(" ");
}
完整写法:
void move_snake()
{
if (kbhit())
ch = getch();
if (!flag)
{
gotoxy(snake.x[snake.len - 1], snake.y[snake.len - 1]);
printf(" ");
}
for (int k = snake.len - 1; k > 0; k--)
{
snake.x[k] = snake.x[k - 1];
snake.y[k] = snake.y[k - 1];
}
switch (ch)
{
case 'w':snake.x[0]--; break;
case 's':snake.x[0]++; break;
case 'a':snake.y[0]--; break;
case 'd':snake.y[0]++; break;
default:break;
}
gotoxy(snake.x[0], snake.y[0]);
printf("*");
flag = 0;
}
最后,我们判断蛇头的位置,当他撞墙的时候,游戏结束,即退出循环
int live()
{
if (snake.x[0] == 0 || snake.x[0] == MAP_LEN - 1 || snake.y[0] == MAP_LEN - 1 || snake.y[0] == 0)
return 0;
for (int i = snake.len; i > 0; i--)
{
if (snake.x[0] == snake.x[i] && snake.y[0] == snake.y[i])
{
return 0;
}
}
return 1;
}
接着,控制蛇的速度;
Sleep函数
功能: 执行挂起一段时间,也就是等待一段时间在继续执行,
通过暂停时间的大小控制速度;
最后,简简单单的整合一下
#include <stdio.h>
#include <windows.h>
#include <time.h>
#include <conio.h>
#define MAP_LEN 27
struct Food
{
int x;
int y;
}food;
struct Snake
{
int x[50];
int y[50];
int len;
int speed;
}snake;
int ch,flag;
void gotoxy(int x, int y)
{
HANDLE hout;
COORD cor;
hout = GetStdHandle(STD_OUTPUT_HANDLE);
cor.X = y;
cor.Y = x;
SetConsoleCursorPosition(hout, cor);
}
void color(short x) //自定义函根据参数改变颜色
{
if (x >= 0 && x <= 15)//参数在0-15的范围颜色
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), x); //只有一个参数,改变字体颜色
else//默认的颜色白色
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
}
void inti_map()
{
//初始化食物
srand(time(NULL));
food.x = rand() % (MAP_LEN - 5) + 2;
food.y = rand() % (MAP_LEN - 5) + 2;
gotoxy(food.x, food.y);
printf("֍");
//初始化蛇
snake.x[0] = (MAP_LEN) / 2;
snake.y[0] = (MAP_LEN) / 2;
gotoxy(snake.x[0], snake.y[0]);
printf("*");
snake.len = 3;
snake.speed = 200;
for (int k = 1; k < snake.len; k++)
{
snake.x[k] = snake.x[k - 1] + 1;
snake.y[k] = snake.y[k - 1];
gotoxy(snake.x[k], snake.y[k]);
printf("*");
}
//初始化地图
for (int j = 0; j < MAP_LEN; j++)
{
gotoxy(0, j);
printf("#");
gotoxy(MAP_LEN - 1, j);
printf("#");
}
for (int j = 0; j < MAP_LEN; j++)
{
gotoxy(j, 0);
printf("#");
gotoxy(j, MAP_LEN - 1);
printf("#");
}
}
void move_snake()
{
if (kbhit())
ch = getch();
if (!flag)
{
gotoxy(snake.x[snake.len - 1], snake.y[snake.len - 1]);
printf(" ");
}
for (int k = snake.len - 1; k > 0; k--)
{
snake.x[k] = snake.x[k - 1];
snake.y[k] = snake.y[k - 1];
}
switch (ch)
{
case 'w':snake.x[0]--; break;
case 's':snake.x[0]++; break;
case 'a':snake.y[0]--; break;
case 'd':snake.y[0]++; break;
default:break;
}
gotoxy(snake.x[0], snake.y[0]);
printf("*");
flag = 0;
}
void updatefood()
{
if (snake.x[0] == food.x && snake.y[0] == food.y)
{
srand(time(NULL));
food.x = rand() % (MAP_LEN - 5) + 3;
food.y = rand() % (MAP_LEN - 5) + 3;
gotoxy(food.x, food.y);
printf("֍");
snake.len++;
flag = 1;
}
}
int live()
{
if (snake.x[0] == 0 || snake.x[0] == MAP_LEN - 1 || snake.y[0] == MAP_LEN - 1 || snake.y[0] == 0)
return 0;
for (int i = snake.len; i > 0; i--)
{
if (snake.x[0] == snake.x[i] && snake.y[0] == snake.y[i])
{
return 0;
}
}
return 1;
}
int main()
{
inti_map();
system("pause");
while (1)
{
updatefood();
move_snake();
if (live() == 0)
break;
Sleep(snake.speed);
}
gotoxy(MAP_LEN + 1, 0);
printf("GAME OVER");
return 0;
}