1.1:為了按鈕做準備
按鈕是鼠標事件響應的象征,在PC游戲中起著十分重要的作用。這一章節,我們開始通過SDL提供的底層函數,自己來設計按鈕。
按鈕一般有這么幾種狀態:
out: 鼠標不在按鈕上;
over: 鼠標在按鈕上;
down: 鼠標按下了;
up: 鼠標松開了;
其中,down和up又可以細分為鼠標是在按鈕上按下松開的,還是在按鈕外按下松開的。
我們先從按鈕的表現形式——圖片來分析這些問題。
為了表現不同的狀態,我們需要多張圖片。至少的,out與over和down中的至少一張圖片應該是不一樣的,這樣才能給人以“按下了”的視覺效果。也就是說,如果我們構建按鈕類,這個類將會包含我們之前設計的SurfaceClass類。這樣,根據我們之前討論的一些C++細節問題,我們必須重新小心的設計SurfaceClass類。
1.2:為SurfaceClass設計基類
我們之前使用DisplaySurface本身作為TextSurface的基類,這是因為我們希望通過基類本身引用派生類,從而不需要為基類和派生類分別寫函數。同樣的,我們希望在ButtonClass中直接使用基類作為成員數據,這樣,ButtonClass可以不需要為派生類重新構建。在之前的DisplaySurface中,我們可以看到,大部分方法,比如最為重要的blit()方法,所涉及到的成員數據僅僅就是SDL_Surface* pSurface,這一點,TextSurface類也是一樣的。DisplaySurface類通過圖片創建pSurface,TextSurface類通過字庫創建pSurface,他們的創建條件不盡相同,TextSurface需要打開TTF_Init(),還需要打開字庫TTF_OpenFont(),所以,他們的構造函數與析構函數是不一樣的。一種更加清晰的關系,是建立起他們的基類,然后把他們的區別點分開處理,而不是之前采用的if來判斷處理。
最清晰的辦法,是把BaseSurface設計成為抽象基類(ABC),但是ABC的問題在于,無法創建ABC本身的對象,也就是說,我們需要在ButtonClass中包含的BaseSurface對象無法建立,所以,我們不能把BaseSurface設計成為ABC。我想到的辦法,是將BaseSurface的默認構造函數僅僅提供給派生類使用,也就是說,因為BaseClass的默認構造函數本身是不能建立起必要的數據的,比如pSurface和pScreen,我們暫時都用空指針代替。這里的思想其實還是ABC的,讓基類僅僅提供算法,即使算法所需要的元素還尚不存在。但是,只要這些元素存在了,BaseSurface也就可以完成這些算法,所以,我們把BaseSurface的復制構造函數設計為公共的,這很重要,這樣才為我們通過派生類去初始化基類的構造函數初始化列表提供了可能。
我們把基類命名為BaseSurface,之前的DisplaySurface我們用更形象的名稱代替,叫PictureSurface,然后TextSurface不改名。
1.3:如何深度復制SDL_Surface ?
因為PictureSurface和TextSurface的構造函數都涉及到了堆操作,也就是說,SDL_Surface是建立在堆上的。我們需要通過基類的復制構造函數復制SDL_Surface,必須找到合適的工具。具體來說,新對象的pSurface必須指像一個新建立起來的SDL_Surface對象,而非被復制的對象本身。
我最先想到的是用new...delete組合,但是失敗了。為什么呢?我們研究SDL_Surafce結構本身,發現在之中包含著一些其它的指針。比如SDL_PixelFormat *format和void *pixels。也就是說,SDL_Surface本身的構建也有堆操作,而且,因為SDL_Surafce是C風格的結構而不是類,它不能提供深度復制的操作,所以,即使我們用new為SDL_Surface申請了新空間,SDL_Surface本身也不會為format和pixels申請新的副本。當被釋放掉原本的時候,副本將尋找不到原本的format和pixels,從而產生錯誤。
我們另外能找到的可以深度復制SDL_Surface的函數,是:
SDL_Surface *SDL_DisplayFormat(SDL_Surface *surface);
SDL_Surface *SDL_ConvertSurface(SDL_Surface *src, SDL_PixelFormat *fmt, Uint32 flags);
這兩個函數貌似都是可行的。實際上,基本上也都是可行的。但是涉及到文字的時候,SDL_DisplayFormat將不能正確的轉換Blended和Shaded的文字,所以,最后只能使用SDL_ConvertSurafce()。新構建的SurfaceClass源代碼見:
http://www.shnenglu.com/lf426/archive/2008/04/14/47038.html