SDL 实现五子棋 GUI (二)

来源:互联网 发布:网络舆论 社会影响 编辑:程序博客网 时间:2024/05/18 00:16
好了, 经过之前简单的介绍, 我们就开始做一个 SDL 下的五子棋 GUI 吧!

首先还是做一些简单的介绍(关于什么是 SDL, 上一篇已经给出官方网站):
在 SDL 中, 制作的思路就是创建出 GUI 所需要的各个组件(图层), 在呈现的时候从最下面的一层一次"贴"到屏幕上面, 用户就能看到一个完整的 GUI 界面了. 同时使用主循环和相应的函数接收消息并作出响应, 每次循环和一些操作之后都要更新界面.

由于 SDL 的原始语言是 C 语言, 在 C++ 中时候之前可以对其进行封装, 这样有利于以后的调用以及异常处理. 封装过程不再累述, 给出 SDL 教程地址, 有兴趣的人可以自行前往学习:
再别流年的技术实验室, http://www.cppblog.com/lf426/category/6107.html?Show=All
Lazy Foo' Productions, http://lazyfoo.net/SDL_tutorials/index.php

我的程序中使用的基本框架也来自于教程, 后来为了加强功能又添加了一些成员函数以及修改了部分细节和异常处理过程.

那么...我们开始 PS 素材吧!

在这里要说一下, 作者是 PS 小白, 一个简单的 GUI 素材用了一整晚的时间, 参考了一些 PS 图文教程, 不会画画确实比较困难.

首先, 我们需要准备一张棋板:


这里使用的是 560x560 像素, PS 网格间距 35 像素, 下载了个边框画笔.


之后我们 PS 一下程序的主界面, 800x600 像素:


其中棋盘左上角坐标(可以下子的区域为棋盘)为 (55, 55), 棋盘为 490x490 尺寸, 一个格子 35 像素. 特别地, 在 SDL 中坐标原点在窗体内部左上角, x 轴水平向右, y 轴竖直向下. 那些坐标信息以后会用到.


还缺什么呢? 棋子! 于是 PS 出这俩货


其中的高光弄得很郁闷, 毫无绘画功底, 更不懂高光.


现在基本齐全了, 不过...每下一盘棋以后还要关闭程序再运行? 好吧, 我们再弄出个 Start/Restart 按钮.

正常时候

鼠标经过

按下


现在素材就准备好了. 在面对枯燥的(我倒觉得蛮有意思)代码之前, 给出一张样品图



注: 本文只给出了 GUI 的实现部分, 不包括程序的 AI 和功能性逻辑结构. 及在目前的 GUI 中, 不能判断玩家是否胜利, 在同一个格子上也可以下两次及以上的棋. 在下一篇日志中我将给出一个可能的加入 AI 借口以后的代码. 至于 AI 怎么实现, 网上文献很多, 就不再讨论了(其实是自己的 AI 很渣, 羞愧).

注2: 要在 windows 下配置编译环境, 可以参考教程, 我会给出在 windows 下通过 Code::Blocks 配置的一篇简单文章.


然后开始写代码, 在这里我先给出界面实现的代码, 然后附带给出个各类的定义. 至于这些类怎么来的, 具体实现是什么, 代码量不小, 改写自教程. 完整的源代码及图片我打包以后放在下载里面, 免费下载学习哈(不知道要不要注册). 给出的文件中, /bin/release 下是一个已经编译好的版本.

