C++【小游戏系列】贪吃蛇

叙述

文字游戏告一段落,想着可不可以绘制图像来实现游戏框架,在一段时间的百度中了解了点背景颜色的实现方式之后,于是乎就有了现在的图像游戏 < 贪吃蛇 >。但目前还不完善,身体增长后的绘制问题没有解决,so…只有一个蛇头在狂吃,但这给我的感觉是发现了一个新世界,绘制图像!这意味着我可以将想法可视化,或者模仿别人小游戏来实现趣味性,万事开头难,但迈下这一步之后就会从中寻找到自己的乐趣并深入其中,庆幸我没有放弃或者变心,接下来我会用同样的方法来制作一下小游戏,可能偶尔会试着学习OpenGL,虽然看不懂,但时间长着呢不是吗?

  • 游戏截图
    主页面
    设置
    游戏
  • 源码

感觉代码还是有点乱,想到怎么优化后再优化吧!

#include <windows.h>
#include <iostream>
#include <iomanip>
#include <conio.h>
#include <ctime>
using namespace std;
#define random( x ) rand ( ) % ( x )

HANDLE handle = GetStdHandle ( STD_OUTPUT_HANDLE );
COORD coord;
void SetPosition ( int x, int y ) { coord.X = x; coord.Y = y; SetConsoleCursorPosition ( handle, coord ); }

class Data {
    public:
        struct strRect { int x; int y; int width; int height; int color; };
        struct strButton { int x; int y; int width; int color; string text [ 2 ]; };
        struct strText { int x; int y; int color; string text; };
        struct strNumber { int x; int y; int color; int number; };
        struct strXY { int x; int y; };

        strButton button_start, button_set, button_exit, button_size, button_size_min,
                        button_level, button_level_n, button_level_h, button_level_vh, button_gameover;
        strRect area_main, area_play, area_score, area_option, area_attribute, area_size;
        strText text_pass, text_level, text_score, text_time, text_multiple, text_gametime;
        strNumber number_score, number_speed, number_pass;
        strXY xy_snake, xy_food [ 2 ];

        int id_window, id_button, id_snake, id_food;
        int isfood_score [ 2 ], isfood_random [ 2 ];

        Data ( ) {
            button_start = { 40, 10, 20, 0x8f, {"开始游戏","开  始  游  戏"} };
            button_set = { 40, 14, 20, 0x8f, { "设置", "设  置" } };
            button_exit = { 40, 18, 20, 0x8f, { "退出游戏", "退  出  游  戏" } };
            button_size = { 10, 5, 20, 0x8f, { "分辨率", "分  辨  率" } };
            button_size_min = { 30, 5, 60, 0x70, { "100 X 31", "100   X   31" } };
            button_level = { 10, 8, 20, 0x8f, { "游戏难度", "游  戏  难  度" } };
            button_level_n = { 30, 5, 60, 0x70, { "简单", "简  单" } };
            button_level_h = { 30, 8, 60, 0x70, { "困难", "困  难" } };
            button_level_vh = { 30, 11, 60, 0x70, { "地狱", "地  狱" } };
            button_gameover = { 10, 14, 56, 0xcf, { "GAME\tOVER", "\0" } };

            area_main = { 10, 0, 80, 31, 0xf0 };
            area_play = { 10, 0, 56, 31, 0x7f };
            area_score = { 66, 0, 24, 31, 0x8f };
            area_option = { 10, 0, 20, 31, 0x8f };
            area_attribute = { 30, 0, 60, 31, 0x7f };
            area_size = { 30, 8, 60, 6, 0x7f };

            text_pass = { 75, 2, 0x8f, "第 1 关" };
            text_level = { 68, 5, 0x8f, "游戏难度:简单" };
            text_score = { 68, 7, 0x8f, "得分:" };
            text_time = { 68, 15, 0x8f, "计时:" };
            text_multiple = { 68, 23, 0x8f, "倍率:" };
            text_gametime = { 68, 25, 0x8f, "游戏时间:" };

            number_score = { 75, 7, 0x8f, 0 };
            number_speed = { 75, 23, 0x8f, 1 };
            number_pass = { 78, 2, 0x8f, 1 };

            xy_snake = { 34, 15 };
            xy_food [ 0 ] = { 0 };
            xy_food [ 1 ] = { 0 };

            id_window = 1;
            id_button = 1;
            id_snake = 1;
            id_food = 1;

            isfood_random [ 0 ] = 0;
            isfood_random [ 1 ] = 0;
            isfood_score [ 0 ] = 0;
            isfood_score [ 1 ] = 0;
        }
};
class Draw : public Data {
    public:
        void Rectangle ( strRect& );
        void PrintText ( strText& );
        void PrintNumber ( strNumber& );
        void PrintButton ( strButton& );

