[C++] 貪食蛇

以Windows Console運行的貪食蛇遊戲

專案編譯通過使用VC6

以下是代碼


main.cpp

#include<iostream>
#include<direct.h>
#include"Snake_Class.h"

#define _max(ID) --snake.ID_option < ID_1?ID : snake.ID_option
#define _min(ID) ++snake.ID_option > ID?ID_1 : snake.ID_option

//鉤子過程
LRESULT CALLBACK _HookProc(int,WPARAM,LPARAM);

void Wall();       //畫牆函數
void Frame();      //畫框函數
void initialize_();//初始化蛇結構數據

Snake_data snake;
Snake_class csnake(&snake);
static HANDLE handle;  //控制台句柄
//控制台信息結構
static CONSOLE_SCREEN_BUFFER_INFO info ;

int main(){
    using namespace std;
        //獲取輸出緩衝區句柄
    handle = GetStdHandle(STD_OUTPUT_HANDLE); 
    //獲取相關信息(主要是緩衝區大小)
    GetConsoleScreenBufferInfo( handle, &info );
    initialize_();
    _mkdir( "d://SnakeRecord" ); //創建目錄

    CONSOLE_CURSOR_INFO cursor;           //光標結構 
    cursor.dwSize = 10;
    cursor.bVisible = 0;                  //0為隱藏光標
    SetConsoleCursorInfo(handle, &cursor);//設置隱藏光標函數 

    //csnake.ShowMenu();
    HHOOK hook;
    MSG msg;
    //相應的鉤子有相應的過程函數MSDN中可看,安裝鍵盤鉤子 
    hook = SetWindowsHookEx(WH_KEYBOARD_LL,_HookProc,GetModuleHandle(NULL),0);
    while(1){
        //判斷蛇是否還活著
        Wall();
        if( !snake.state && snake.ID_interface == ID_2 ){
               //csnake.Die();
               snake.ID_interface = ID_4;
               Frame();
        }
        if( snake.ID_interface == ID_2 ){
             csnake.StartGame();
             Sleep( snake.rank );
        }
        if( PeekMessage(&msg,NULL,0,0,PM_REMOVE) ){//循環接收消息
               TranslateMessage(&msg);
               DispatchMessage(&msg);
        }
    }

    UnhookWindowsHookEx( hook );    //卸載鉤子 
    return 0;
}