void SDLGUI::startGame(){    //constant value    const int SCREEN_WIDTH = 800;    const int SCREEN_HEIGHT = 600;    const int BIT_DEPTH = 32;    const Uint32 FLAG = SDL_DOUBLEBUF | SDL_HWSURFACE;    const int BOARD_Top = 55;//pixel    const int BOARD_Left = 55;//pixel    const int BOARD_WIDTH = 490;    const int BOARD_HEIGHT = 490;    const int PIXEL_PER_GRID = 35;    const int BUTTON_X = 605;    const int BUTTON_Y = 510;    const int BLACK_ICON_X = 600;    const int BLACK_ICON_Y = 180;    const int WHITE_ICON_X = 600;    const int WHITE_ICON_Y = 240;    const int TEXT_BLACK_X = 660;    const int TEXT_BLACK_Y = 177;    const int TEXT_WHITE_X = 660;    const int TEXT_WHITE_Y = 237;    #ifdef __windows__    SDL_putenv("SDL_VIDEODRIVER=directx");    #endif    #ifdef __linux__    SDL_putenv("SDL_VIDEODRIVER=dga");    #endif    bool isQuit = false;    bool isBlackTurn = true; // Alternate each round    int row = 0;    int col = 0;    ScreenSurface screen(SCREEN_WIDTH, SCREEN_HEIGHT, BIT_DEPTH, FLAG, "MySDL");    PictureSurface backSurface("board.jpg", screen);    PictureSurface blackStone("black.png", screen, true);    PictureSurface whiteStone("white.png", screen, true);    ButtonPlus button("button.png", "button_over.png", "button_press.png", screen, true);    TextSurface txtBlackStone(int2string(0), screen, "verdana.ttf", 30, 0x00, 0x00, 0x00);    TextSurface txtWhiteStone(int2string(0), screen, "verdana.ttf", 30, 0x00, 0x00, 0x00);    //set back ground image    backSurface.blit();    //set start button    button.setBtnRegion(BUTTON_X, BUTTON_Y);    button.blitOut();    //set stone counter icon and text    blackStone.blit(BLACK_ICON_X, BLACK_ICON_Y);    whiteStone.blit(WHITE_ICON_X, WHITE_ICON_Y);    txtBlackStone.blit(TEXT_BLACK_X, TEXT_BLACK_Y);    txtWhiteStone.blit(TEXT_WHITE_X, TEXT_WHITE_Y);    screen.flip();    while (!isQuit){        //press ESC or click X to quit        SDL_Event gameEvent;        while(SDL_PollEvent(&gameEvent) != 0){            if (gameEvent.type == SDL_QUIT){                isQuit = true;            }            if (gameEvent.type == SDL_KEYUP){                if (gameEvent.key.keysym.sym == SDLK_ESCAPE){                    isQuit = true;                }            }            //lay down a stone            if (gameEvent.type == SDL_MOUSEBUTTONDOWN){                if (gameEvent.button.y >= BOARD_Top && gameEvent.button.y <= BOARD_Top + BOARD_HEIGHT                    && gameEvent.button.x >= BOARD_Left && gameEvent.button.x <= BOARD_Left + BOARD_WIDTH){                        row = (gameEvent.button.y - BOARD_Top) / PIXEL_PER_GRID;                        col = (gameEvent.button.x - BOARD_Left) / PIXEL_PER_GRID;                        //if the mouse position exceeds row+0.5                        if ((gameEvent.button.y - BOARD_Top) % PIXEL_PER_GRID > (PIXEL_PER_GRID / 2)){                            row++;                        }                        //if the mouse position exceeds col+0.5 GRID                        if ((gameEvent.button.x - BOARD_Left) % PIXEL_PER_GRID > (PIXEL_PER_GRID / 2)){                            col++;                        }                        //lay down a stone                        if (isBlackTurn){                            isBlackTurn = !isBlackTurn;                            blackStone.blit(BOARD_Left + col * PIXEL_PER_GRID - PIXEL_PER_GRID / 2,                                    BOARD_Top + row * PIXEL_PER_GRID - PIXEL_PER_GRID / 2);                            //API BOARD board.counter_black                            txtBlackStone.setMessage(int2string(string2int(txtBlackStone.getMessage()) + 1));                            backSurface.blit(TEXT_BLACK_X, TEXT_BLACK_Y, TEXT_BLACK_X, TEXT_BLACK_Y, txtBlackStone.getWidth(), txtBlackStone.getHeight());                            txtBlackStone.blit(TEXT_BLACK_X, TEXT_BLACK_Y);                        }                        else{                            //white player's turn                            isBlackTurn = !isBlackTurn;                            whiteStone.blit(BOARD_Left + col * PIXEL_PER_GRID - PIXEL_PER_GRID / 2,                                    BOARD_Top + row * PIXEL_PER_GRID - PIXEL_PER_GRID / 2);                            //API BOARD board.counter_white                            txtWhiteStone.setMessage(int2string(string2int(txtWhiteStone.getMessage()) + 1));                            backSurface.blit(TEXT_WHITE_X, TEXT_WHITE_Y, TEXT_WHITE_X, TEXT_WHITE_Y, txtWhiteStone.getWidth(), txtWhiteStone.getHeight());                            txtWhiteStone.blit(TEXT_WHITE_X, TEXT_WHITE_Y);                        }                }//if in board            }//if mouse down            //change button's look            if (button.mouseOver(gameEvent) == true){                button.blitOver();            }            else if (button.mouseDown(gameEvent) == true){                button.blitDown();            }            else{                button.blitOut();            }            //if game start btn is pressed            if (button.effectiveClick(gameEvent) == true){                //reset the game                backSurface.blit();                button.blitOut();                txtBlackStone.setMessage("0");                txtWhiteStone.setMessage("0");                //set stone counter icon and text                blackStone.blit(BLACK_ICON_X, BLACK_ICON_Y);                whiteStone.blit(WHITE_ICON_X, WHITE_ICON_Y);                txtBlackStone.blit(TEXT_BLACK_X, TEXT_BLACK_Y);                txtWhiteStone.blit(TEXT_WHITE_X, TEXT_WHITE_Y);            }            screen.flip();        }//while        SDL_Delay(10);    }//main loop    return;}


以下是 GUI 类的定义:
#include "main.h"#include "surfaceClass.h"#include "buttonClass.h"#include "sdlFont.h"#ifndef SDLGUI_H#define SDLGUI_Hclass SDLGUI{    private:        std::string int2string(int n);        int string2int(std::string str);    public:        void startGame();};#endif



以下是 Surface 类的定义:

/**This file defines the GUI of game wuzi.And all code are based on SDL library.Classes are designed based on Long Fei's tutorialhttp://www.cppblog.com/lf426/*/#include"main.h"#ifdef __windows__//sdlFont.h include chinese rendering functions#include "sdlFont.h"#endif#ifndef SURFACECLASS_H#define SURFACECLASS_H//===============================//class ScreenSurface//===============================class ScreenSurface{    private:        static int counter_screen;//ensure there is only one screen surface each progress        int width;        int height;        int bitDepth;        Uint32 flags;        SDL_Surface* pScreen;        std::string windowCaption;    public:        ScreenSurface(std::string caption="");        ScreenSurface(int w, int h, int dep=8, Uint32 f=0, std::string caption="");        ~ScreenSurface();        SDL_Surface* getPointer() const;        void flip() const;//flip to dispaly on the screen        void fillColor(Uint8 r=0x0, Uint8 g=0x0, Uint8 b=0x0) const;        int getWeight() const{return width;}        int getHeight() const{return height;}        int getBitDepth() const{return bitDepth;}        Uint32 getFlags() const{return flags;}};//===============================//class BaseSurface//===============================class BaseSurface{    private:        //    protected:        SDL_Surface* pScreen;        SDL_Surface* pSurface;        BaseSurface();    public:        BaseSurface(const BaseSurface& copy);        virtual ~BaseSurface();        BaseSurface& operator=(const BaseSurface& copy);        //surface's pointer        SDL_Surface* getPointer() const;        //blit surface to screen        void blit() const;        void blit(int any_num) const;// blit the whole source to destination        void blit(int atDstX, int atDstY) const;        void blit(int atDstX, int atDstY, int fromSrcX, int fromSrcY, int width, int height, int deltaX=0, int deltaY=0) const;        //blit surface to other surface        void blit(const BaseSurface& dstSurface) const;        void blit(const BaseSurface& dstSurface, int any_num) const;// blit the whole source to destination        void blit(const BaseSurface& dstSurface, int atDstX, int atDstY) const;        void blit(const BaseSurface& dstSurface, int atDstX, int atDstY, int fromSrcX, int fromSrcY, int width, int height, int deltaX=2, int deltaY=2) const;        //set transparent color        void colorKey(Uint8 r, Uint8 g, Uint8 b, Uint32 flag=SDL_SRCCOLORKEY);        int getWidth() const{return pSurface->w;}        int getHeight() const{return pSurface->h;}};//====================================//class PictureSurface//====================================class PictureSurface: public BaseSurface{    private:        std::string fileName;    public:        PictureSurface(std::string file_name, const ScreenSurface& screen, bool alpha = false);};//==================================================//class TextSurface, derived from class DisplaySurface//==================================================class TextSurface: public BaseSurface{    private:        static int counter_textSurface;    // release or QuitTTF lib when equals 0        std::string message;        //the text to show        std::string TTF_fileName;        //the file name of .ttf        int TTF_size;            //font size        Uint8 r, g, b;            //font color    public:        TextSurface(const std::string& _message, const ScreenSurface& screen,            const std::string& ttf_fileName, int ttf_size=12,            Uint8 _r=0xFF, Uint8 _g=0xFF, Uint8 _b=0xFF);        TextSurface(const TextSurface& copy);        ~TextSurface();        //text tools        void toBlended();                    //render text in blended mode        void toSolid();                        //render text in solid mode        void toShaded(Uint8 _r, Uint8 _g, Uint8 _b);        //render text in shaded mode,                                    //(_r, _g, _b) is the color of shade        void setColor(Uint8 _r, Uint8 _g, Uint8 _b);        //set font color        void setSize(int ttf_size);                //set font size        void setFont(const std::string& ttf_fileName);        //set font        void setMessage(const std::string& _message);        std::string getMessage();};#endif

以下是 SDLFONT 类的定义:
/**This file defines the class and functions tomake it possible use Chinese in SDL.Refers to http://fribidi.freedesktop.org/wikifribidi_char_sets_utf8.cSDL Tutorial written by Long Fei http://www.cppblog.com/lf426/*/#include "main.h"#include "iconv.h"#ifndef SDLFONT_H#define SDLFONT_H//returns the Unicode of each character in strstd::vector<Uint16> getUnicode(const std::string& str);//function UTF8toUNICODEint utf8toUnicode(Uint16* unicode, unsigned char* utf8, int len);//font rendering functionsSDL_Surface*     chsTTF_RenderString_Blended(TTF_Font* font, const std::string& str, SDL_Color fg);SDL_Surface*     chsTTF_RenderString_Solid(TTF_Font* font, const std::string& str, SDL_Color fg);SDL_Surface*     chsTTF_RenderString_Shaded(TTF_Font* font, const std::string& str, SDL_Color fg, SDL_Color bg);#endif



以下是 BUTTON 类的定义:

/**This file defines the button class.Original source:Long Fei ( lf426 ), E-mail: zbln426@163.comLaboratory of ZaiBieLiunNianhttp://www.cppblog.com/lf426/modified by Shadow*/#include "surfaceClass.h"#ifndef BUTTONCLASS_H#define BUTTONCLASS_Hclass BaseButton{    private:        //    protected:        int atX;    //the left-top location of the button,        int atY;    //and is also the valid press region        int offset;    //used in the button skin blit()        int w;        //button width        int h;        //button height        //Mouse state        bool inBox;        //mouse pointer is in the btn region        bool clickDown;    //mouse click down        bool clickUp;    //release mouse    public:        BaseButton();        virtual ~BaseButton();        void setBtnRegion(int at_x, int at_y, int _offset = 0);        //set valid press region of the button        virtual void colorKey(Uint8 r, Uint8 g, Uint8 b) = 0;        //set the transparent color of the button image        virtual void blitOut() const = 0;                //blit picture when mouse is out of button        virtual void blitOver() const = 0;                //blit picture when mouse moves over the button        virtual void blitDown() const = 0;                //blit picture when press the button        virtual void addText(const TextSurface& out_text,        //attach the text                const TextSurface& over_text) = 0;        //to the btn surface        bool mouseOver(const SDL_Event& gameEvent) const;        bool mouseDown(const SDL_Event& gameEvent) const;        bool mouseUp(const SDL_Event& gameEvent) const;            //release the mouse in the btn region        bool mouseUpOutside(const SDL_Event& gameEvent) const;        //release the mouse outside the region        bool effectiveClick(const SDL_Event& game_event);        //check if click is valid, also is the main API of button class};class Button: public BaseButton{    private:        //    protected:        BaseSurface outImg;        BaseSurface overImg;    public:        Button(const std::string& outImg_fileName, const std::string& overImg_fileName, const ScreenSurface& screen, bool alpha = false);        Button(const BaseSurface& out_img, const BaseSurface& over_img);        Button(const std::string buttonText, const ScreenSurface& screen,        Uint8 out_r = 0xFF, Uint8 out_g = 0xFF, Uint8 out_b = 0xFF, Uint8 on_r = 0, Uint8 on_g = 0, Uint8 on_b = 0xFF,        int ttf_size = 28, const std::string& ttf_fileName = "./verdana.ttf");        virtual ~Button();        virtual void colorKey(Uint8 r = 0, Uint8 g = 0xFF, Uint8 b = 0xFF);        virtual void blitOut() const;        virtual void blitOver() const;        virtual void blitDown() const;        virtual void addText(const TextSurface& out_text, const TextSurface& over_text);};class ButtonPlus: public Button{    private:        BaseSurface downImg;    public:        ButtonPlus(const std::string& outImg_fileName, const std::string& overImg_fileName, const std::string& downImg_fileName,            const ScreenSurface& screen, bool alpha = false);        ButtonPlus(const BaseSurface& out_img, const BaseSurface& over_img, const BaseSurface& down_img);        virtual void colorKey(Uint8 r = 0, Uint8 g = 0xFF, Uint8 b = 0xFF);        virtual void blitDown() const;        virtual void addText(const TextSurface& out_text, const TextSurface& over_text);};class SpriteButton: public BaseButton{    private:        PictureSurface spriteSheet;        int outX;        int outY;        int overX;        int overY;        int downX;        int downY;    public:        SpriteButton(const std::string& spriteSheet_fileName, const ScreenSurface& screen,        int button_w, int button_h,        int out_x, int out_y, int over_x, int over_y, int down_x, int down_y);        virtual void colorKey(Uint8 r = 0, Uint8 g = 0xFF, Uint8 b = 0xFF);        virtual void blitOut() const;        virtual void blitOver() const;        virtual void blitDown() const;        virtual void addText(const TextSurface& out_text, const TextSurface& over_text);};#endif

原创粉丝点击