小白入門——“貪喫蛇”的C語言實現(詳細)

C語言實現,編譯環境VS2017 附:easyx圖形化(文章末尾)

 

 

效果圖如下

 

(有一些函數kbhit,getch,在這表示爲_kbhit與_getch)//不同編譯器原因 注意在Dev等集成開發軟件下可能會CE

 

o(* ̄▽ ̄*)o

 

 

 

一、引言

    作爲一個小白,相信大家的心情都是一樣的,渴望寫一個人生的第一個“貪喫蛇”。

    在網上看了基本思路後,如果有一定的知識(鏈表的相關操作),寫出這個應該是不難的。

    1、背景

        打印遊戲背景框,以及一些初設的東西,如蛇的初始長度,可以的話可以自己加上出場界面

    2、食物產生

        通過srand,與rand 函數實現隨機產生

    3、鍵盤信號獲取

        由 _kbhit(),_getch() ,函數獲取

    4、蛇的移動

        分爲普通移動與喫到食物的移動

        ps.(許多網上通過刷屏實現,其實可以靠覆蓋實現,將原來蛇覆蓋用空格,然後重新打印蛇)

二、一些必要函數

    打印這個並不是圖形庫實現,所以要通過光標跳轉實現打印

    注:此方法我也不清楚是從網上查閱資料所得,目前還是小白(ง •_•)ง

    

void gotoxy(int x, int y) 
{
    // 更新光標位置 
	COORD pos;
	HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	pos.X = x;
	pos.Y = y;
	SetConsoleCursorPosition(hOutput, pos);
    // 隱藏光標 
    CONSOLE_CURSOR_INFO cursor;
	cursor.bVisible = FALSE;    
	cursor.dwSize = sizeof(cursor);
	SetConsoleCursorInfo(hOutput, &cursor);
}

    應該是獲取窗口句柄

    詳細可以參考

    https://baike.baidu.com/item/SetConsoleCursorPosition/575826

    https://baike.baidu.com/item/GetStdHandle/6909878?fr=aladdin

    https://baike.baidu.com/item/coord/4594820?fr=aladdin

三、不多說,看代碼

以前寫的太爛了 現在重新更新了

/*
@Author: Joke-Lin
@Time: 2020-03-19
@Encoding: GB 2312
@IDE: VS2019
*/

#include<stdio.h>
#include<string.h>
#include<windows.h>
#include<time.h>
#include<conio.h>

#define up 'w'
#define down 's'
#define left 'a'
#define right 'd'

void welcome();               // 開始界面
void Finish();                // 結束界面
void creatgraph();            // 圍牆打印
void gotoxy(int x, int y);    // 光標跳轉,橫爲X 0,1,2..
void gotoprint(int x, int y); // 跳轉打印
void gotodelete(int x, int y);// 跳轉刪除
void creatfood();             // 食物產生
int ClickControl();           // 獲取鍵盤信號
int Judge();                  // 遊戲結束判斷
void MovingBody();            // 蛇的移動 
void Eating();                // 蛇喫到東西后的操作(伸長)
void ChangeBody(int x, int y); // 蛇的座標變換

/*全局變量 + 預處理:*/
typedef struct Snakes
{
    int x;
    int y;
    struct Snakes* next;
}snake;

snake* head;    // 聲明蛇頭指針 

// 申明並定義食物 
struct Food
{
    int x;
    int y;
}food;

char name[20];  // 保存用戶名 有興趣可以製作登錄系統 
int score = 0;  // 分數 
char click = 1; // 記錄敲下的鍵盤按鍵 
int speed;      // 速度 其實是延遲的毫秒數 

/************************************************************/

int main()
{
    system("color 0B"); // 設置控制檯字體顏色 
    welcome();          // 歡迎界面 
    creatgraph();       // 創建地圖 
    creatfood();        // 新建食物 
    // 捕獲鼠標按鍵 ClickControl
    if (ClickControl() == 0) return 0;
    return 0;
}

/**********************************************************/
void welcome()
{
    gotoxy(15, 10);
    printf("/**********************************************/");
    gotoxy(15, 20);
    printf("/**********************************************/");
    gotoxy(20, 13);
    printf("WELCOME TO THE GAME OF RETRO SNAKE");
    gotoxy(14, 16);
    printf("請在英文輸入法中操作,反向移動等同於喫到自己,wasd控制p暫停");
    gotoxy(20, 18);
    printf("PLEASE ENTER YOUR NAME:");
    scanf_s("%s", &name, 20);
    system("cls");
}

/**********************************************************/
void creatgraph() {
    int i;
    /*
    注意這裏橫座標是每次+2 因爲控制檯字符寬高比爲1:2
    */
    for (i = 0; i < 58; i += 2)
    {
        gotoprint(i, 0);
        gotoprint(i, 26);
    }
    for (i = 1; i < 26; i++)
    {
        gotoprint(0, i);
        gotoprint(56, i);
    }
    gotoxy(63, 10);
    printf("hello %s,Welcome To Play", name);
    gotoxy(63, 15);
    printf("Your Score Is:%d    = ̄ω ̄= ", score);
    gotoxy(63, 20);
    printf("This Game Is Created By JOKER");
    head = (snake*)malloc(sizeof(snake));
    snake* p = (snake*)malloc(sizeof(snake));
    snake* q = (snake*)malloc(sizeof(snake));
    head->x = 16;
    head->y = 15;
    p->x = 16;
    p->y = 16;
    q->x = 16;
    q->y = 17;
    head->next = p;
    p->next = q;
    q->next = NULL;
}
/**********************************************************/
void gotoxy(int x, int y)
{
    // 更新光標位置 
    COORD pos;
    HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
    pos.X = x;
    pos.Y = y;
    SetConsoleCursorPosition(hOutput, pos);
    // 隱藏光標 
    CONSOLE_CURSOR_INFO cursor;
    cursor.bVisible = FALSE;
    cursor.dwSize = sizeof(cursor);
    SetConsoleCursorInfo(hOutput, &cursor);
}

