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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章