        void Load ( );
        void WindowMain ( );
        void WindowPlay ( );
        void WindowSet ( );
        void SignalButton ( strButton& );
        void SnakePlay ( );
        void Food ( );
};
class Signal : public Draw {
    public:
        void SignalOn ( );
        void SignalW ( );
        void SignalS ( );
        void SignalA ( );
        void SignalD ( );
        void SignalEnd ( );
        void SignalEsc ( );
};
void Draw::Load ( ) {
    CONSOLE_CURSOR_INFO info = { 1, 0 };
    SetConsoleCursorInfo ( handle, &info );
    system ( "mode con cols=100 lines=31" );
    system ( "color f0" );
    SetConsoleTitle ( TEXT ( "贪吃蛇" ) );
    HWND hWnd = GetConsoleWindow ( );
    RECT rc;
    GetWindowRect ( hWnd, &rc );
    SetWindowLongPtr ( hWnd, GWL_STYLE, GetWindowLong ( hWnd, GWL_STYLE ) &
                                         ~WS_THICKFRAME & ~WS_MAXIMIZEBOX & ~WS_MINIMIZEBOX );
    SetWindowPos ( hWnd, NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, NULL );
    srand ( ( int ) time ( NULL ) );
    WindowMain ( );
}
void Draw::WindowMain ( ) {
    SignalButton ( button_start );
    PrintButton ( button_set );
    PrintButton ( button_exit );
}
void Draw::WindowPlay ( ) {
    Rectangle ( area_play );
    Rectangle ( area_score );
    PrintText ( text_pass );
    PrintText ( text_level );
    PrintText ( text_score );
    PrintText ( text_time );
    PrintText ( text_multiple );
    PrintText ( text_gametime );
    PrintNumber ( number_pass );
    PrintNumber ( number_score );
    PrintNumber ( number_speed );
    SnakePlay ( );
}
void Draw::WindowSet ( ) {
    Rectangle ( area_option );
    Rectangle ( area_attribute );
    SignalButton ( button_size );
    PrintButton ( button_level );
    PrintButton ( button_size_min );
}
void Draw::Rectangle ( strRect& rect ) {
    SetConsoleTextAttribute ( handle, rect.color );
    for (int i = 0; i < rect.height; i++ ) {
        SetPosition ( rect.x, ( rect.y + i ) );
        cout << setw ( rect.width ) << '\0';
    }
}
void Draw::PrintButton ( strButton& button ) {
    SetConsoleTextAttribute ( handle, button.color );
    for ( int i = 0; i < 3; i++ ){
        SetPosition ( button.x, ( button.y + i ) );
        cout << setw ( button.width ) << '\0';
    }
    SetPosition ( ( button.x + ( ( button.width - button.text [ 0 ].length ( ) ) / 2 ) ), ( button.y + 1 ) );
    cout << button.text [ 0 ];
}
void Draw::SignalButton ( strButton& button ) {
    SetConsoleTextAttribute ( handle, 0xcf );
    for (int i = 0; i < 3; i++ ) {
        SetPosition ( button.x, ( button.y + i ) );
        cout << setw ( button.width ) << '\0';
    }
    SetPosition ( ( button.x + ( ( button.width - button.text [ 1 ].length ( ) ) / 2 ) ), ( button.y + 1 ) );
    cout << button.text [ 1 ];
}
void Draw::PrintText ( strText& text ) {
    SetConsoleTextAttribute ( handle, text.color );
    SetPosition ( text.x, text.y );
    cout << text.text;
}
void Draw::PrintNumber ( strNumber& number ) {
    SetConsoleTextAttribute ( handle, number.color );
    SetPosition ( number.x, number.y );
    cout << number.number;
}
void Signal::SignalOn ( ) {
    switch ( getch ( ) ) {
        case 'w':SignalW ( );break;
        case 's':SignalS ( );break;
        case 'a':SignalA ( );break;
        case 'd':SignalD ( );break;
        case 13:SignalEnd ( );break;
        case 27:SignalEsc ( );break;
    }
}
void Signal::SignalW ( ) {
    switch ( id_button ) {
        case 2:SignalButton ( button_start );PrintButton ( button_set );id_button--;break;
        case 3:SignalButton ( button_set );PrintButton ( button_exit );id_button--;break;
        case 5:SignalButton ( button_size );PrintButton ( button_size_min );PrintButton ( button_level );
                    Rectangle ( area_size );id_button--;break;
        case 8:SignalButton ( button_level_n );PrintButton ( button_level_h );id_button--;break;
        case 9:SignalButton ( button_level_h );PrintButton ( button_level_vh );id_button--;break;
    }
}
void Signal::SignalS ( ) {
    switch ( id_button ) {
        case 1:SignalButton ( button_set );PrintButton ( button_start );id_button++;break;
        case 2:SignalButton ( button_exit );PrintButton ( button_set );id_button++;break;
        case 4:SignalButton ( button_level );PrintButton ( button_size );PrintButton ( button_level_n );
                    PrintButton ( button_level_h );PrintButton ( button_level_vh );id_button++;break;
        case 7:SignalButton ( button_level_h );PrintButton ( button_level_n );id_button++;break;
        case 8:SignalButton ( button_level_vh );PrintButton ( button_level_h );id_button++;break;
    }
}
void Signal::SignalA ( ) {
    switch ( id_button ) {
        case 6:SignalButton ( button_size );PrintButton ( button_size_min );id_button = 4;break;
        case 7:SignalButton ( button_level );PrintButton ( button_level_n );id_button = 5;break;
        case 8:SignalButton ( button_level );PrintButton ( button_level_h );id_button = 5;break;
        case 9:SignalButton ( button_level );PrintButton ( button_level_vh );id_button = 5;break;
    }
}
void Signal::SignalD ( ) {
    switch ( id_button ) {
        case 4:SignalButton ( button_size_min );PrintButton ( button_size );id_button = 6;break;
        case 5:SignalButton ( button_level_n );PrintButton ( button_level );id_button = 7;break;
    }
}
void Signal::SignalEnd ( ) {
    switch ( id_button ) {
        case 1:WindowPlay ( );id_button = 10;id_window = 2;break;
        case 2:WindowSet ( );id_button = 4;id_window = 3;break;
    }
}
void Signal::SignalEsc ( ) {
    switch ( id_window ) {
        case 2:Rectangle ( area_main );WindowMain ( );id_button = 1;id_window = 1;
                    id_food = 1;number_score.number = 0;number_pass.number = 1;number_speed.number = 1;break;
        case 3:Rectangle ( area_main );WindowMain ( );id_button = 1;id_window = 1;break;
    }
}
void Draw::SnakePlay ( ) {
    while ( 1 ) {
        SetConsoleTextAttribute ( handle, 0xc0 );
        SetPosition ( xy_snake.x, xy_snake.y );
        cout << setw ( 2 ) << '\0';
        Sleep ( 100 / number_speed.number );
        while ( kbhit ( ) == 1 ) {
            switch ( getch ( ) ) {
                case 'w':id_snake = 4;break;
                case 's':id_snake = 3;break;
                case 'a':id_snake = 2;break;
                case 'd':id_snake = 1;break;
            }
        }
        SetConsoleTextAttribute ( handle, 0x70 );
        SetPosition ( xy_snake.x, xy_snake.y );
        cout << setw ( 2 ) << '\0';
        switch ( id_snake ) {
            case 1:xy_snake.x += 2;break;
            case 2:xy_snake.x -= 2;break;
            case 3:xy_snake.y++;break;
            case 4:xy_snake.y--;break;
        }
        if ( xy_snake.x > ( ( area_play.x + area_play.width ) - 2 ) || xy_snake.x < area_play.x ||  xy_snake.y < area_play.y || 
                                        xy_snake.y > ( area_play.height - 1 ) ) {
            PrintButton ( button_gameover );
            xy_snake = { 34, 15 };
            break;
        }
        Food ( );
    }
}
void Draw::Food ( ) {
    while ( 1 ) {
        isfood_random [ 0 ] = random ( 64 );
        isfood_random [ 1 ] = random ( 64 );
        if ( ( isfood_random [ 0 ] % 2 ) != 0 ) {
            isfood_random [ 0 ]++;
        }
        if ( ( isfood_random [ 1 ] % 2 ) != 0 ) {
            isfood_random [ 1 ]++;
        }
        if ( isfood_random [ 0 ] > 10 && isfood_random [ 1 ] > 10 ) {
            break;
        }
    }
    if ( id_food != 0 ) {
        SetConsoleTextAttribute ( handle, 0xcf );
        for ( int i = 0; i < 2; i++ ) {
            xy_food [ i ] = { isfood_random [ i ], random ( 31 ) };
            SetPosition ( xy_food [ i ].x, xy_food [ i ].y );
            isfood_score [ i ] = random ( 100 );
            cout << setw ( 2 ) << isfood_score [ i ];
        }
        id_food = 0;
    }
    else if ( xy_food [ 0 ].x == xy_snake.x && xy_food [ 0 ].y == xy_snake.y ) {
        id_food = 1;
        number_score.number += isfood_score [ 0 ];
        SetConsoleTextAttribute ( handle, 0x70 );
        SetPosition ( xy_food [ 1 ].x, xy_food [ 1 ].y );
        cout << setw ( 2 ) << '\0';
        PrintNumber ( number_score );
    }
    else if ( xy_food [ 1 ].x == xy_snake.x && xy_food [ 1 ].y == xy_snake.y ) {
        id_food = 1;
        number_score.number += isfood_score [ 1 ];
        SetConsoleTextAttribute ( handle, 0x70 );
        SetPosition ( xy_food [ 0 ].x, xy_food [ 0 ].y );
        cout << setw ( 2 ) << '\0';
        PrintNumber ( number_score );
    }
    if ( ( number_score.number > 1000  && number_pass.number == 1 ) || 
          ( number_score.number > 2000 && number_pass.number == 2 ) ||
          ( number_score.number > 3000 && number_pass.number == 3 ) ) {
        number_pass.number++;
        number_speed.number ++;
        PrintNumber ( number_pass );
        PrintNumber ( number_speed );
    }
}
int main ( ) {
    Draw draw;
    Signal signal;

    draw.Load ( );
    while ( 1 ) {
        signal.SignalOn ( );
    }
    return 0;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值