溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

C語(yǔ)言如何實(shí)現(xiàn)貪吃蛇小黑窗

發(fā)布時(shí)間:2022-01-04 17:10:52 來(lái)源:億速云 閱讀:112 作者:iii 欄目:開(kāi)發(fā)技術(shù)

本篇內(nèi)容主要講解“C語(yǔ)言如何實(shí)現(xiàn)貪吃蛇小黑窗”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“C語(yǔ)言如何實(shí)現(xiàn)貪吃蛇小黑窗”吧!

思路:

1.利用整型二維數(shù)組保存顯示數(shù)據(jù),小蛇每移動(dòng)一次清屏并便利數(shù)組做到動(dòng)態(tài)效果。每次移動(dòng)(清屏)的間隔時(shí)間控制了游戲難度,這個(gè)時(shí)間應(yīng)不斷縮減,直到游戲結(jié)束。

2.需要保存小蛇移動(dòng)的方向,然后寫(xiě)一個(gè)函數(shù)通過(guò)小蛇的移動(dòng)方向去處理二維數(shù)組中的數(shù)據(jù),達(dá)到移動(dòng)小蛇的目的。

3.小蛇的移動(dòng)可分解為兩個(gè)過(guò)程:頭部像前方生長(zhǎng)一格然后尾部消去一格。如果蛇頭吃到食物,尾部無(wú)需消去,此時(shí)應(yīng)立即隨機(jī)生成一個(gè)新的食物。

4.游戲開(kāi)始時(shí)小蛇應(yīng)隨機(jī)生成在地圖某一位置,此時(shí)小蛇的默認(rèn)移動(dòng)方向也應(yīng)該是隨機(jī)的。

5每次移動(dòng)前應(yīng)接收玩家由鍵盤(pán)輸入的移動(dòng)方向,如果接收到后,判斷合法后將其設(shè)為小蛇的默認(rèn)移動(dòng)方向,如果玩家未進(jìn)行任何輸入,小蛇應(yīng)按照默認(rèn)方向移動(dòng)。

個(gè)人難點(diǎn):

1.小蛇移動(dòng)

該函數(shù)需要拿到蛇頭當(dāng)時(shí)所在的位置坐標(biāo)和小蛇的移動(dòng)方向。隨后可由蛇頭位置往移動(dòng)方向往前生長(zhǎng)一格,即將二維數(shù)組中目標(biāo)移動(dòng)位置的數(shù)據(jù)設(shè)置為小蛇的數(shù)據(jù)。消去蛇尾另寫(xiě)一個(gè)函數(shù),調(diào)用前需先判斷是否吃到食物,是否撞到墻壁或者是自身,然后決定是否削去尾部。消去蛇尾需獲得蛇尾的位置,所以我們?cè)谠摵瘮?shù)內(nèi)加入遞歸搜索蛇尾的算法:進(jìn)入函數(shù)后先判斷此時(shí)的位置是否為蛇尾,若不是就將自身位置往后移動(dòng)一格(將蛇身往后一格的坐標(biāo)輸入給DeleteTail函數(shù),然后繼續(xù)此過(guò)程),直到遇到蛇尾,然后將其消去(置零)。

具體代碼實(shí)現(xiàn)如下:

int MoveSnake(int trend, int* px, int* py, int data[ROW][COL], int* t)
{
    int ret = 1;//默認(rèn)前進(jìn)成功
    //printf("trend=%d\n", trend);
    switch (trend) {
    case 1:*py -= 1; break;//向上
    case 2:*px -= 1; break;//向左
    case 3:*py += 1; break;//向下
    case 4:*px += 1; break;//向右
    }//找到即將前進(jìn)的坐標(biāo)
    if (data[*py][*px] == 6) {
        data[*py][*px] = trend;
        CreatFood(data);
        *t *= 0.9;
    }//如果蛇頭要前進(jìn)的格子是食物,向前長(zhǎng)一格,尾部不變;
    else if (data[*py][*px] == 0) {
        data[*py][*px] = trend;//向前長(zhǎng)一格
        DeleteTail(*px, *py, data);//消去最后的尾巴
    }
    else {
        ret = 0;
        printf("前進(jìn)失敗\n");
    }//前進(jìn)失敗
    return ret;
}
 
int DeleteTail(int x, int y, int data[ROW][COL])
{
    //PrintTest(data);
    if (data[y][x] <= 4 && data[y][x] >= 1) {
        switch (data[y][x]) {
        case 1:
            if (DeleteTail(x, y + 1, data) == 0) {
                data[y][x] = 0;
            }
            break;
        case 2:
            if (DeleteTail(x + 1, y, data) == 0) {
                data[y][x] = 0;
            }
            break;
        case 3:
            if (DeleteTail(x, y - 1, data) == 0) {
                data[y][x] = 0;
            }
            break;
        case 4:
            if (DeleteTail(x - 1, y, data) == 0) {
                data[y][x] = 0;
            }
            break;
        }
        return 1;
    }
    else {
        return 0;
    }
}

2.輸入

