本篇博客适于c语言界的小白,大神请移步~~~
关于自顶向下,之前写的一篇博客TOP-DOWN里面有记录一丢丢。
言归正传,自顶向下设计的思路就是break down
相信大家都有玩过贪吃蛇的游戏,贪吃蛇可分解为以下部分:
1、框架、蛇的表示
2、将图形输出
3、移动蛇的位置
4、食物的出现与消失(被吃)
5、撞墙over
下面开始逐个击破。
1、框架、蛇的表示
因为蛇、食物都在框架里面,那么单纯c语言输出,必须是将其全部囊括在一个字符数组里面,即char screen[15][15], 表示15*15的框架。
然后需要明白的一点就是:移动的过程其实只是蛇尾与蛇头的移动
用面向对象的方法,蛇头(head)、蛇尾(tail)的属性为x,y坐标,移动方向。将它们的信息储存在结构体turn中
typedef struct T
{
int x;
int y;
char dir;
}turn;
turn tail, head;
将框架与蛇初始化:
void initial(char(*Screen)[15])//初始化输出数组
{
for (i = 0; i < 15; i++)
{
for (j = 0; j < 15; j++)
{
if (i == 0 || j == 0 || j == 14 || i == 14)
Screen[i][j] = '#';
else
Screen[i][j] = ' ';
}
}
Screen[1][1] = '*';//*表示尾巴
Screen[1][2] = Screen[1][3] = 'O';//O表示身体
Screen[1][4] = '@';//@表示头
tail.x = 1;
tail.y = 1;
tail.dir = 'd';
head.x = 1;
head.y = 4;
head.dir = 'd';
}
2、输出看看
out (screen);
void out(char(*SCREEN)[15])
{
for (i = 0; i < 15; i++)
{
for (j = 0; j < 15; j++)
{
printf("%c", SCREEN[i][j]);
}
printf("\n");
}
}
如图
3、移动蛇的位置
蛇分为两种行进,前进与转弯,这里的转弯包括蛇尾与蛇头的转弯。
(1)前进
void move(turn *Tail, turn *Head)
{
screen[Tail->x][Tail->y] = ' ';
switch (Tail->dir)//尾巴向着蛇尾的方向前进
{
case 'd'://s/S、d/D、w/W、a/A分别表示下、右、上、左
case 'D':
Tail->y++;
break;
case 'a':
case 'A':
Tail->y--;
break;
case 'w':
case 'W':
Tail->x--;
break;
case 's':
case 'S':
Tail->x++;
break;
default:
break;
}
screen[Tail->x][Tail->y] = '*';
screen[Head->x][Head->y] = 'O';
switch (Head->dir)//头向着头的方向前进
{
case 'd':
case 'D':
Head->y++;
break;
case 'a':
case 'A':
Head->y--;
break;
case 'w':
case 'W':
Head->x--;
break;
case 's':
case 'S':
Head->x++;
default:
break;
}
screen[Head->x][Head->y] = '@';
}
(2)转弯
蛇头的转弯比较容易,输入方向,改变head.dir就可以了。
如下
if (_kbhit())//判断是否有输入方向
{
change = getchar();//记录方向
head.dir = change;//头部方向变为所记录的方向
Ticks();//Tick是函数,作用下面解释
}
Free();//Free是函数,作用下面解释
那么蛇尾就尴尬了,当前输入的方向并不能改变tail.dir。
那怎么办呢??
首先我们知道,蛇尾运行到某些位置会转弯,那么把那些位置记下来,看看蛇尾是否在那个位置即可。
记下位置属性:
turn ticks[14];
int times=0;//记录位置数量
void Ticks()//增加位置
{
ticks[times] = head;//增加的位置恰好就蛇头的位置
times++;
}
void Free()//减少位置
{
int n;
if (screen[ticks[0].x][ticks[0].y] == '*')
{
tail.dir = ticks[0].dir;
for (n = 0; n < times; n++)
{
ticks[n] = ticks[n + 1];//第一个位置要删除,将后面的位置信息给前一个
}
times--;
}
}
4、食物的出现与消失
首先明白:屏幕上始终只有一个食物,一个食物的消失伴随另一个食物的出现。
那么,就让它消失吧!
int food[2]={1,4};//初始化食物的位置刚好在蛇头
void eat()
{
srand(time(NULL));
if (head.x == food[0] && head.y == food[1])
//蛇头坐标与食物坐标相同,就被吃掉
{
screen[head.x][head.y] = 'O';//食物位置变成身体的一节
switch (head.dir)//蛇头位置向前
{
case 'd':
case 'D':
head.y++;
break;
case 'a':
case 'A':
head.y--;
break;
case 'w':
case 'W':
head.x--;
break;
case 's':
case 'S':
head.x++;
default:
break;
}
screen[head.x][head.y] = '@';重新制造蛇头
while (screen[food[0]][food[1]] != ' ')
{//制造食物,随机食物坐标不在蛇身
food[0] = rand() % 13 + 1;//坐标范围1~13
food[1] = rand() % 13 + 1;
}
screen[food[0]][food[1]] = '$';//$是食物
}
}
5、撞墙over
肯定是头撞墙。
if (head.x == 0 || head.y == 14 || head.x == 14 || head.y == 0)
{
printf("game over");
break;//这里是跳出主循环
}
主函数完整代码,其中有些部分已在前面出现
int main()
{
char change;
initial(screen);
out(screen);
eat();
while (1)
{
if (_kbhit())
{
change = getchar();
head.dir = change;
Ticks();
}
Free();
move(&tail, &head);
eat();
system("cls");//清屏
out(screen);
if (head.x == 0 || head.y == 14 || head.x == 14 || head.y == 0)
{
break;
}
Sleep(500);//延时500毫秒
}
system("cls");
printf("\n game over!\n");
system("pause");
return 0;
}
将主函数与辅助函数整合在一起,如下
#include
#include
#include
#include
#include
#include
char screen[15][15];
int i, j, times=0, food[2] = { 1,4 };
typedef struct T
{
int x;
int y;
char dir;
}turn;
turn ticks[14], tail, head;
void initial(char(*Screen)[15])//初始化输出数组
{
for (i = 0; i < 15; i++)
{
for (j = 0; j < 15; j++)
{
if (i == 0 || j == 0 || j == 14 || i == 14)
Screen[i][j] = '#';
else
Screen[i][j] = ' ';
}
}
Screen[1][1] = '*';
Screen[1][2] = Screen[1][3] = 'O';
Screen[1][4] = '@';
for (i = 0; i < 14; i++)
{
ticks[i].x = 0;
ticks[i].y = 0;
}
tail.x = 1;
tail.y = 1;
tail.dir = 'd';
head.x = 1;
head.y = 4;
head.dir = 'd';
}
void out(char(*SCREEN)[15])
{
for (i = 0; i < 15; i++)
{
for (j = 0; j < 15; j++)
{
printf("%c", SCREEN[i][j]);
}
printf("\n");
}
}
void move(turn *Tail, turn *Head)
{
screen[Tail->x][Tail->y] = ' ';
switch (Tail->dir)
{
case 'd':
case 'D':
Tail->y++;
break;
case 'a':
case 'A':
Tail->y--;
break;
case 'w':
case 'W':
Tail->x--;
break;
case 's':
case 'S':
Tail->x++;
break;
default:
break;
}
screen[Tail->x][Tail->y] = '*';
screen[Head->x][Head->y] = 'O';
switch (Head->dir)
{
case 'd':
case 'D':
Head->y++;
break;
case 'a':
case 'A':
Head->y--;
break;
case 'w':
case 'W':
Head->x--;
break;
case 's':
case 'S':
Head->x++;
default:
break;
}
screen[Head->x][Head->y] = '@';
}
void eat()
{
srand(time(NULL));
if (head.x == food[0] && head.y == food[1])
{
screen[head.x][head.y] = 'O';
switch (head.dir)
{
case 'd':
case 'D':
head.y++;
break;
case 'a':
case 'A':
head.y--;
break;
case 'w':
case 'W':
head.x--;
break;
case 's':
case 'S':
head.x++;
default:
break;
}
screen[head.x][head.y] = '@';
while (screen[food[0]][food[1]] != ' ')
{
food[0] = rand() % 13 + 1;
food[1] = rand() % 13 + 1;
}
screen[food[0]][food[1]] = '$';
}
}
void Ticks()
{
ticks[times] = head;
times++;
}
void Free()
{
int n;
if (screen[ticks[0].x][ticks[0].y] == '*')
{
tail.dir = ticks[0].dir;
for (n = 0; n < times; n++)
{
ticks[n] = ticks[n + 1];
}
times--;
}
}
int main()
{
char change;
initial(screen);
out(screen);
eat();
while (1)
{
if (_kbhit())
{
change = getchar();
head.dir = change;
Ticks();
}
Free();
move(&tail, &head);
eat();
system("cls");
out(screen);
if (head.x == 0 || head.y == 14 || head.x == 14 || head.y == 0)
{
break;
}
Sleep(500);
}
system("cls");
printf("\n game over!\n");
system("pause");
return 0;
}