//定義鉤子過程(未完成)
LRESULT CALLBACK _HookProc(int message, WPARAM wParam, LPARAM lParam){
    //判斷是否彈起按鍵消息
    if( wParam == WM_KEYUP){
        bool state = true;
            switch(((LPKBDLLHOOKSTRUCT) lParam)->vkCode){//lParam:指向一個結構 
                //按下上鍵
                case VK_UP:              
                    switch( snake.ID_interface ){
                        case ID_1:
                            snake.Flag = true;
                            csnake.ShowMenu();
                            snake.Flag = false;
                            snake.ID_option = _max( ID_5 );
                            csnake.ShowMenu();
                            break;
                        case ID_2:
                            if( snake.key != VK_DOWN && snake.key != VK_UP ){
                                snake.key = VK_UP;
                            }
                            break;
                        case ID_5:
                            snake.Flag = true;
                            csnake.ShowRank();
                            snake.ID_option = _max( ID_3 );
                            snake.Flag = false;
                            csnake.ShowRank();
                            break;
                        case ID_6:
                            snake.Flag = true;
                            csnake.ShowRecord();
                            snake.ID_option = _max( ID_6 );
                            snake.Flag = false;
                            csnake.ShowRecord();
                            break;
                    }
                    break;
                    //按下下鍵
                case VK_DOWN:
                    switch( snake.ID_interface ){
                        case ID_1:
                            snake.Flag = true;
                            csnake.ShowMenu();
                            snake.Flag = false;
                            snake.ID_option = _min( ID_5 );
                            csnake.ShowMenu();
                            break;
                        case ID_2:
                            if( snake.key != VK_UP && snake.key != VK_DOWN ){
                                snake.key = VK_DOWN;
                            }
                            break;
                        case ID_5:
                            snake.Flag = true;
                            csnake.ShowRank();
                            snake.ID_option = _min( ID_3 );
                            snake.Flag = false;
                            csnake.ShowRank();
                            break;
                        case ID_6:
                            snake.Flag = true;
                            csnake.ShowRecord();
                            snake.ID_option = _min( ID_6 );
                            snake.Flag = false;
                            csnake.ShowRecord();
                            break;
                    }
                    break;
                    //按下左鍵
                case VK_LEFT:
                    switch( snake.ID_interface ){
                        case ID_2:
                            if( snake.key != VK_RIGHT && snake.key != VK_LEFT ){
                                snake.key = VK_LEFT;
                            }
                            break;
                        case ID_3:
                            snake.Flag = true;
                            csnake.ShowPause();
                            snake.ID_option = _max( ID_3 );
                            snake.Flag = false;
                            csnake.ShowPause();
                            break;
                        case ID_4:
                            snake.Flag = true;
                            csnake.Die();
                            snake.ID_option = _max( ID_2 );
                            snake.Flag = false;
                            csnake.Die();
                            break;
                    }
                    break;
                    //按下右鍵
                 case VK_RIGHT:
                     switch( snake.ID_interface ){
                        case ID_2:
                            if( snake.key != VK_LEFT && snake.key != VK_RIGHT ){
                                snake.key = VK_RIGHT;
                            }
                            break;
                        case ID_3:
                            snake.Flag = true;
                            csnake.ShowPause();
                            snake.ID_option = _min( ID_3 );
                            snake.Flag = false;
                            csnake.ShowPause();
                            break;
                        case ID_4:
                            snake.Flag = true;
                            csnake.Die();
                            snake.ID_option = _min( ID_2 );
                            snake.Flag = false;
                            csnake.Die();
                            break;
                     }
                     break;
                     //按下空格和回車鍵
                 case VK_SPACE:
                 case VK_RETURN:
                     system( "cls" );
                     switch( snake.ID_interface ){
                        case ID_1://主菜單界面
                            switch( snake.ID_option ){
                                 case ID_1:
                                     snake.ID_interface = ID_2;//開始遊戲界面ID
                                     csnake.StartGame();
                                     break;
                                 case ID_2:
                                     snake.ID_interface = ID_5;//等級界面
                                     snake.ID_option = ID_1;
                                     Frame();
                                     //csnake.ShowRank();
                                     break;
                                 case ID_3:
                                     snake.ID_interface = ID_6;//讀取記錄界面
                                     snake.ID_option = ID_1;
                                     csnake.ShowRecord();
                                     break;
                                 case ID_4:
                                     snake.ID_interface = ID_7;//英雄榜界面
                                     csnake.ShowArmory();
                                     break;
                                 case ID_5:
                                     state = false;
                                     break;
                            }
                            break;

                        case ID_2://遊戲界面
                            snake.ID_interface = ID_3;
                            snake.ID_option = ID_1;
                            Frame();
                            //csnake.ShowPause();
                            break;

                        case ID_3://暫停界面
                            switch( snake.ID_option ){
                                 case ID_1:
                                     snake.ID_interface = ID_2;
                                     csnake.StartGame();
                                     break;
                                 case ID_2:
                                     csnake.SaveRecord();
                                     break;
                                 case ID_3:
                                     state = false;
                                     break;
                            }
                            break;

                        case ID_4://死亡界面
                            switch( snake.ID_option ){
                                 case ID_1:
                                     snake.ID_interface = ID_1;
                                     snake.ID_option = ID_1;
                                     initialize_();
                                     csnake.ShowMenu();
                                     break;
                                 case ID_2:
                                     state = false;
                                     break;
                            }
                            break;

                        case ID_5://等級界面
                            switch( snake.ID_option ){
                                 case ID_1:
                                     snake.rank = first;
                                     break;
                                 case ID_2:
                                     snake.rank = middle;
                                     break;
                                 case ID_3:
                                     snake.rank = high;
                                     break;
                            }
                            snake.ID_interface = ID_1;
                            snake.ID_option = ID_1;
                            csnake.ShowMenu();
                            break;

                        case ID_6://讀取界面
                            size_t id;
                            switch( snake.ID_option ){
                                 case ID_1:
                                     id = 0; break;
                                 case ID_2:
                                     id = 1; break;
                                 case ID_3:
                                     id = 2; break;
                                 case ID_4:
                                     id = 3; break;
                                 case ID_5:
                                     id = 4; break;
                            }
                            //進行讀取文件
                            if( snake.ID_option != ID_6&&snake.ID_option != ID_7 ){
                                     initialize_();
                                     if( csnake.Read( id ) ){
                                         snake.ID_interface = ID_2;
                                         csnake.StartGame();
                                     }
                                     else snake.ID_interface = ID_6;
                            }
                            else {
                                     snake.ID_interface = ID_1;
                                     snake.ID_option = ID_1;
                                     csnake.ShowMenu();
                            }
                            break;

                        case ID_7://英雄榜界面
                            snake.ID_interface = ID_1;
                            snake.ID_option = ID_1;
                            csnake.ShowMenu();
                            break;
                     }
                     if( !state ){
                         COORD cd = { info.srWindow.Right/4, info.srWindow.Bottom/5*4 };
                         SetConsoleCursorPosition( handle,cd );
                         exit(0);
                     }
                     snake.ID_option = ID_1;
                    break;
            }
    }
          //消息傳給下個鉤子
          return CallNextHookEx ( NULL, message, wParam, lParam );
}

//畫牆函數和調用相應界面(已測試完成)
void Wall(){
    short i;
    COORD coord = { 0,0 };  //坐標結構
//繪牆
    SetConsoleCursorPosition( handle, coord );
    for( i=0;i<=info.srWindow.Right;++i )
            std::cout<<"#";

    coord.X = info.srWindow.Right;
    coord.Y = 1;
    for( i=1;i<info.srWindow.Bottom;++i ){
        SetConsoleCursorPosition( handle, coord );
        std::cout<<"#";
        ++coord.Y ;
    }

    coord.X = 0;
    coord.Y = info.srWindow.Bottom;
    for( i=1;i<=info.srWindow.Right;++i ){
        SetConsoleCursorPosition( handle, coord );
        std::cout<<"#";
        ++coord.X ;
    }

    coord.X = 0;
    coord.Y = 1;
    for( i=1;i<info.srWindow.Bottom;++i ){
        SetConsoleCursorPosition( handle, coord );
        std::cout<<"#";
        ++coord.Y ;
    }
//判斷所在界面顯示相關界面的菜單選項及其它
    int j = info.srWindow.Right/4;
    switch( snake.ID_interface ){
        case ID_1:
            csnake.ShowMenu(); 
            coord.X = j;
            coord.Y = info.srWindow.Bottom-6;
            SetConsoleCursorPosition( handle, coord );
            std::cout<<"o(-\"-)o  貪  #^_^#  吃  →_→  蛇  \\(^o^)/";
            break;//顯示菜單選項

        case ID_2:
        case ID_3:
        case ID_4:
            //繪輸出信息框
            coord.X = 1;
            coord.Y = info.srWindow.Bottom - 5;
            SetConsoleCursorPosition( handle, coord );
            for( i=1;i<info.srWindow.Right; std::cout<<"#", ++i );
            for( coord.X=j;coord.X<=info.srWindow.Right-j;coord.X+=j ){
                coord.Y = info.srWindow.Bottom - 5;
                for( i=coord.Y;i<info.srWindow.Bottom;++i ){
                        SetConsoleCursorPosition( handle, coord );
                        std::cout<<"#";
                        ++coord.Y ;
                }
            }
            //輸出每個框的信息
            coord.X = 2;
            coord.Y-= 4;
            SetConsoleCursorPosition( handle, coord );
            std::cout<<"遊戲難度:";
            coord.Y +=2;
            SetConsoleCursorPosition( handle, coord );
            std::cout<<"\t   ";
            switch( snake.rank ){
                  case first:
                      std::cout<<"初 級"; break;
                  case middle:
                      std::cout<<"中 級"; break;
                  case high:
                      std::cout<<"高 級"; break;
            }
      //當前分數
            coord.X += j;
            coord.Y -= 2;
            SetConsoleCursorPosition( handle, coord );
            std::cout<<"  當 前 分 數";
            coord.X +=j/2-3;
            coord.Y +=2;
            SetConsoleCursorPosition( handle, coord );
            std::cout<<snake.mark ;
      //操作說明
            coord.X = j*2+1;
            coord.Y = info.srWindow.Bottom -4;
            SetConsoleCursorPosition( handle, coord );
            std::cout<<" 操作說明: ";
            coord.Y +=2;
            SetConsoleCursorPosition( handle, coord );
            std::cout<<"  ↑ ↓ ←  →";
            ++coord.Y; 
            SetConsoleCursorPosition( handle, coord );
            std::cout<<" 空格: 暫停遊戲";
      //製作人
            coord.X += j;
            SetConsoleCursorPosition( handle, coord );
            std::cout<<"\t作者:jordanyeh";
            break;

        case ID_5:
            csnake.ShowRank(); break;//顯示遊戲等級

        case ID_6:
            csnake.ShowRecord(); break;//顯示存檔記錄

        case ID_7:
            csnake.ShowArmory(); break;//顯示英雄榜
    }

}

//畫框函數(完成)
void Frame(){
	short i;
    COORD coord = { 0, info.srWindow.Bottom/3 };
    SetConsoleCursorPosition( handle, coord );
    for( i=0;i<=info.srWindow.Right; std::cout<<"-", ++i );
        
    coord.Y = info.srWindow.Bottom/3*2;
    SetConsoleCursorPosition( handle, coord );
    for( i=0;i<=info.srWindow.Right; std::cout<<"-", ++i );
        
    switch( snake.ID_interface ){
        case ID_3:
            csnake.ShowPause(); break;//顯示暫停菜單
        case ID_4:
            csnake.Die(); break;//顯示死亡界面菜單
        case ID_5:
            csnake.ShowRank(); break;//顯示等級選項
    }
}

//初始化蛇數據(完成)
void initialize_(){
    snake.state = true; //蛇狀態
    snake.Snake_size = 5; //蛇初始化長度
    //初始化蛇位置
    COORD cd;
    cd.Y = 3;
    snake.Snake_coord.clear();
    for( size_t i=10;i>5;--i ){
        cd.X = i;
        snake.Snake_coord.push_back( cd );
    }
    snake.food_coord.X = 0;
    snake.food_coord.Y = 0;
    snake.rank = first;   //默認等級
    snake.mark = 0; //分數
    snake.key = VK_RIGHT; 
    snake.ID_interface = ID_1;//界面標記
    snake.ID_option = ID_1;   //選項標記
    snake.Flag = false;
}

Snake_class.cpp

#include"Snake_Class.h"
#include<iostream>
#include<fstream>
#include<ctime>
#include<cstdlib>

//獲取緩衝區句柄
static const HANDLE handle = GetStdHandle( STD_OUTPUT_HANDLE );
static CONSOLE_SCREEN_BUFFER_INFO info ;
//保存蛇的記錄數據文件
static const char *Snake_Record[] = { "d://SnakeRecord//Snake1.txt",
                                      "d://SnakeRecord//Snake2.txt",
                                      "d://SnakeRecord//Snake3.txt",
                                      "d://SnakeRecord//Snake4.txt",
                                      "d://SnakeRecord//Snake5.txt" };

static const char *S_Armory[] = { "d://SnakeRecord//Armory1.txt",
                                  "d://SnakeRecord//Armory2.txt",
                                  "d://SnakeRecord//Armory3.txt" };
//顯示主菜單(完成已測試)
void Snake_class::ShowMenu(){
    //獲取緩衝區相關信息
    GetConsoleScreenBufferInfo( handle, &info );
    char *str[] = {"開 始 游 戲",
                   "難 度 等 級",
                   "讀 取 存 檔",
                   "英 雄 榜",
                   "退 出 游 戲"};
    //輸出菜單選項
    short y = 3;
    COORD cd = { info.srWindow.Right/2 - 5, y };
    for( size_t n=0;n<sizeof(str)/sizeof(*str);++n ){
        SetConsoleCursorPosition( handle, cd );
        std::cout<<*(str+n);
        cd.Y += 2;
    }
//判斷指針指向哪個菜單選項
    cd.X -= 2;
    cd.Y  = y;
    switch( pSnake->ID_option ){
        case ID_1:
            break;
        case ID_2:
            cd.Y = y+2; break;
        case ID_3:
            cd.Y = y+4; break;
        case ID_4:
            cd.Y = y+6; break;
        case ID_5:
            cd.Y = y+8; break;
    }
    ShowPointer( cd,pSnake->Flag?std::string("  "):std::string("><") );
}

