C语言版贪吃蛇:第四部分

C语言版贪吃蛇:第四部分

“马上就要结束了!”

本章学习:

  1. 判断是否吃到食物并增长身体
  2. 判断是否撞墙或吃到自己


判断是否存活

  1. 定义一个变量 life 表示是否活着
    1. life=1表示活着,life=0表示挂掉
    2. 记得在 init( ) 里给 life 初始值1
    3. 主函数的while条件里要加life
  2. 判断撞墙
    1. 判断蛇头座标与墙是否重合
  3. 判断吃到自己
    1. 依次判断蛇头座标是否与每节蛇身重合
  4. 记得要在move()函数的最后加上check_life( )
    1. 每移动一次都要判断是否活着
      参考代码如下
// 判断蛇是否还活着
void check_life()
{
    // 判断是否撞墙,只需判断蛇头座标是否与墙重合即可
    if (Snake[head].x == 1 || Snake[head].x == 70 || Snake[head].y == 1 || Snake[head].y == 20)
        Game_over();
    // 判断是否吃到自己
    // 方法:依次判断蛇头是否与蛇身重合
    int i, j = Snake[head].next;
    for (i = 1; i < lenth; i++)
    {
        // 重合就结束游戏
        if (Snake[j].x == Snake[head].x && Snake[j].y == Snake[head].y)
            Game_over();
        j = Snake[j].next;
    }
}


增长身体

  1. 直接判断蛇头座标与食物是否重合
  2. 若重合,则增长
    1. 增长分为水平和竖直增长
  3. 具体可参考代码

参考代码如下

// 判断是否吃到食物
void check_food()
{
    // 检验蛇头是否与食物重合
    // 重合则增长身体(在蛇尾后增加一节),并重新放置一个食物
    if (Snake[head].x == food_x && Snake[head].y == food_y)
    {
        // 增长身体,要注意水平增长还是竖直增长
        // 通过最后两节来判断
        // 水平座标相同则水平增长
        // 竖直座标相同则竖直增长
        lenth++;
        // 水平增长
        if (Snake[nail].x == Snake[Snake[nail].pre].x)
        {
            // 水平座标 x 不变
            Snake[lenth].x = Snake[nail].x;
            // 竖直座标向蛇尾方向加 1 或 减 1
            // 为了省去判断,这里用蛇尾竖直座标减蛇尾前一个竖直座标表示
            Snake[lenth].y = Snake[nail].y + (Snake[nail].y - Snake[Snake[nail].pre].y);
            // 将新的一节接上去
            Snake[nail].next = lenth;
            Snake[lenth].pre = nail;
            // 设置新的蛇尾
            nail = lenth;
        }
        // 竖直增长,将上面的 x 变成 y 即可
        if (Snake[nail].y == Snake[Snake[nail].pre].y)
        {
            Snake[lenth].y = Snake[nail].y;
            Snake[lenth].x = Snake[nail].x + (Snake[nail].x - Snake[Snake[nail].pre].x);
            Snake[nail].next = lenth;
            Snake[lenth].pre = nail;
            nail = lenth;
        }
        // 放置新的食物
        printfood();
    }
}



完整源代码