在實(shí)際代碼實(shí)現(xiàn)的過(guò)程中,我發(fā)現(xiàn)scanf函數(shù)無(wú)法實(shí)現(xiàn)需求,理由是程序執(zhí)行到scanf語(yǔ)句時(shí),會(huì)停留在該位置,直到scanf函數(shù)掃描到輸入后,程序才會(huì)繼續(xù)進(jìn)行。經(jīng)學(xué)習(xí)查閱,決定使用kbhit函數(shù)掃描此時(shí)鍵盤(pán)緩沖區(qū)中是否有數(shù)據(jù):如果有就讀取第一個(gè)數(shù)據(jù),并將后面的數(shù)據(jù)清空,避免后面使用該數(shù)據(jù),若沒(méi)有數(shù)據(jù),緩沖區(qū)不做任何處理,程序也應(yīng)當(dāng)繼續(xù)執(zhí)行。

使用kbhit函數(shù)前應(yīng)“#include<conio.h>”。清理緩沖區(qū)運(yùn)用的是getch()循環(huán)。代碼如下:

int Input() {
    int trend = 0;
    if (kbhit()) {
        char trend_ = getch();
        while (kbhit()) {
            getch();
        }//清空緩沖區(qū)
        //printf("已接收到%c ", trend_);
        switch (trend_) {
        case 'w':trend = 1; break;
        case 'a':trend = 2; break;
        case 's':trend = 3; break;
        case 'd':trend = 4; break;
        default:printf("請(qǐng)輸入w,a,s,d以控制前進(jìn)方向!!\n");
            break;
        }
    }
    else {
        printf("請(qǐng)輸入w,a,s,d以控制前進(jìn)方向!!\n");
    }
    return trend;
}

完整源代碼:

#pragma once
#pragma warning(disable : 4996)
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<Windows.h>
#include<conio.h>

#define ROW 30
#define COL 30
#define TIME 300

int Game();
int Menu();
int Input();
int CreatHead(int* px, int* py, int data[ROW][COL]);
void CreatFood(int data[ROW][COL]);
int MoveSnake(int trend, int* px, int* py, int data[ROW][COL], int* t);
int DeleteTail(int x, int y, int data[ROW][COL]);
void PrintShow(int data[ROW][COL]);
int GameOver(int score);
void PrintTest(int data[ROW][COL]);
#include"main.h"
int main()
{
    int ret = 1;
    while (ret) {
        int choose = Menu();
        int score = 0;
        switch (choose) {
        case 1:
            score = Game();
            ret = GameOver(score);
            break;
        case 2:
            system("cls");
            printf("==========================================================\n");
            printf("                      游戲說(shuō)明                            \n");
            printf("  1.輸入‘w'‘a(chǎn)'‘s'‘d'以控制小蛇的移動(dòng)。\n");
            printf("  2.小蛇在固定時(shí)間內(nèi)只移動(dòng)一次,如一個(gè)時(shí)間段內(nèi)輸入多個(gè)方向\n則以第一次輸入為準(zhǔn)。\n");
            printf("  3.不能撞到墻壁或者是自身。\n");
            printf("  4.小蛇移動(dòng)速度會(huì)在吃到食物后加快,直到游戲結(jié)束。\n");
            printf("  輸入“1”繼續(xù)...........\n");
            printf("==========================================================\n");
            int ok = 0;
            scanf("%d", &ok);
            if (ok) {
                system("cls");
                break;
            }
        case 3:
            ret = 0;
            break;
        }
    }
}
#include"main.h"

int Game()
{
    int data[ROW][COL] = { 0 };
    int time_ = TIME;
    for (int i = 0; i < COL; i++) {
        for (int j = 0; j < ROW; j++) {
            if (i == 0 || i == COL - 1) {
                data[i][j] = 5;//邊界墻
            }
            if (j == 0 || j == ROW - 1) {
                data[i][j] = 5;//邊界墻
            }
        }

    }//初始化數(shù)據(jù)存儲(chǔ)數(shù)組
    //PrintShow(data);
    int x = 0, y = 0;
    int trend = CreatHead(&x, &y, data);
    //生成蛇頭
    CreatFood(data);//生成食物
    int ret = 1;
    while (ret) {
        system("cls");
        PrintShow(data);
        Sleep(time_);
        int trend_ = Input();
        if (trend_ != 0) {
            trend = trend_;
        }
        ret = MoveSnake(trend, &x, &y, data, &time_);
    }
    int score = 0;
    for (int i = 0; i < ROW; i++) {
        for (int j = 0; j < COL; j++) {
            if (data[i][j] <= 4 && data[i][j] >= 1) {
                score++;
            }
        }
    }
    return score;
}

int Menu()
{
    int choose = 0;
    while (1) {
        printf("==========================\n");
        printf("===歡迎進(jìn)入貪吃蛇游戲!===\n");
        printf("===   1、經(jīng)典模式      ===\n");
        printf("===   2、游戲說(shuō)明      ===\n");
        printf("===   3、退出游戲      ===\n");
        printf("=== 請(qǐng)輸入您的選項(xiàng)...  ===\n");
        printf("==========================\n");
        scanf("%d", &choose);
        if (choose == 1 || choose == 2 || choose == 3) {
            break;
        }
    }
    return choose;
}