//開始遊戲(完成待測試)
void Snake_class::StartGame(){
    COORD cd;
    //判斷是否已有食物
    if( !pSnake->food_coord.X ){
        srand((unsigned int)time(NULL));
        while(1){
            //限制食物出現的坐標不與圍牆相同
              ++( cd.X = rand()%78 ); 
              ++( cd.Y = rand()%18 );
            //判斷食物坐標是否與蛇身吻合
            std::vector<COORD>::iterator ite;
            for( ite=pSnake->Snake_coord.begin(); ite!=pSnake->Snake_coord.end(); ++ite ){
                    if( ite->X == cd.X && ite->Y == cd.Y )
                        break;
            }
            if( ite == pSnake->Snake_coord.end() ){
                pSnake->food_coord.X = cd.X ;
                pSnake->food_coord.Y = cd.Y ;
                break;
            }
        }
    }
    SetConsoleCursorPosition( handle, pSnake->food_coord );
    std::cout<<"*";
    //判定按鍵方向
    cd.X  = pSnake->Snake_coord.begin()->X;
    cd.Y = pSnake->Snake_coord.begin()->Y ;
    switch( pSnake->key ){
        case VK_UP:
            --cd.Y; break;
        case VK_DOWN:
            ++cd.Y; break;
        case VK_LEFT:
            --cd.X; break;
        case VK_RIGHT:
            ++cd.X; break;
    }
    ShowSnake( cd );
    JudgeDie();
}

//顯示暫停界面(完成已測試)
void Snake_class::ShowPause(){
    COORD cd = { info.srWindow.Right/2-10, info.srWindow.Bottom/5 };
    SetConsoleCursorPosition( handle, cd );
    std::cout<<"游 戲 暫 停 中 ......";
    char *str[] = { "繼 續 游 戲",
                    "保 存 游 戲",
                    "退 出 游 戲" };
//輸出菜單選項
    short X = info.srWindow.Right/3;
    cd.X = X/2-5 ;
    cd.Y = info.srWindow.Bottom/3*2-4;
    for( size_t i=0;i<sizeof(str)/sizeof(*str);++i ){
        SetConsoleCursorPosition( handle, cd );
        std::cout<<*(str+i);
        cd.X += X;
    }

//判斷指針應指向的菜單選項
    switch( pSnake->ID_option ){
        case ID_1:
            cd.X = X/2-7; break;
        case ID_2:
            cd.X = X/2+X-7; break;
        case ID_3:
            cd.X = X/2+2*X-7; break;
    }
    ShowPointer( cd,pSnake->Flag?std::string("  "):std::string("><") );
}

//保存記錄(完成未測試)
void Snake_class::SaveRecord(){
    std::ofstream outopen;
    outopen.open( *( Snake_Record + Create_file() ) );
    if( !outopen ){
        std::cerr<<"\n打開文件失敗!\n";
        exit(0);
    }
    //保存記錄到文件中,前面加"0"是為了後面檢測是否文件為空使用
    outopen<<"0 "<<pSnake->Snake_size<<" ";
    for(std::vector<COORD>::iterator ite=pSnake->Snake_coord.begin();
        ite!=pSnake->Snake_coord.end();++ite )
            outopen<<ite->X<<" "<<ite->Y<<" ";
    outopen<<pSnake->rank<<" "<<pSnake->mark<<" "<<pSnake->key;
    outopen.close();
//輸出保存成功
    COORD cd = {info.srWindow.Right/2-4, info.srWindow.Bottom/3*2-1};
    SetConsoleCursorPosition( handle, cd );
    std::cout<<"save success! \a";
}

//顯示等級(已測試)
void Snake_class::ShowRank(){
    COORD cd = { info.srWindow.Right/2-6, info.srWindow.Bottom/3+2 };
    char *str[] = { "初       級",
                    "中       級",
                    "高       級" };
    for( size_t i=0;i<sizeof(str)/sizeof(*str);++i ){
        SetConsoleCursorPosition( handle, cd );
        std::cout<<*(str+i);
        cd.Y += 2;
    }
    //判斷指針所停留的選項
    cd.X -= 2;
    cd.Y  = info.srWindow.Bottom/3+2;
    switch( pSnake->ID_option ){
        case ID_1:
            break;
        case ID_2:
            cd.Y += 2; break;
        case ID_3:
            cd.Y += 4; break;
    }
    ShowPointer( cd,pSnake->Flag?std::string("  "):std::string("><") );
}

