自顶向下设计C语言贪吃蛇

本篇博客适于c语言界的小白,大神请移步~~~
关于自顶向下,之前写的一篇博客TOP-DOWN里面有记录一丢丢。
言归正传,自顶向下设计的思路就是break down

设计思路

相信大家都有玩过贪吃蛇的游戏,贪吃蛇可分解为以下部分:
1、框架、蛇的表示
2、将图形输出
3、移动蛇的位置
4、食物的出现与消失(被吃)
5、撞墙over
下面开始逐个击破。

start

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");
    }
}

如图 自顶向下设计C语言贪吃蛇_第1张图片
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;
}

你可能感兴趣的:(游戏开发)