/*
    这里是贪吃蛇源代码

    chapter 1:
    解释下头文件:
    time.h 生成随机数要用到
    windows.h 要用到里面的函数 gotoxy
    ---------
    1.画围墙

    ===========================

    chapter 2:
    目标:绘制蛇,食物
        蛇的存储结构:简单的链表(数组实现功能)
        食物:随机数的生成

    ===========================

    chapter 3:
    目标: 实现蛇的运动
        判断键盘输入
        改变蛇的座标
        重绘图像

    ===========================

    chapter 4:
    目标: 判断是否吃到食物
        增长身体
        判断是否撞墙,是否吃到自己

    ===========================
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <windows.h>
#include <conio.h>
// 定义一个结构体用来存储蛇的每节身体的座标
struct snake
{
    int x, y;
    int next; //保存当前节点的下一个节点的位置(数组下标)
    int pre;  //保存上一个节点的位置
} Snake[100];

// 定义三个变量存 蛇长,蛇头,蛇尾
int lenth, head, nail;
// 食物位置
int food_x, food_y;
// 储存蛇的当前,和上一次的移动方向
int direation, direation_pre;
// 存储蛇是否还活着,1活着
int life;
// 光标移动函数
void gotoxy(int x, int y)
{
    COORD coord = {x, y};
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}
// 打印蛇
void printsnake()
{
    int i, j = head;
    for (i = 1; i <= lenth; i++)
    {
        // 注意 里面的参数是j,j从蛇头移动到蛇尾
        gotoxy(Snake[j].x, Snake[j].y);
        printf("*");
        j = Snake[j].next;
    }
}
// 清除蛇
void clear()
{
    int i, j = head;
    for (i = 1; i <= lenth; i++)
    {
        // 注意 里面的参数是j,j从蛇头移动到蛇尾
        gotoxy(Snake[j].x, Snake[j].y);
        printf(" ");
        j = Snake[j].next;
    }
}
// 游戏结束
void Game_over()
{
    // 将 life 设置为0,表示游戏结束,用来结束主函数中的while循环
    life = 0;
    // 清屏
    system("cls");
    // 打印提示信息
    gotoxy(10, 10);
    printf("GAME OVER");
}
// 判断食物是否合法
int ok_food()
{
    // 判断是否和墙重合
    // 横座标不能等于1,或70 ; 纵座标不能等于1,或20
    if (food_x <= 1 || food_x >= 70)
        return 0;
    if (food_y <= 1 || food_y >= 20)
        return 0;
    // 判断是否和蛇重合
    int j = head;
    for (int i = 1; i <= lenth; i++)
    {
        if (food_x == Snake[j].x && food_y == Snake[j].y)
            return 0;
        j = Snake[j].next;
    }
    // 都没有,则返回1
    return 1;
}

// 打印食物
void printfood()
{
    // 不断产生随机数,知道座标符合要求
    do
    {
        srand((unsigned long)time(0));
        food_x = rand() % 70;
        food_y = rand() % 20;
    } while (!ok_food());
    // ok_food()为判断食物是否合法的函数,合法返回1,不合法返回0
    gotoxy(food_x, food_y);
    printf("@");
}
// 判断是否吃到食物
void check_food()
{
    // 检验蛇头是否与食物重合
    // 重合则增长身体(在蛇尾后增加一节),并重新放置一个食物
    if (Snake[head].x == food_x && Snake[head].y == food_y)
    {
        // 增长身体,要注意水平增长还是竖直增长
        // 通过最后两节来判断
        // 水平座标相同则水平增长
        // 竖直座标相同则竖直增长
        lenth++;
        // 水平增长
        if (Snake[nail].x == Snake[Snake[nail].pre].x)
        {
            // 水平座标 x 不变
            Snake[lenth].x = Snake[nail].x;
            // 竖直座标向蛇尾方向加 1 或 减 1
            // 为了省去判断,这里用蛇尾竖直座标减蛇尾前一个竖直座标表示
            Snake[lenth].y = Snake[nail].y + (Snake[nail].y - Snake[Snake[nail].pre].y);
            // 将新的一节接上去
            Snake[nail].next = lenth;
            Snake[lenth].pre = nail;
            // 设置新的蛇尾
            nail = lenth;
        }
        // 竖直增长,将上面的 x 变成 y 即可
        if (Snake[nail].y == Snake[Snake[nail].pre].y)
        {
            Snake[lenth].y = Snake[nail].y;
            Snake[lenth].x = Snake[nail].x + (Snake[nail].x - Snake[Snake[nail].pre].x);
            Snake[nail].next = lenth;
            Snake[lenth].pre = nail;
            nail = lenth;
        }
        // 放置新的食物
        printfood();
    }
}
// 判断蛇是否还活着
void check_life()
{
    // 判断是否撞墙,只需判断蛇头座标是否与墙重合即可
    if (Snake[head].x == 1 || Snake[head].x == 70 || Snake[head].y == 1 || Snake[head].y == 20)
        Game_over();
    // 判断是否吃到自己
    // 方法:依次判断蛇头是否与蛇身重合
    int i, j = Snake[head].next;
    for (i = 1; i < lenth; i++)
    {
        // 重合就结束游戏
        if (Snake[j].x == Snake[head].x && Snake[j].y == Snake[head].y)
            Game_over();
        j = Snake[j].next;
    }
}
// 实现蛇的座标改变
void move()
{
    // 擦掉原来的蛇
    clear();
    // 根据 direation 选择运动方向
    switch (direation)
    {
    case 'w':
    {
        // 蛇尾变到蛇头前面,向上运动,则纵座标减一(回忆之前介绍的座标轴)
        Snake[nail].x = Snake[head].x;
        Snake[nail].y = Snake[head].y - 1;
        // 将新蛇头的下一个位置指向旧蛇头
        Snake[nail].next = head;
        // 将旧蛇头的前一个位置指向新蛇头
        Snake[head].pre = nail;
        // 新蛇头是原来的蛇尾
        head = nail;
        // 新蛇尾是原来蛇尾的前一节
        nail = Snake[nail].pre;
        break;
    }
    case 's':
    {
        Snake[nail].x = Snake[head].x;
        Snake[nail].y = Snake[head].y + 1;
        Snake[nail].next = head;
        Snake[head].pre = nail;
        head = nail;
        nail = Snake[nail].pre;
        break;
    }
    case 'a':
    {
        Snake[nail].x = Snake[head].x - 1;
        Snake[nail].y = Snake[head].y;
        Snake[nail].next = head;
        Snake[head].pre = nail;
        head = nail;
        nail = Snake[nail].pre;
        break;
    }
    case 'd':
    {
        Snake[nail].x = Snake[head].x + 1;
        Snake[nail].y = Snake[head].y;
        Snake[nail].next = head;
        Snake[head].pre = nail;
        head = nail;
        nail = Snake[nail].pre;
        break;
    }
    }
    printsnake();
    check_food();
    check_life();
}

// 绘制围墙
void printwall()
{
    /*
        chapter 1 绘制围墙部分
        围墙大小 70*20, 长70,宽20
    */

    // 绘制水平围墙,
    for (int i = 1; i <= 70; i++)
    {
        gotoxy(i, 1);
        printf("#");
        gotoxy(i, 20);
        printf("#");
    }
    // 绘制竖直围墙
    for (int i = 1; i <= 20; i++)
    {
        gotoxy(1, i);
        printf("#");
        gotoxy(70, i);
        printf("#");
    }
}
void init()
{
    printwall();
    // 初始化蛇
    Snake[1].x = 4;
    Snake[1].y = 4;
    Snake[2].x = 4;
    Snake[2].y = 5; 
    head = 1;
    nail = 2;
    lenth = 2;
    Snake[head].next = nail;
    Snake[nail].pre = head;
    direation = 's';
    direation_pre = 's';
    life=1;
    // 第一次打印蛇
    printsnake();
    // 第一次打印食物
    printfood();
}
int main()
{
    init(); // 初始化函数,绘制围墙
    char c;
    c=getch();
    while (1)
    {
        // 没有读入则按照之前的方向一直运动
        while (!kbhit() && life)
        {
            move();
            Sleep(150);
        }
        // 有读入则停下来改变方向
        // 先记下原来的方向
        direation_pre = direation;
        // 读入要改变的方向
        direation = getch();
        // 判断方向是否合法,如果和上次相反,则保持原来方向
        if (direation == 'w' && direation_pre == 's' || direation == 's' && direation_pre == 'w')
            direation = direation_pre;
        if (direation == 'a' && direation_pre == 'd' || direation == 'd' && direation_pre == 'a')
            direation = direation_pre;
    }
    system("pause");
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章