//顯示存檔記錄(已測試)
void Snake_class::ShowRecord(){
    COORD cd = { info.srWindow.Right/2-12, 8 };
    //輸出記錄
    std::ifstream inopen;
    SetConsoleCursorPosition( handle, cd );
    for( size_t i=0;i<sizeof(Snake_Record)/sizeof(*Snake_Record);++i ){
        inopen.open( *(Snake_Record+i) );
        if( !inopen || (inopen.get() == EOF && i==0) ){
            Show_not();
            pSnake->ID_option = ID_7;//第7個選項標記,在按回車時檢測下
            return;
        }
        if( inopen.get() != EOF ){
            UINT _rank, _mark;
            inopen>>_mark;
            ++(_mark *= 2);
            while( _mark-- )
                inopen>>_rank;
            inopen>>_mark;
            switch( _rank ){
                case first:
                    std::cout<<"初級"; break;
                case middle:
                    std::cout<<"中級"; break;
                case high:
                    std::cout<<"高級"; break;
            }
            std::cout<<"\t\t\t  "<<_mark;            
        }else
            std::cout<<" ---\t\t\t  ---"; 

        cd.Y += 2;
        SetConsoleCursorPosition( handle, cd );
        inopen.close();
        inopen.clear();//重置流狀態
    }
    std::cout<<"\t   返 回 菜 單";
    cd.X = info.srWindow.Right/2-4; 
    cd.Y = 4;
    SetConsoleCursorPosition( handle, cd );
    std::cout<<"存 檔 記 錄";
    cd.X -=10;
    cd.Y +=2;
    SetConsoleCursorPosition( handle, cd );
    std::cout<<"遊戲等級\t\t當前分數";
    //輸出指針
    cd.X = info.srWindow.Right/2-14;
    cd.Y = 8;
    switch( pSnake->ID_option ){
        case ID_1:
            break;
        case ID_2:
            cd.Y +=2; break;
        case ID_3:
            cd.Y +=4; break;
        case ID_4:
            cd.Y +=6; break;
        case ID_5:
            cd.Y +=8; break;
        case ID_6:
            cd.Y +=10;break;
    }
    ShowPointer( cd,pSnake->Flag?std::string("  "):std::string("><") );
}

//讀取記錄
bool Snake_class::Read( size_t i ){
    std::ifstream inopen( *(Snake_Record+i) );
    if( inopen.get() == EOF ){
        std::cout<<"\a";
        inopen.close();
        return false;
    }
    inopen>>pSnake->Snake_size;
    COORD cd;
    pSnake->Snake_coord.clear();
    for( int n=1;n<=pSnake->Snake_size;++n ){
        inopen>>cd.X>>cd.Y ;
        pSnake->Snake_coord.push_back( cd );
    }
    inopen>>pSnake->rank>>pSnake->mark>>pSnake->key;
    inopen.close();
    inopen.clear();
    return true;
}

//顯示英雄榜(未測試)
void Snake_class::ShowArmory(){
    short nt=0;
    COORD cd = { info.srWindow.Right/3, info.srWindow.Bottom/3 };
    std::ifstream inopen;
    for( size_t i=0;i<sizeof(S_Armory)/sizeof(*S_Armory);++i ){
        UINT _rank=0, _mark=0;
        inopen.open( *(S_Armory+i) );
        if( !inopen ){
            ++nt;
            continue;
        }
        inopen>>_rank>>_mark;
        switch( _rank ){
            case first:
                SetConsoleCursorPosition( handle, cd );
                std::cout<<"小牛 :初級\t\t  "<<_mark;
                break;
            case middle:
                cd.Y +=2;
                SetConsoleCursorPosition( handle, cd );
                std::cout<<"中牛 :中級\t\t  "<<_mark;
                break;
            case high:
                cd.Y +=2;
                SetConsoleCursorPosition( handle, cd );
                std::cout<<"大牛 :高級\t\t  "<<_mark;
                break;
        }
        inopen.close();
        inopen.clear();
    }
    if( nt == 3 ){
        Show_not();
        return;
    }
    cd.X = info.srWindow.Right/2-3;
    cd.Y = 4;
    SetConsoleCursorPosition( handle, cd );
    std::cout<<"英 雄 榜";
    cd.X -=10;
    cd.Y +=2;
    SetConsoleCursorPosition( handle,cd );
    std::cout<<"\t等 級\t\t分 數"; 
    cd.Y = info.srWindow.Bottom-7;
    SetConsoleCursorPosition( handle, cd );
    std::cout<<"按回車返回主菜單........";
}