/**********************************************************/
void gotoprint(int x, int y)
{
    gotoxy(x, y);
    printf("■");
}

/**********************************************************/
void gotodelete(int x, int y)
{
    gotoxy(x, y);
    printf("  ");
}

/**********************************************************/
void creatfood()
{
    // 隨機產生一個食物 
    bool flag = false;
    while (!flag)
    {
        flag = true;
        srand((int)time(NULL));
        food.y = rand() % (25 - 1 + 1) + 1;
        food.x = rand() % (54 - 2 + 1) + 2;
        if (food.x % 2 != 0)
        {
            food.x = food.x + 1;
        }
        snake* judge = head;
        while (1)  //遍歷排除蛇身重複
        {
            if (judge->next == NULL) break;
            if (food.x == judge->x && food.y == judge->y)
            {
                flag = false;
            }
            judge = judge->next;
        }
    }
    gotoxy(food.x, food.y);
    printf("⊙");
}

/**********************************************************/
// 捕獲鼠標 遊戲主循環 
int ClickControl()
{
    char c;
    while (1)
    {
        if (Judge() == 0) return 0;
        if (_kbhit())
        {
            click = _getch();
        }
        MovingBody();
        Eating();
    }
    return 1;
}

/**********************************************************/
void MovingBody() {
    int x = head->x, y = head->y;
    snake* p = head;
    // 通過先清空後打印實現動畫效果
    while (p->next != NULL) {
        p = p->next;
    }
    gotodelete(p->x, p->y); // 消除尾節點
    switch (click)
    {
    case up:
        y -= 1;
        break;
    case down:
        y += 1;
        break;
    case left:
        x -= 2;
        break;
    case right:
        x += 2;
        break;
    default:
        break;
    }
    if (x != head->x || y != head->y) {
        // 改變座標時更新 暫停遊戲停止更新蛇 
        ChangeBody(x, y);
    }
    p = head;
    // 打印蛇頭
    gotoprint(p->x, p->y);
    // 蛇速度控制 
    int count = score / 10;
    if (count <= 10) speed = 150;
    else if (count > 10 && count <= 20) speed = 100;
    else if (count > 20 && count <= 40) speed = 50;
    else speed = 10;
    Sleep(speed);
}

/**********************************************************/
// 喫到食物處理 添加一個尾巴 
void Eating()
{
    if (head->x == food.x && head->y == food.y)
    {
        creatfood();
        snake* _new = (snake*)malloc(sizeof(snake));
        snake* p;
        p = head;
        while (1)
        {
            if (p->next == NULL) break;
            p = p->next;
        }
        p->next = _new;
        _new->next = NULL;
        score += 10;
        gotoxy(77, 15);
        printf("%d", score);
    }
}

/**********************************************************/
// 更新蛇體座標 只需要消除尾結點 然後把新座標結點置爲頭結點即可 
void ChangeBody(int x, int y)
{
    snake* p = head;
    while (p->next->next != NULL) {
        p = p->next;
    }
    free(p->next);
    p->next = NULL;
    snake* new_head = (snake*)malloc(sizeof(snake));
    new_head->x = x;
    new_head->y = y;
    new_head->next = head;
    head = new_head;
}

/**********************************************************/
// 判斷是否遊戲結束 
int Judge()
{
    if (head->x == 0 || head->x == 56 || head->y == 0 || head->y == 26)
    {
        Finish();
        return 0;
    }
    snake* p = head->next;
    while (1)
    {
        if (p == NULL) break;
        if (head->x == p->x && head->y == p->y)
        {
            Finish();
            return 0;
        }
        p = p->next;
    }
    return 1;
}

/**********************************************************/
void Finish()
{
    system("cls");
    gotoxy(15, 10);
    printf("/**********************************************/");
    gotoxy(15, 20);
    printf("/**********************************************/");
    gotoxy(18, 14);
    printf("GAME   OVER      o(* ̄▽ ̄*)o");
    gotoxy(20, 16);
    printf("Your Score is %d    hiahiahia", score);
    gotoxy(18, 18);
    printf("還不錯哦,     繼續努力O(∩_∩)O");
    gotoxy(0, 27);
    // 釋放空間 
    snake* p = head, * q;
    while (p != NULL) {
        q = p->next;
        free(p);
        p = q;
    }
    system("pause");
}

四、

   easyx 實現:鏈接地址

 效果如下:

     

覺得好的話歡迎犒勞(ง •_•)ง (要恰飯的嘛嘿嘿)

對評論裏的重點問題,我有時間在博客裏多加一些

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章