作者:龍飛
最近幾篇教程基本上都是參考著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();
}
我們在下節給出完整的代碼以及一個用于演示的例子。
posted on 2008-03-24 20:22
lf426 閱讀(3988)
評論(0) 編輯 收藏 引用 所屬分類:
SDL入門教程