//死亡界面(未測試)
void Snake_class::Die(){
    COORD cd = { info.srWindow.Right/2-10, info.srWindow.Bottom/5 };
    SetConsoleCursorPosition( handle, cd );
    std::cout<<"    您 已 x_x 了 !";
    char *str[] = { "返 回 菜 單",
                    "退 出 游 戲" };
//輸出菜單選項
    short X = info.srWindow.Right/2;
    cd.X = X/2-5 ;
    cd.Y = info.srWindow.Bottom/3*2-4;
    for( size_t i=0;i<sizeof(str)/sizeof(*str);++i ){
        SetConsoleCursorPosition( handle, cd );
        std::cout<<*(str+i);
        cd.X += X;
    }

//判斷指針應指向的菜單選項
    switch( pSnake->ID_option ){
        case ID_1:
            cd.X = X/2-7; break;
        case ID_2:
            cd.X = X/2+X-7; break;
    }
    ShowPointer( cd,pSnake->Flag?std::string("  "):std::string("><") );
    if( Jesus() ){
        cd.X = X/2;
        cd.Y = info.srWindow.Bottom/3;
        SetConsoleCursorPosition( handle, cd );
        std::cout<<"喲...這分? ╮(╯▽╰)╭ 也能上榜。。。!";
        cd.Y +=2;
        SetConsoleCursorPosition( handle, cd );
        std::cout<<"上榜等級:";
        switch( pSnake->rank ){
            case first:
                std::cout<<"初級"; break;
            case middle:
                std::cout<<"中級"; break;
            case high:
                std::cout<<"高級"; break;
        }
        std::cout<<"\t上榜分數:"<<pSnake->mark;
    }
}

//存儲記錄文件(完成未測試)
size_t Snake_class::Create_file(){
    std::ifstream inopen;
    size_t fn=0, fc=0, iend = sizeof(Snake_Record)/sizeof(*Snake_Record);
    //判斷文件是否存在或文件已被存滿
    for( size_t i=0;i<iend;++i ){
        inopen.open( *(Snake_Record+i) );
        if( !inopen ) ++fn;
        else if( inopen.get() == EOF ){  
            inopen.close(); 
            return i; 
        }
        else { ++fc; inopen.close(); }
    }
    if( fn == iend || fc == iend ){
            std::ofstream outopen;
                   //創建文本
            for( size_t i=0;i<iend;++i ){
                outopen.open( *(Snake_Record+i) );
                outopen.close(); 
            }
    } 
    //返回打開成功的文件索引
    return 0 ;
}

//判斷死亡(未測試)
void Snake_class::JudgeDie(){
    std::vector<COORD>::iterator hbeg = pSnake->Snake_coord.begin(),
        beg = hbeg+1;
    while( beg != pSnake->Snake_coord.end() ){
        if( beg->X == hbeg->X && beg->Y == hbeg->Y ){
            pSnake->state = FALSE;
            return;
        }
        ++beg;
    }
    COORD cd;
    if(hbeg->X <= 0 || hbeg->Y <= 0 ||
        hbeg->X >=info.srWindow.Right || hbeg->Y >= info.srWindow.Bottom-5 ){
            if( pSnake->Snake_size < 40 ){
                pSnake->state = FALSE;
                return;
            }
            //如果達到了40級可以穿牆
            switch( pSnake->key ){
                case VK_UP:
                    cd.X = pSnake->Snake_coord.begin()->X ;
                    cd.Y = info.srWindow.Bottom-6;
                    break;
                case VK_DOWN:
                    cd.X = pSnake->Snake_coord.begin()->X ;
                    cd.Y = 1;
                    break;
                case VK_LEFT:
                    cd.X = info.srWindow.Right-1;
                    cd.Y = pSnake->Snake_coord.begin()->Y ;
                    break;
                case VK_RIGHT:
                    cd.X = 1;
                    cd.Y = pSnake->Snake_coord.begin()->Y ;
                    break;
            }
            ShowSnake( cd );
    }
}

