“笔者刚学完c语言基础语法,本着练习的心态用控制台实现了贪吃蛇游戏,于是有了本篇。”
效果预览:
目录
公众号摸鱼老K同步更新,感谢关注~
一、预备知识
基本的语法就不多赘述了,本篇主要介绍基础学习不常涉及到的函数
1、kbhit()
用于非阻塞地响应键盘输入事件,在本项目中用于检测按键控制蛇体移动。
功能及返回值: 检查当前是否有键盘输入,若有则返回一个非0值,否则返回0
2、getch()
从stdio流中读字符,即从控制台读取一个字符,但不显示在屏幕上,getch()会暂停输出控制台,直到按下一个键为止,它不使用任何缓冲区来存储输入字符,输入的字符将立即返回,而无需等待回车键。
返回值:读取的字符的ASCII码值(整数)。
3、system()
int system(const char * command)
在windows系统中,system函数直接在控制台调用一个command命令。这些命令可以通过system(“HELP”)获取,我们在这只使用system("cls")来清除屏幕输出。
返回值:命令执行成功返回0,执行失败返回-1。
4、rand()
rand()函数用于产生一个随机数,其内部实现是用线性同余法实现的,是伪随机数,由于周期较长,因此在一定范围内可以看成是随机的。调用rand()函数会得到一个在0-RAND_MAX。RAND_MAX在头文件stdlib.h中定义。
我们还可以通过rand()%(n-m+1)+m这个公式实现指定范围(m,n)内的随机数。
二、基本思路
实现思路就是通过清空控制台再打印输出,如此循环,实现动画效果。
定义出蛇头,蛇身,蛇尾,程序难点就在蛇体运动和蛇尾判定。首先明确大体过程,蛇头不断朝着正向前进,并且可以通过按键改变方向。蛇的整体运动其实就是蛇头前移,之后在蛇头后面打印出一个蛇身,最后是清楚蛇的末尾,这样就能实现蛇的动态。
再一个难点是蛇身拐点,也就是多一个拐点蛇身就多处一个运动的矢量,本例程是将拐点xy坐标以及方向存储在三个数组中,通过这三个值判断尾端的移动。这样的好处是编程逻辑清楚简单,相应缺点就是数组大小有限,并且不能释放无用的内存。当你熟练了指针用法之后也可以通过链表存储来改进。这里笔者还不熟练,今后学到可能会回头来优化(刚开始就挖坑~)
食物就通过随机数生成,死亡判定就直接判断头坐标下一个内容(是墙或者蛇身判定死亡)。
三、代码实现
1、变量声明
//蛇头和蛇身
char head = '#', body = '*';
//蛇头的坐标值,长度,拐点个数
int x = 20, y = 10, length = 10, change = 0;
//记录拐点信息,方向用1233代表wasd
int xchange[999], ychange[999], decation[999] = {0};
//食物坐标
int xfood = 20, yfood = 30;
//尾部坐标,尾部到达拐点标志
int xtail, ytail, tailflag = 0;
2、主程序
int main() {
//尾部初始值
xtail = x;
ytail = y - length;
while (1) {
//按键检测函数
if (kbhit())
input();
//蛇体默认移动,触发死亡条件break掉循环
if (add())
break;
//尾部检测,清楚尾部的图案
tail();
//吃到食物尾部加长
addlong();
//更新屏幕显示
system("cls");
printf("\t\t\t成绩:%d\n", length);
printf("%s", backgd);
}
system("cls");
printf("游戏结束");
return 0;
}
3、按键检测
用来记录拐点信息
void input() {
char key = getch();
change++;
xchange[change] = x;
ychange[change] = y;
if (key == 'w') {
decation[change] = 1;
}
if (key == 'a') {
decation[change] = 2;
}
if (key == 's') {
decation[change] = 3;
}
if (key == 'd') {
decation[change] = 4;
}
}
4、食物判定
如果蛇头移动到食物坐标length就会加一,并且再随机一个食物
void addlong() {
backgd[xfood][yfood] = 'X';
if (x == xfood && y == yfood && change == 0) {
length++;
ytail--;
xfood = rand() % 25 + 1;
yfood = rand() % 77 + 1;
}
if (x == xfood && y == yfood && change != 0) {
length++;
if (decation[tailflag] == 1)
xtail++;
if (decation[tailflag] == 2)
ytail++;
if (decation[tailflag] == 3)
xtail--;
if (decation[tailflag] == 4)
ytail--;
xfood = rand() % 25 + 1;
yfood = rand() % 77 + 1;
}
}
5、尾部判定加清楚
用tailflag去读取拐点信息,再进行相应的坐标偏移
void tail() {
if (tailflag == 0) {
ytail++;
if (ytail == ychange[tailflag + 1])
tailflag++;
} else {
if (decation[tailflag] == 1) {
xtail--;
if (xtail == xchange[tailflag + 1]) {
tailflag++;
return;
}
}
if (decation[tailflag] == 2) {
ytail--;
if (ytail == ychange[tailflag + 1]) {
tailflag++;
return;
}
}
if (decation[tailflag] == 3) {
xtail++;
if (xtail == xchange[tailflag + 1]) {
tailflag++;
return;
}
}
if (decation[tailflag] == 4) {
ytail++;
if (ytail == ychange[tailflag + 1]) {
tailflag++;
return;
}
}
}
}
6、蛇体默认移动、死亡判定
蛇头根据拐点进行坐标偏移,如果碰到“*”即为死亡
int add() {
clear();
if (change == 0) {
y++;
backgd[x][y] = head;
backgd[x][y - 1] = body;
} else {
if (decation[change] == 1) {
if (backgd[x - 1][y] == '*')
return 1;
backgd[x - 1][y] = head;
backgd[x][y] = body;
x--;
}
if (decation[change] == 2) {
if (backgd[x][y - 1] == '*')
return 1;
backgd[x][y - 1] = head;
backgd[x][y] = body;
y--;
}
if (decation[change] == 3) {
if (backgd[x + 1][y] == '*')
return 1;
backgd[x + 1][y] = head;
backgd[x][y] = body;
x++;
}
if (decation[change] == 4) {
if (backgd[x][y + 1] == '*')
return 1;
backgd[x][y + 1] = head;
backgd[x][y] = body;
y++;
}
}
return 0;
}
7、源码
#include <stdio.h>
char backgd[27][81] = {
{"********************************************************************************\n"},
{"* *\n"},
{"* *\n"},
{"* *\n"},
{"* *\n"},
{"* *\n"},
{"* *\n"},
{"* *\n"},
{"* *\n"},
{"* *\n"},
{"* *\n"},
{"* *\n"},
{"* *\n"},
{"* *\n"},
{"* *\n"},
{"* *\n"},
{"* *\n"},
{"* *\n"},
{"* *\n"},
{"* *\n"},
{"* *\n"},
{"* *\n"},
{"* *\n"},
{"* *\n"},
{"* *\n"},
{"******************************************************************************** "}
};
char head = '#', body = '*';
int x = 20, y = 10, length = 1, change = 0;
int xchange[999], ychange[999], decation[999] = {0};
int xfood = 20, yfood = 30;
int xtail, ytail, tailflag = 0;
void clear() {
backgd[xtail][ytail] = ' ';
}
void input() {
char key = getch();
change++;
xchange[change] = x;
ychange[change] = y;
if (key == 'w') {
decation[change] = 1;
}
if (key == 'a') {
decation[change] = 2;
}
if (key == 's') {
decation[change] = 3;
}
if (key == 'd') {
decation[change] = 4;
}
}
void addlong() {
backgd[xfood][yfood] = 'X';
if (x == xfood && y == yfood && change == 0) {
length++;
ytail--;
xfood = rand() % 25 + 1;
yfood = rand() % 77 + 1;
}
if (x == xfood && y == yfood && change != 0) {
length++;
if (decation[tailflag] == 1)
xtail++;
if (decation[tailflag] == 2)
ytail++;
if (decation[tailflag] == 3)
xtail--;
if (decation[tailflag] == 4)
ytail--;
xfood = rand() % 25 + 1;
yfood = rand() % 77 + 1;
}
}
void tail() {
if (tailflag == 0) {
ytail++;
if (ytail == ychange[tailflag + 1])
tailflag++;
} else {
if (decation[tailflag] == 1) {
xtail--;
if (xtail == xchange[tailflag + 1]) {
tailflag++;
return;
}
}
if (decation[tailflag] == 2) {
ytail--;
if (ytail == ychange[tailflag + 1]) {
tailflag++;
return;
}
}
if (decation[tailflag] == 3) {
xtail++;
if (xtail == xchange[tailflag + 1]) {
tailflag++;
return;
}
}
if (decation[tailflag] == 4) {
ytail++;
if (ytail == ychange[tailflag + 1]) {
tailflag++;
return;
}
}
}
}
int add() {
clear();
if (change == 0) {
y++;
backgd[x][y] = head;
backgd[x][y - 1] = body;
} else {
if (decation[change] == 1) {
if (backgd[x - 1][y] == '*')
return 1;
backgd[x - 1][y] = head;
backgd[x][y] = body;
x--;
}
if (decation[change] == 2) {
if (backgd[x][y - 1] == '*')
return 1;
backgd[x][y - 1] = head;
backgd[x][y] = body;
y--;
}
if (decation[change] == 3) {
if (backgd[x + 1][y] == '*')
return 1;
backgd[x + 1][y] = head;
backgd[x][y] = body;
x++;
}
if (decation[change] == 4) {
if (backgd[x][y + 1] == '*')
return 1;
backgd[x][y + 1] = head;
backgd[x][y] = body;
y++;
}
}
return 0;
}
int main() {
xtail = x;
ytail = y - length;
while (1) {
if (kbhit())
input();
if (add())
break;
tail();
addlong();
system("cls");
printf("\t\t\t成绩:%d\n", length);
printf("%s", backgd);
}
system("cls");
printf("游戏结束");
return 0;
}