支持HW团队,就支付宝领取下面的红包吧!(2018年3月31前,就几毛,也会几块,可以和其他红包叠加使用),你领取消费,HW有奖励。红包使用无条件限制,有条件请注意是不是有病毒。

小伙伴们,给大家发红包喽!人人可领,领完就能用。祝大家领取的红包金额大大大!#吱口令#长按复制此消息,打开支付宝就能领取!er1OEj73Uj

登入 注册 | 验证
| 搜索
HelloWorld论坛 : > 计算机科学、技术、教学> 编程专题> 开源免费项目> [转]SDL 文本
 
 
 
 
类别:游戏 阅读:3712 评论:0 时间:五月 12, 2013, 1:27 p.m. 关键字:SDL 文本

 

 来源:
http://www.cppblog.com/lf426/archive/2008/03/24/45302.html
http://www.cppblog.com/lf426/archive/2008/03/24/45304.html
http://www.cppblog.com/lf426/archive/2008/03/25/45336.html
http://www.cppblog.com/lf426/archive/2008/03/26/45459.html
http://www.cppblog.com/lf426/archive/2008/03/26/45461.html
作者:龙飞

1、在SDL图形窗口显示文本

最近几篇教程基本上都是参考着Lazy Foo的教程顺序来的。因为我也觉得他的顺序很实用。所不同的是,新的类型我都添加在了之前建立起来的surface类的基础之上。所以,如果你觉得单独看这些教程完全搞不明白,最好从头按照顺序来学习。另外,为了复习C++知识,也为了遵循C++的理念,我有意的将程序风格向C++靠拢。如果你更喜欢C风格,相信你在其他地方可以找到更适合你的教程。

1.1:一个小细节,SDL窗口的名称

因为涉及到文本的显示了,我们提一个一直以来忽略的问题——SDL建立起来的窗口的名字。因为我们所建立起来的Screen Surface是唯一和特殊的。所以窗口名字这个行为是可以绑定在这个唯一的Screen Surface对象上的。SDL中的相关函数是:

void SDL_WM_SetCaption(const char *title, const char *icon);

一般icon还暂时用不上,我们设置为空指针。我们修改一下Screen Surface的数据成员与构造函数。在数据成员里面添加一个windowName,并且修改构造函数

class ScreenSurface
{
private:
        //
        char* windowName;
public:
        //
        ScreenSurface(int w, int h, char* window_name = 0, int b = 0, Uint32 f = 0); 
};
ScreenSurface::ScreenSurface()
        : width(640), height(480), bpp(32), flags(0), windowName(0)
{
        if ( screenNum > 0 )
                throw ErrorInfo("DONOT create more than ONE screen!");
        if ( SDL_Init(SDL_INIT_VIDEO < 0 ) )
                throw ErrorInfo(SDL_GetError());
        pScreen = SDL_SetVideoMode(width, height, bpp, flags);
        screenNum++;
}

ScreenSurface::ScreenSurface(int w, int h, char* window_name, int b, Uint32 f)
        : width(w), height(h), bpp(b), flags(f)
{
        if ( screenNum > 0 )
                throw ErrorInfo("DONOT create more than ONE screen!");
        if ( SDL_Init(SDL_INIT_VIDEO < 0 ) )
                throw ErrorInfo(SDL_GetError());
        pScreen = SDL_SetVideoMode(width, height, bpp, flags);
        screenNum++;
        if ( window_name != 0 )
        {
                windowName = window_name;
                SDL_WM_SetCaption(windowName, 0);
        }
        else
                windowName = 0;
}

这样,我们在创建SceenSurface的时候,第三个参数如果指定,则可以用字符串表示窗口名称。

1.2:使用*.ttf文件

SDL使用*.ttf文件,仍然需要扩展库的支持。相关的下载和SDL_image的类似,大家可以参考前面的教程。下载地址如下:
http://www.libsdl.org/projects/SDL_ttf/
使用ttf扩展库的程序如下:
(1)装载扩展库:TTF_Init();
(2)打开字库:TTF_OpenFont(const char* ttf_fileName, int ttf_size);
(3)构建显示文本的surface:TTF_RenderText_Solid(TTF_Font* pFont, const char* message, SDL_Color textColor);
(4)显示(blit)文本surface;
(5)关闭字库:TTF_CloseFont();
(6)退出扩展库:TTF_Quit();
(7)释放显示文本的surface:SDL_FreeSurface();
我们考虑下这个TextSurface与之前的DisplaySurface之间的关系,希望通过类将二者有所联系。

1.3:构建TextSurface类

我们分析下TextSurface与DisplaySurface的关系:他们都依赖于一个ScreenSurface对象,至少具有两个一样的私有数据成员pSurface和pScreen;他们有一致的行为blit();他们的构造前提条件不同,析构做的“善后”也不一样。
我在水木社区的CPP版请教有这样关系的两个类应该是什么关系。有前辈指教说,一个类,用不同的flag加以区分。而我并不愿意多增加一个构造函数的参数,所以,我用构造函数的重载实现构造的不同;用继承类实现方法代码的重用;用继承类的析构函数为TextSurface类做额外的析构工作。
考虑到应在第一次建立TextSurface对象的时候装载ttf扩展库,并在最后一个对象使用完毕后关闭ttf扩展库,所以,在基类DisplaySurface中添加静态私有成员作为计数器,并添加相应的方法为派生类使用。这些方法,以及专门为派生类创建的基类构造函数,我们并不希望能被外部使用,所以,使用了关键字proteced。

class DisplaySurface
{
private:
        //
        //for TextSurafce
        static int textNum;
        TTF_Font* pFont;
public:
        //
protected:
        //for TextSurface
        DisplaySurface(const std::string& msg_name, const std::string& message, const ScreenSurface& screen,
                Uint8 r, Uint8 g, Uint8 b, 
                const std::string& ttf_fileName, int ttf_size);
        int tellTextNum() const;
        void reduceTextNum();
        void deleteFontPoint();
};

pFont是TextSurface会用到的私有数据,构造基类的时候,直接设置成空指针就可以了。
保护成员的实现如下:

//for TextSurface
DisplaySurface::DisplaySurface(const std::string& msg_name, const std::string& message, const ScreenSurface& screen,
        Uint8 r, Uint8 g , Uint8 b,
        const std::string& ttf_fileName, int ttf_size)
        : fileName(msg_name)
{
        if ( textNum == 0 )
                if ( TTF_Init() < 0 )
                        throw ErrorInfo("TTF_Init() failed!");

        SDL_Color textColor;
        textColor.r = r;
        textColor.g = g;
        textColor.b = b;

        pFont = TTF_OpenFont(ttf_fileName.c_str(), ttf_size);
        if ( pFont == 0 )
                throw ErrorInfo("TTF_OpenFont() failed!");

        pSurface = TTF_RenderText_Solid(pFont, message.c_str(), textColor);
        if ( pSurface == 0 )
                throw ErrorInfo("TTF_RenderText_solid() failed!");
        pScreen = screen.point();

        textNum++;
}

int DisplaySurface::tellTextNum() const
{
        return textNum;
}

void DisplaySurface::reduceTextNum()
{
        textNum--;
}

void DisplaySurface::deleteFontPoint()
{
        TTF_CloseFont(pFont);
}

有了这些数据成员和方法,我们可以构建TextSurface类了。

class TextSurface: public DisplaySurface
{
public:
        TextSurface(const std::string& msg_name, const std::string& message, const ScreenSurface& screen,
                Uint8 r = 0xFF, Uint8 g = 0xFF, Uint8 b = 0xFF,
                const std::string& ttf_fileName = "lazy.ttf", int ttf_size = 28);
        ~TextSurface();
};

可以看到,我们仅仅增添了派生类的构造函数和析构函数,实现如下:

//class TextSurface

TextSurface::TextSurface(const std::string& msg_name, const std::string& message, const ScreenSurface& screen,
        Uint8 r, Uint8 g, Uint8 b,
        const std::string& ttf_fileName, int ttf_size)
        : DisplaySurface(msg_name, message, screen, r, g, b, ttf_fileName, ttf_size)
{}

TextSurface::~TextSurface()
{
        deleteFontPoint();
        reduceTextNum();
        if ( tellTextNum() == 0 )
                TTF_Quit();
}

我们在下节给出完整的代码以及一个用于演示的例子。

2、显示文本的完整代码
注意:ttf字库文件,可以在
C:\WINDOWS\Fonts
下寻找,比如例子中用到的times.ttf;
lazy.ttf请到Lazy Foo的相关教程True Type Fonts后面的示例中获得。

//UVi Soft (2008)
//Long Fei (lf426), E-mail: zbln426@163.com

//FileName: SurfaceClass.h

#ifndef SURFACE_CLASS_H
#define SURFACE_CLASS_H

#include <iostream>
#include <string>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_ttf.h"

class ScreenSurface
{
private:
        static int screenNum;
        int width;
        int height;
        int bpp;
        Uint32 flags;
        SDL_Surface* pScreen;
        char* windowName;
public:
        ScreenSurface();
        ScreenSurface(int w, int h, char* window_name = 0, int b = 0, Uint32 f = 0);
        ~ScreenSurface();
        SDL_Surface* point() const;
        void flip() const;
        void fillColor(Uint8 r = 0, Uint8 g = 0, Uint8 b = 0) const;
};

class DisplaySurface
{
private:
        std::string fileName;
        SDL_Surface* pSurface;
        SDL_Surface* pScreen;
        //for TextSurafce
        static int textNum;
        TTF_Font* pFont;
public:
        DisplaySurface(const std::string& file_name, const ScreenSurface& screen);
        ~DisplaySurface();
        SDL_Surface* point() const;
        void blit() const;
        void blit(int at_x, int at_y) const;
        void blit(int at_x, int at_y,
                int from_x, int from_y, int w, int h,
                int delta_x = 0, int delta_y = 0) const;
        void colorKey(Uint8 r = 0, Uint8 g = 0xFF, Uint8 b = 0xFF, Uint32 flag = SDL_SRCCOLORKEY);
protected:
        //for TextSurface
        DisplaySurface(const std::string& msg_name, const std::string& message, const ScreenSurface& screen,
                Uint8 r, Uint8 g, Uint8 b,
                const std::string& ttf_fileName, int ttf_size);
        int tellTextNum() const;
        void reduceTextNum();
        void deleteFontPoint();
};

class TextSurface: public DisplaySurface
{
public:
        TextSurface(const std::string& msg_name, const std::string& message, const ScreenSurface& screen,
                Uint8 r = 0xFF, Uint8 g = 0xFF, Uint8 b = 0xFF,
                const std::string& ttf_fileName = "lazy.ttf", int ttf_size = 28);
        ~TextSurface();
};

class ErrorInfo
{
private:
        std::string info;
public:
        ErrorInfo():info("Unknown ERROR!")
        {}
        ErrorInfo(const char* c_str)
        {
                info = std::string(c_str);
        }
        ErrorInfo(const std::string& str):info(str)
        {}
        void show() const
        {
                std::cerr << info << std::endl;
        }
};

#endif
//UVi Soft (2008)
//Long Fei (lf426), E-mail: zbln426@163.com

#include "SurfaceClass.h"

//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
//class ScreenSurface

int ScreenSurface::screenNum = 0;

ScreenSurface::ScreenSurface()
        : width(640), height(480), bpp(32), flags(0), windowName(0)
{
        if ( screenNum > 0 )
                throw ErrorInfo("DONOT create more than ONE screen!");
        if ( SDL_Init(SDL_INIT_VIDEO < 0 ) )
                throw ErrorInfo(SDL_GetError());
        pScreen = SDL_SetVideoMode(width, height, bpp, flags);
        screenNum++;
}

ScreenSurface::ScreenSurface(int w, int h, char* window_name, int b, Uint32 f)
        : width(w), height(h), bpp(b), flags(f)
{
        if ( screenNum > 0 )
                throw ErrorInfo("DONOT create more than ONE screen!");
        if ( SDL_Init(SDL_INIT_VIDEO < 0 ) )
                throw ErrorInfo(SDL_GetError());
        pScreen = SDL_SetVideoMode(width, height, bpp, flags);
        screenNum++;
        if ( window_name != 0 ) {
                windowName = window_name;
                SDL_WM_SetCaption(windowName, 0);
        }
        else
                windowName = 0;
}

ScreenSurface::~ScreenSurface()
{
        SDL_Quit();
}

SDL_Surface* ScreenSurface::point() const
{
        return pScreen;
}

void ScreenSurface::flip() const
{
        if ( SDL_Flip(pScreen) < 0 )
                throw ErrorInfo(SDL_GetError());
}


void ScreenSurface::fillColor(Uint8 r, Uint8 g, Uint8 b) const
{
        if ( SDL_FillRect(pScreen, 0, SDL_MapRGB(pScreen->format, r, g, b)) < 0 )
                throw ErrorInfo(SDL_GetError());
}

//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
//class DisplaySurface

int DisplaySurface::textNum = 0;

DisplaySurface::DisplaySurface(const std::string& file_name, const ScreenSurface& screen)
        : fileName(file_name), pFont(0)
{
        SDL_Surface* pSurfaceTemp = IMG_Load(file_name.c_str());
        if ( pSurfaceTemp == 0 )
                throw ErrorInfo(SDL_GetError());
        pSurface = SDL_DisplayFormat(pSurfaceTemp);
        if ( pSurface == 0 )
                throw ErrorInfo(SDL_GetError());
        SDL_FreeSurface(pSurfaceTemp);
        pScreen = screen.point();
}

DisplaySurface::~DisplaySurface()
{
        SDL_FreeSurface(pSurface);
}

SDL_Surface* DisplaySurface::point() const
{
        return pSurface;
}

void DisplaySurface::blit() const
{
        if ( SDL_BlitSurface(pSurface, 0, pScreen, 0) < 0 )
                throw ErrorInfo(SDL_GetError());
}


void DisplaySurface::blit(int at_x, int at_y) const
{
        SDL_Rect offset;
        offset.x = at_x;
        offset.y = at_y;

        if ( SDL_BlitSurface(pSurface, 0, pScreen, &offset) < 0 )
                throw ErrorInfo(SDL_GetError());
}

void DisplaySurface::blit(int at_x, int at_y,
        int from_x, int from_y, int w, int h,
        int delta_x, int delta_y) const
{
        SDL_Rect offset;
        offset.x = at_x - delta_x;
        offset.y = at_y - delta_y;

        SDL_Rect dest;
        dest.x = from_x - delta_x;
        dest.y = from_y - delta_y;
        dest.w = w + delta_x*2;
        dest.h = h + delta_y*2;

        if ( SDL_BlitSurface(pSurface, &dest, pScreen, &offset) < 0 )
                throw ErrorInfo(SDL_GetError());
}

void DisplaySurface::colorKey(Uint8 r, Uint8 g, Uint8 b, Uint32 flag)
{
        Uint32 colorkey = SDL_MapRGB(pSurface->format, r, g, b);
        if ( SDL_SetColorKey(pSurface, flag, colorkey ) < 0 )
                throw ErrorInfo(SDL_GetError());
}

//for TextSurface
DisplaySurface::DisplaySurface(const std::string& msg_name, const std::string& message, const ScreenSurface& screen,
        Uint8 r, Uint8 g , Uint8 b,
        const std::string& ttf_fileName, int ttf_size)
        : fileName(msg_name)
{
        if ( textNum == 0 )
                if ( TTF_Init() < 0 )
                        throw ErrorInfo("TTF_Init() failed!");

        SDL_Color textColor;
        textColor.r = r;
        textColor.g = g;
        textColor.b = b;

        pFont = TTF_OpenFont(ttf_fileName.c_str(), ttf_size);
        if ( pFont == 0 )
                throw ErrorInfo("TTF_OpenFont() failed!");

        pSurface = TTF_RenderText_Solid(pFont, message.c_str(), textColor);
        if ( pSurface == 0 )
                throw ErrorInfo("TTF_RenderText_solid() failed!");
        pScreen = screen.point();

        textNum++;
}

int DisplaySurface::tellTextNum() const
{
        return textNum;
}

void DisplaySurface::reduceTextNum()
{
        textNum--;
}

void DisplaySurface::deleteFontPoint()
{
        TTF_CloseFont(pFont);
}

//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
//class TextSurface

TextSurface::TextSurface(const std::string& msg_name, const std::string& message, const ScreenSurface& screen,
        Uint8 r, Uint8 g, Uint8 b,
        const std::string& ttf_fileName, int ttf_size)
        : DisplaySurface(msg_name, message, screen, r, g, b, ttf_fileName, ttf_size)
{}

TextSurface::~TextSurface()
{
        deleteFontPoint();
        reduceTextNum();
        if ( tellTextNum() == 0 )
                TTF_Quit();
}

//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
#ifdef WIN32
#ifdef _DEBUG
#pragma comment (lib, "SDLd")
#pragma comment (lib, "SDLmaind")
#pragma comment (lib, "SDL_imaged")
#pragma comment (lib, "SDL_ttfd")
#else
#pragma comment (lib, "SDL")
#pragma comment (lib, "SDLmain")
#pragma comment (lib, "SDL_image")
#pragma comment (lib, "SDL_ttf")
#endif
#endif /* WIN32 */

//UVi Soft (2008)
//Long Fei (lf426), E-mail: zbln426@163.com

#include "SurfaceClass.h"

int game(int argc, char* argv[]);
int main(int argc ,char* argv[])
{
        int mainRtn = 0;
        try {
                mainRtn = game(argc, argv);
        }
        catch ( const ErrorInfo& info ) {
                info.show();
                return -1;
        }

        return mainRtn;
}

int game(int argc ,char* argv[])
{
        //Create a SDL screen.
        const int SCREEN_WIDTH = 640;
        const int SCREEN_HEIGHT = 480;
        ScreenSurface screen(SCREEN_WIDTH, SCREEN_HEIGHT, "Font");
        //Fill background with white.(default is black)
        screen.fillColor(0xFF, 0xFF, 0xFF);

        //Load a textSurface
        TextSurface myText("logo", "UVi Soft", screen, 0, 0, 0xFF, "times.ttf", 80);
        TextSurface lazy("lazy", "by lf426 (zbln426@163.com)", screen, 0xff, 0, 0);
        //Display text
        myText.blit(170, 180);
        lazy.blit(150,400);
        screen.flip();

        //press ESC or click X to quit.
        bool gameOver = false;
        SDL_Event gameEvent;
        while( gameOver == false ){
                while ( SDL_PollEvent(&gameEvent) != 0 ){
                        if ( gameEvent.type == SDL_QUIT ){
                                gameOver = true;
                        }
                        if ( gameEvent.type == SDL_KEYUP ){
                                if ( gameEvent.key.keysym.sym == SDLK_ESCAPE ){
                                        gameOver = true;
                                }
                        }
                }
        }

        return 0;
}

 我们有自己的配置约定,请看 [原]开发环境配置(boost log4cxx ACE SDL 等)

3、文本反馈“按键”信息
3.1:一些小的修改

我觉得写C++的程序,一是看起来确实比较C++一点,二是相对于C的“精炼”,C++要的是“健壮”。所以,其实我不太满意用C风格字符串作为ScreenSurface的成员数据,所以做了修改。这也是为了在程序中构建ScreenSurface对象的时候可以使用string。

class ScreenSurface
{
private:
        //
        std::string windowName;
public:
        //
        ScreenSurface(int w, int h, const std::string& window_name = "NULL", int b = 0, Uint32 f = 0);
};

相应的,我们修改了2个构造函数。

ScreenSurface::ScreenSurface()
        : width(640), height(480), bpp(32), flags(0), windowName("NULL")
{
        if ( screenNum > 0 )
                throw ErrorInfo("DONOT create more than ONE screen!");
        if ( SDL_Init(SDL_INIT_VIDEO < 0 ) )
                throw ErrorInfo(SDL_GetError());
        pScreen = SDL_SetVideoMode(width, height, bpp, flags);
        screenNum++;
}

ScreenSurface::ScreenSurface(int w, int h, const std::string& window_name, int b, Uint32 f)
        : width(w), height(h), bpp(b), flags(f)
{
        if ( screenNum > 0 )
                throw ErrorInfo("DONOT create more than ONE screen!");
        if ( SDL_Init(SDL_INIT_VIDEO < 0 ) )
                throw ErrorInfo(SDL_GetError());
        pScreen = SDL_SetVideoMode(width, height, bpp, flags);
        screenNum++;
        if ( window_name != "NULL" ) {
                windowName = window_name;
                SDL_WM_SetCaption(windowName.c_str(), 0);
        }
        else
                windowName = "NULL";
}

第二个地方,我修改了TextSurface构造函数的参数顺序,并且将默认的字体改为Windows都自带的“新罗马时代”字体times.ttf。我将字体参数放在最后,将字体大小参数提前了,这样更符合习惯上的使用规律。

class TextSurface: public DisplaySurface
{
public:
        TextSurface(const std::string& msg_name, const std::string& message, const ScreenSurface& screen,
                Uint8 r = 0xFF, Uint8 g = 0xFF, Uint8 b = 0xFF,
                int ttf_size = 28, const std::string& ttf_fileName = "times.ttf");
        ~TextSurface();
};

(在DisplaySurface里相应的构造函数也做类似的修改,略)

3.2:回顾SDL事件轮询

SDL_PollEvent()的作用,是事件一旦被触发,就会响应一次,注意它的响应并不是连续不断的。比如你按下某个键,即触发了一次事件。即使你按着不松开,也仅仅是触发了一次,所以SDL_PollEvent()也只响应一次。
下面的程序,演示键盘事件中,方向键被按下后的反馈信息。

3.3:演示程序

//UVi Soft (2008)
//Long Fei (lf426), E-mail: zbln426@163.com

#include "SurfaceClass.h"

int game(int argc, char* argv[]);
int main(int argc ,char* argv[])
{
        int mainRtn = 0;
        try {
                mainRtn = game(argc, argv);
        }
        catch ( const ErrorInfo& info ) {
                info.show();
                return -1;
        }

        return mainRtn;
}

int game(int argc ,char* argv[])
{
        //Create a SDL screen.
        const int SCREEN_WIDTH = 640;
        const int SCREEN_HEIGHT = 480;
        const std::string WINDOW_NAME = "Key Presses";
        ScreenSurface screen(SCREEN_WIDTH, SCREEN_HEIGHT, WINDOW_NAME);
        //Fill background.(default is black)
        screen.fillColor();
        screen.flip();

        //Load a textSurface
        TextSurface upMessage("upMsg", "Up was pressed.", screen);
        TextSurface downMessage("downMsg", "Down was pressed.", screen, 0xFF, 0, 0);
        TextSurface leftMessage("leftMsg", "Left was pressed.", screen, 0, 0xFF, 0);
        TextSurface rightMessage("rightMsg", "Right was pressed.", screen, 0, 0, 0xFF);
        TextSurface otherMessage("otherMsg", "Other key was pressed.", screen, 100, 100, 100, 35);

        //Main loop.Press ESC or click X to quit.
        bool gameOver = false;
        SDL_Event gameEvent;
        int x = 200;
        int y = 200;
        while( gameOver == false ){
                while ( SDL_PollEvent(&gameEvent) != 0 )
                {
                        if ( gameEvent.type == SDL_KEYDOWN )
                        {
                                screen.fillColor();
                                switch ( gameEvent.key.keysym.sym )
                                {
                                case SDLK_UP:
                                        upMessage.blit(x, y--);
                                        break;
                                case SDLK_DOWN:
                                        downMessage.blit(x, y++);
                                        break;
                                case SDLK_LEFT:
                                        leftMessage.blit(x--, y);
                                        break;
                                case SDLK_RIGHT:
                                        rightMessage.blit(x++, y);
                                        break;
                                default:
                                        otherMessage.blit(x, y);
                                }
                                screen.flip();
                        }
                        if ( gameEvent.type == SDL_QUIT ){
                                gameOver = true;
                        }
                        if ( gameEvent.type == SDL_KEYUP ){
                                if ( gameEvent.key.keysym.sym == SDLK_ESCAPE ){
                                        gameOver = true;
                                }
                        }
                }
        }

        return 0;
}

4、int转换为std::string
我下面考虑的问题,是用TextSurface反馈鼠标事件的信息。我想到的第一个例子,很自然就是反馈鼠标所在坐标的位置。这里涉及到一个基础的问题,即鼠标位置显然不是用字符串表示的。SDL给我们的反馈信息是int,我们需要用TextSurface将int构建成可以被blit到ScreenSurface上的面,需要做的第一件事情,是将int转换为string。
我的思路是这样的:首先找到int的数位数;然后依次从高位读取数字,之后将这个位去掉(通常减掉是最简单的);依次记录这些数字,转换成string,然后将这些数字“加”(字符串的合并)起来。
头文件如下:

//UVi Soft (2008)
//Long Fei (lf426), E-mail: zbln426@163.com

//FileName: int_to_string.h

#ifndef INT_TO_STRING_H_
#define INT_TO_STRING_H_

#include <iostream>
#include <string>
#include <vector>

int int_power(int base, int exp);
std::string int_to_string(int num);

#endif

其中,int_to_string()是我们需要构建的函数,int_power()是求一个数的整数幂的函数。这么简单的算法,我们就自己写吧。至于用到vector,按照我的思路,我们需要的数据结构显然应该是“队列”(先进先出)。不过真得感谢STL,用vector显然不是最优化的,但是肯定是最“通俗”的,因为即使是作为非专业的队列(或者栈),vector也已经为我们提供了必要的方法,比如推入(push_back)。
下面我就把程序说明夹在程序中间了。原因是本人英语太菜,简单描述还能忍,描述算法就有点不能忍了-_-!!!。另外,尽管我英语这水平,我还是希望程序里面别用中文注释的好。这种事情,您见过一次乱码,就总是得恶心一辈子。

//UVi Soft (2008)
//Long Fei (lf426), E-mail: zbln426@163.com

#include "int_to_string.h"

int int_power(int base, int exp)
{
        int result = 1;
        for (int i = exp; i > 0; i-- )
                result*=base;
        return result;
}

这是个很简单的求幂的算法。其实我们在程序中,只需要用到求10的n次幂,所以,实际上我们还可以写得更加有针对一点。

std::string int_to_string(int num)
{
        bool negative = false;
        if ( num < 0 )
        {
                negative = true;
                num = -num;
        }

这开始写转换函数了。首先我们判定int是否为负。如果是,我们把它变成其相反数,然后与正数一样转换,最后在前面加上“-”就OK了。

int bitNum = 1;
for ( int i = num; i > 9; i/=10 )
        bitNum++;

bitNum是这个int的数位数。比如3就是1位,1024就是4位。

std::vector<int> eachNum;
for ( int i = bitNum, temp = num; i > 0; i-- )
{
        int highBit = int(temp/int_power(10, (i-1)));
        eachNum.push_back(highBit);
        temp-=(highBit*int_power(10, (i-1)));
}

我们通过vector数组纪录每个数位上的数字,从高位到低位。需要说明的是,n位的数字是10的n-1次方幂。比如1024是4位,而1000是10的3次方幂。所以,我们这里用的是i-1而非i。

        std::string str;
        if ( negative == true )
                str = "-";
        for ( std::vector<int>::iterator pTemp = eachNum.begin(); pTemp != eachNum.end(); pTemp++ )
        {
                switch ( *pTemp ){
                case 0:
                        str+="0";
                        break;
                case 1:
                        str+="1";
                        break;
                case 2:
                        str+="2";
                        break;
                case 3:
                        str+="3";
                        break;
                case 4:
                        str+="4";
                        break;
                case 5:
                        str+="5";
                        break;
                case 6:
                        str+="6";
                        break;
                case 7:
                        str+="7";
                        break;
                case 8:
                        str+="8";
                        break;
                case 9:
                        str+="9";
                        break;
                default:
                        break;
                }
        }
        return str;
}

最后,我们用了STL的方法将每个数字转换成std::string的字符串,然后将这些字符串合并起来,作为函数的返回值。
我们在下一节中将用TextSurface演示这个函数的作用,以及实现我们在本节前面所提出的问题。

5、文本反馈鼠标位置坐标信息
注意事项:
1、times.ttf文件请到C:\WINDOWS\Fonts下寻找并拷贝到资源目录下。
2、如果您使用VC2008,请用Release编译。原因是,似乎涉及到vector的操作,Runtime Library在debug的时候必须用Multi-theaded Debug DLL (MDd),而Release时候才用Multi-theaded DLL (MD)。而我们亲爱的SDL必须始终用MD,所以,请Release吧。

这是一个检验TextSurface构造函数和析构函数的好例子。我们每一次的鼠标移动,都会导致一个新的TextSurface对象被建立,然后很快的又消亡。

源代码:

//UVi Soft (2008)
//Long Fei (lf426), E-mail: zbln426@163.com

#include "SurfaceClass.h"
#include "int_to_string.h"

int game(int argc, char* argv[]);
int main(int argc ,char* argv[])
{
        int mainRtn = 0;
        try
        {
                mainRtn = game(argc, argv);
        }
        catch ( const ErrorInfo& info )
        {
                info.show();
                return -1;
        }

        return mainRtn;
}

int game(int argc ,char* argv[])
{
        //Create a SDL screen.
        const int SCREEN_WIDTH = 640;
        const int SCREEN_HEIGHT = 480;
        const std::string WINDOW_NAME = "Mouse Motion";
        ScreenSurface screen(SCREEN_WIDTH, SCREEN_HEIGHT, WINDOW_NAME);
        //Fill background.(default is black)
        screen.fillColor();
        screen.flip();

        //Main loop.Press ESC or click X to quit.
        bool gameOver = false;
        SDL_Event gameEvent;
        int x;
        int y;
        while( gameOver == false )
        {
                while ( SDL_PollEvent(&gameEvent) != 0 )
                {
                        if ( gameEvent.type == SDL_MOUSEMOTION )
                        {
                                x = gameEvent.motion.x;
                                y = gameEvent.motion.y;
                                std::string mouse_at = "Mouse at: ";
                                mouse_at += ("x = " + int_to_string(x) + "; y = " + int_to_string(y) + ";");
                                TextSurface text("text", mouse_at, screen);
                                screen.fillColor();
                                text.blit();
                                screen.flip();
                        }
                        if ( gameEvent.type == SDL_QUIT ){
                                gameOver = true;
                        }
                        if ( gameEvent.type == SDL_KEYUP ){
                                if ( gameEvent.key.keysym.sym == SDLK_ESCAPE ){
                                        gameOver = true;
                                }
                        }
                }
        }

        return 0;
}

    例子里面的字体自带,加载字体要指定目录

文件名 大小 时间 会员 费用 操作
VS2010工程.rar(精华) 11M618K 五月 12, 2013, 6:17 p.m. 初学MPEG 积分:0
荣誉:0
会币:0
下载
 
 
[挂载人]初学MPEG [审核人]初学MPEG 推荐

个人签名--------------------------------------------------------------------------------

Please Login (or Sign Up) to leave a comment