//上榜判斷(未測試)
bool Snake_class::Jesus(){
    std::ifstream inopen;
    size_t i;
    //判斷相應等級打開相應文件
    switch( pSnake->rank ){
        case first:
            i=0; break;
        case middle:
            i=1; break;
        case high:
            i=2; break;
    }
    inopen.open( *(S_Armory+i) );
    if( inopen ){
        UINT _mark;
        inopen>>_mark>>_mark;
        if( _mark >= pSnake->mark ){
            inopen.close();
            return FALSE;
        }
    }
    std::ofstream outopen( *(S_Armory+i) );//創建文件並輸入
    if( !outopen ){
        std::cerr<<"打開英雄榜文件出錯"<<std::endl;
        exit(0);
    }
    outopen<<pSnake->rank<<" "<<pSnake->mark;
    outopen.close();
    return TRUE;
}
//顯示蛇(未測試)
void Snake_class::ShowSnake( COORD& cd){
    if( cd.X == pSnake->food_coord.X && cd.Y == pSnake->food_coord.Y ){
            //在最後添加一個坐標
        pSnake->Snake_coord.push_back( *(pSnake->Snake_coord.rbegin()) );
        pSnake->food_coord.X = pSnake->food_coord.Y = 0;//標誌食物已被吃掉
        ++pSnake->mark;
        ++pSnake->Snake_size;
    }
    COORD cod;
    cod.X = (pSnake->Snake_coord.rbegin())->X ;
    cod.Y = (pSnake->Snake_coord.rbegin())->Y ;
    std::vector<COORD>::reverse_iterator rbeg = pSnake->Snake_coord.rbegin();
    while( rbeg != pSnake->Snake_coord.rend()-1 ){
        rbeg->X = (rbeg+1)->X ;
        rbeg->Y = (rbeg+1)->Y ;
        ++rbeg;
    }
    //顯示蛇
    pSnake->Snake_coord.begin()->X = cd.X ;
    pSnake->Snake_coord.begin()->Y = cd.Y ;
    for( std::vector<COORD>::iterator beg = pSnake->Snake_coord.begin();
        beg != pSnake->Snake_coord.end();++beg ){
            SetConsoleCursorPosition( handle, *beg );
            std::cout<<"*";
    }
    SetConsoleCursorPosition( handle,cod );
    std::cout<<" ";
}

//顯示指針(完成)
inline void Snake_class::ShowPointer( COORD cd,std::string str ){
    SetConsoleCursorPosition( handle, cd );
    std::cout<<str[0];
    pSnake->ID_interface != ID_6?cd.X += 14:cd.X = info.srWindow.Right/3*2+3;
    SetConsoleCursorPosition( handle, cd );
    std::cout<<str[1];
}

//顯示無數據(完成)
inline void Snake_class::Show_not(){
    COORD cd = { info.srWindow.Right/2-4 ,info.srWindow.Bottom/2 };
    SetConsoleCursorPosition( handle, cd );
    std::cout<<"無 數 據 !";
    cd.X -= 6;
    cd.Y += 2;
    SetConsoleCursorPosition( handle, cd );
    std::cout<<"請按回車返回主菜單......";
}



Snake_Class.h

#ifndef SNAKE
#define SNAKE

#include<windows.h>
#include<vector>
#include<string>

#define WH_KEYBOARD_LL 13

typedef struct tagKBDLLHOOKSTRUCT {
	DWORD vkCode;
	DWORD scanCode;
	DWORD flags;
	DWORD time;
	DWORD dwExtraInfo;
} KBDLLHOOKSTRUCT, FAR *LPKBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT;

//標記界面和菜單項的ID
enum ID_ { ID_1=1, ID_2, ID_3, ID_4, ID_5, ID_6, ID_7 };

//標記初級,中級,高級三種遊戲等級
enum Rank_ { first=150, middle=100, high=50 };


//貪吃蛇結構
struct Snake_data{
    bool state ;                    //標記蛇狀態
    UINT Snake_size;                //標記蛇長度
    std::vector<COORD> Snake_coord; //蛇的當前坐標
    COORD food_coord;               //食物坐標
    UINT rank;                     //標記等級
    UINT mark;                      //分數
    UINT key;                       //記錄按鍵方向
    ID_ ID_interface;               //標記當前停留界面ID
    short ID_option ;               //標記被選中菜單的ID
    bool Flag;                      //標記刷新
};

//貪吃蛇類
class Snake_class{
public:
    Snake_class(){}
    Snake_class(Snake_data *data): pSnake(data){}
    void ShowMenu();            //顯示菜單
    void StartGame() ;          //開始遊戲
    void ShowPause();           //顯示暫停界面
    void SaveRecord();          //保存記錄
    void ShowRank();            //顯示等級
    void ShowRecord();          //顯示存檔記錄列表
    bool Read( size_t );        //讀取記錄
    void ShowArmory();          //顯示英雄榜
    void Die();                 //死亡界面
    size_t Create_file();       //存儲文件
private:
    void JudgeDie();            //判斷死亡
    bool Jesus();               //上榜判斷
    void ShowSnake( COORD& );   //顯示蛇
    void ShowPointer( COORD,std::string ); //顯示指針
    void Show_not();            //顯示無數據
    Snake_data *pSnake;
};



#endif



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值