SDL入门教程(九):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();
}
我们在下节给出完整的代码以及一个用于演示的例子。  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SDL是Simple DirectMedia Layer(简易直控媒体层)的缩写。它是一个跨平台的多媒体库,以用于直接控制底层的多媒体硬件的接口。这些多媒体功能包括了音频、键盘和鼠标(事件)、游戏摇杆等。当然,最为重要的是提供了2D图形帧缓冲(framebuffer)的接口,以及为OpenGL与各种操作系统之间提供了统一的标准接口以实现3D图形。从这些属性我们可以看出,SDL基本上可以认为是为以电脑游戏为核心开发的多媒体库。 SDL支持主流的操作系统,包括Windows和Linux。在官方的介绍中,我们可以找到它所支持的其他平台。(SDL supports Linux, Windows, Windows CE, BeOS, MacOS, Mac OS X, FreeBSD, NetBSD, OpenBSD, BSD/OS, Solaris, IRIX, and QNX. )。SDL本身从C语言开发,并且能很好的在C++等高级语言中使用。在官方可以看到SDL所支持的语言很多。(Including Ada, C#, Eiffel, Erlang, Euphoria, Guile, Haskell, Java, Lisp, Lua, ML, Objective C, Pascal, Perl, PHP, Pike, Pliant, Python, Ruby, Smalltalk, and Tcl. ) SDL在GNU LGPL version 2下发布,这意味着你可以免费的使用。并且可以免费的用于商业软件的制作(只要你直接使用SDL的动态链接库,Windows下的SDL.dll)。如果你将SDL库编译进了自己的二进制代码中,你需要指明你所使用的SDL库的版本以及包括你自己修改的源代码,并说明这些代码的原始出处。这是很宽松的法律,你可以用如此强大的多媒体库完全合法的免费开发商业游戏。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值