int MoveSnake(int trend, int* px, int* py, int data[ROW][COL], int* t)
{
    int ret = 1;//默認(rèn)前進(jìn)成功
    //printf("trend=%d\n", trend);
    switch (trend) {
    case 1:*py -= 1; break;//向上
    case 2:*px -= 1; break;//向左
    case 3:*py += 1; break;//向下
    case 4:*px += 1; break;//向右
    }//找到即將前進(jìn)的坐標(biāo)
    if (data[*py][*px] == 6) {
        data[*py][*px] = trend;
        CreatFood(data);
        *t *= 0.9;
    }//如果蛇頭要前進(jìn)的格子是食物,向前長(zhǎng)一格,尾部不變;
    else if (data[*py][*px] == 0) {
        data[*py][*px] = trend;//向前長(zhǎng)一格
        DeleteTail(*px, *py, data);//消去最后的尾巴
    }
    else {
        ret = 0;
        printf("前進(jìn)失敗\n");
    }//前進(jìn)失敗
    return ret;
}

void CreatFood(int data[ROW][COL])
{
    srand(time(NULL));
    while (1) {
        int x = rand() % (COL - 2) + 1;
        int y = rand() % (ROW - 2) + 1;
        if (data[y][x] == 0) {
            data[y][x] = 6;
            break;
        }
    }
}
 
int DeleteTail(int x, int y, int data[ROW][COL])
{
    //PrintTest(data);
    if (data[y][x] <= 4 && data[y][x] >= 1) {
        switch (data[y][x]) {
        case 1:
            if (DeleteTail(x, y + 1, data) == 0) {
                data[y][x] = 0;
            }
            break;
        case 2:
            if (DeleteTail(x + 1, y, data) == 0) {
                data[y][x] = 0;
            }
            break;
        case 3:
            if (DeleteTail(x, y - 1, data) == 0) {
                data[y][x] = 0;
            }
            break;
        case 4:
            if (DeleteTail(x - 1, y, data) == 0) {
                data[y][x] = 0;
            }
            break;
        }
        return 1;
    }
    else {
        return 0;
    }
}
int Input() {
    int trend = 0;
    if (kbhit()) {
        char trend_ = getch();
        while (kbhit()) {
            getch();
        }//清空緩沖區(qū)
        //printf("已接收到%c ", trend_);
        switch (trend_) {
        case 'w':trend = 1; break;
        case 'a':trend = 2; break;
        case 's':trend = 3; break;
        case 'd':trend = 4; break;
        default:printf("請(qǐng)輸入w,a,s,d以控制前進(jìn)方向!!\n");
            break;
        }
    }
    else {
        printf("請(qǐng)輸入w,a,s,d以控制前進(jìn)方向!!\n");
    }
    return trend;
}
 
void PrintShow(int data[ROW][COL])
{
    for (int i = 0; i < ROW; i++) {
        for (int j = 0; j < COL; j++) {
            if (data[i][j] == 0) {
                printf("  ");
            }
            if (data[i][j] == 5) {
                printf("■");
            }
            if (data[i][j] >= 1 && data[i][j] <= 4) {
                printf("□");
            }
            if (data[i][j] == 6) {
                printf("●");
            }
        }
        printf("\n");
    }
}
 
int CreatHead(int* px, int* py, int data[ROW][COL])
{
    srand(time(NULL));
    while (1) {
        *px = rand() % (COL - 8) + 4;
        *py = rand() % (ROW - 8) + 4;
        if (data[*py][*px] == 0) {
            break;
        }
    }//蛇頭只能刷新在空格位置
    //x,y始終為蛇頭的坐標(biāo)
    int trend = rand() % 4 + 1;//1:上,2:左,3:下,4:右
    data[*py][*px] = trend;
    switch (trend) {
    case 1:data[*py + 1][*px] = 1;
        data[*py + 2][*px] = 1; break;
    case 2:data[*py][*px + 1] = 2;
        data[*py][*px + 2] = 2; break;
    case 3:data[*py - 1][*px] = 3;
        data[*py - 2][*px] = 3; break;
    case 4:data[*py][*px - 1] = 4;
        data[*py][*px - 2] = 4; break;
    }
    return trend;
}
void PrintTest(int data[ROW][COL])
{
    printf("\n");
    for (int i = 0; i < ROW; i++) {
        for (int j = 0; j < COL; j++) {
            printf("%d ", data[i][j]);
        }
        printf("\n");
    }
}
 
int GameOver(int score)
{
    system("cls");
    printf("==============================================\n");
    printf("游戲結(jié)束,您的小蛇最終長(zhǎng)到了%d米長(zhǎng)...\n", score);
    printf("輸入1重新開(kāi)始,輸入其它退出游戲...\n");
    int ret = 0;
    scanf("%d", &ret);
    if (ret == 1) {
        return 1;
    }
    else {
        return 0;
    }
}

到此,相信大家對(duì)“C語(yǔ)言如何實(shí)現(xiàn)貪吃蛇小黑窗”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI