HGE引擎提供一個基本的GUI控制項類,其不實現任何功能,但是提供一套虛函數和屬性供衍生類別使用。
開發人員可以在此基礎之上開發屬於自己的控制項,總的來說還是比較方便的。
我在開發自己的遊戲架構過程中,吸取了許多經驗教訓。
建議HGE引擎的使用者們不要直接在渲染過程中使用HGE提供的圖形函數,而應該將他們全部都封裝在GUI控制項衍生類別中,
這樣有幾大好處。
1. 更貼近物件導向,使得程式架構清晰;
2. 更好管理資源,使用和釋放都在同一個小模組中,即使規模擴大,也方便維護;
3. 易複用,我們可以整理一套統一的基類,然後逐步派生、組合實現我們需要的功能。
下面給出我在開發過程中自己使用的幾個方便的基類
/* * CopyRight 2009 - 2010 GDE工作室 * 遊戲UI系統 - HGE遊戲引擎控制項基類 * =================================== * 為了提高代碼的複用性,提供一些常用的功能作為基類,在構建基於HGE的GUI控制項時可以派生複用。 * * 2010/01/07 cg create */ #ifndef GDE_UI_BasicClasses_H_ #define GDE_UI_BasicClasses_H_ #include "../HGE/include/hge.h" #include "../HGE/include/hgesprite.h" #include "../HGE/include/hgefont.h" #include "../HGE/include/hgerect.h" #include "../HGE/include/hgegui.h" #include "../HGE/include/hgeguictrls.h" #include "../HGE/cn/GfxFont.h" #include "../HGE/cn/GfxEdit.h" #include <string> #include <string.h> #include <stdio.h> #include <stdlib.h> /****** 預設帶中文字型的基類 ******/ class GDE_BASIC_GUIChineseFont : public hgeGUIObject { public: GDE_BASIC_GUIChineseFont() { font = new GfxFont("宋體",20,TRUE,FALSE,FALSE);// 宋體,粗體,非斜體,非平滑 font->SetColor(0xFFFFFFFF); // 設定像素字型顏色,預設白色 } //fonttype 字型,size 文字大小 GDE_BASIC_GUIChineseFont( std::string fonttype , int size ) { font = new GfxFont(fonttype.c_str(),size,TRUE,FALSE,FALSE); font->SetColor(0xFFFFFFFF); } ~GDE_BASIC_GUIChineseFont() { if( font ) delete font; } //以某種顏色顯示一次,然後還原顏色 void FontPrintOnce( int x,int y, DWORD Color, std::string txt ) { DWORD oldcolor = font->GetColor(); font->SetColor( Color ); font->Print( x,y, txt.c_str() ); font->SetColor( oldcolor ); } protected: GfxFont* font;//中文字型指標 }; /****** 只用於顯示,不用於控制的基類 ******/ class GDE_BASIC_GUIViewOnly : public hgeGUIObject { public: GDE_BASIC_GUIViewOnly() { this->rect.Set( 0,0,0,0 );//這樣不會覆蓋其他GUI控制項的控制區 } }; /****** 感應滑鼠移動的基類 ******/ class GDE_BASIC_GUIMouseSensitive : public hgeGUIObject { public: GDE_BASIC_GUIMouseSensitive() : mx_ ( 0 ) , my_ ( 0 ) , is_mouse_over_ ( FALSE ) { } virtual ~GDE_BASIC_GUIMouseSensitive(){} virtual void MouseOver( bool bOver ) { is_mouse_over_ = bOver; } virtual bool MouseMove(float x, float y) { mx_ = x; my_ = y; return false; } protected: float mx_,my_; //當前滑鼠位置 bool is_mouse_over_; //滑鼠是否懸停 }; #endif
具體的一個執行個體,比如我的介面角色管理類
/* * CopyRight 2009 - 2010 GDE工作室 * 遊戲UI系統 - HGE GUI控制項 - 角色管理器 * =================================== * 提供角色的資源管理、角色圖片資訊管理等功能 * * 2010/01/07 cg create */ #ifndef GDE_UI_ROLE_MANAGER_H_ #define GDE_UI_ROLE_MANAGER_H_ #include "GDE_UI_BasicClasses.h" using namespace GDE; //角色渲染資料單元 struct RoleGuiUnit { RoleGuiUnit( int id , std::string filename , int px, int py ,HGE* pgHGE ) { role_id = id; img_filename = filename; x = px; y = py; pHGE = pgHGE; ////讀取圖片 tex = pHGE->Texture_Load( filename.c_str() ); //裝載紋理 w = pHGE->Texture_GetWidth( tex ); h = pHGE->Texture_GetHeight( tex ); spr = new hgeSprite( tex, 0, 0, w, h ); } ~RoleGuiUnit() { if( tex ) pHGE->Texture_Free( tex ); if( spr ) delete spr; } void SetAttackInfo( std::string txt ) { attackinfo = txt; attackinfo_show_count = 200; //此處和FPS相關 } int role_id; //角色ID std::string img_filename;//角色圖片檔案名稱 int x,y; //角色座標(絕對座標) Direction direct; //角色朝向 HTEXTURE tex; hgeSprite* spr; int w,h; //角色圖片寬高 HGE* pHGE; std::string attackinfo;//攻擊掉血數 int attackinfo_show_count; }; struct RoleGuiUnitAutoPtr { RoleGuiUnitAutoPtr( RoleGuiUnit* r ) { ptr = r; } ~RoleGuiUnitAutoPtr() { delete ptr; } RoleGuiUnit* GetPtr() { return ptr; } private: RoleGuiUnit* ptr; }; //人物角色管理器GUI class GDE_GUIRoleManager : public GDE_BASIC_GUIChineseFont { public: GDE_GUIRoleManager( int id , HGE* pgHGE ) : pHGE( pgHGE ) { this->id = id; this->rect.Set( 0,0,0,0 ); //該GUI控制項只用於顯示不用於輸入 } virtual ~GDE_GUIRoleManager() { for( int i = 0; i < roles_.size(); i++ ) { delete roles_[i]; } roles_.clear(); } //增加角色 void AddRole( int x, int y, int role_id, std::string filename ) { RoleGuiUnit* tmp = new RoleGuiUnit( role_id, filename, x, y, pHGE ); //RoleGuiUnitAutoPtr ptr( tmp ); roles_.push_back(tmp); } //移除角色 void RemoveRole( int role_id ) { std::vector<RoleGuiUnit*>::iterator iter; for(iter = roles_.begin(); iter != roles_.end(); ++iter ) { if( (*iter)->role_id == role_id ) { RoleGuiUnit* ptr = *iter; roles_.erase( iter ); delete ptr; return; } } } //設定人物位置 void SetPos( int role_id , int x, int y ) { std::vector<RoleGuiUnit*>::iterator iter; for(iter = roles_.begin(); iter != roles_.end(); ++iter ) { if( (*iter)->role_id == role_id ) { (*iter)->x = x; (*iter)->y = y; return; } } } //設定人物方向 void SetDirection( int role_id , Direction d ) { std::vector<RoleGuiUnit*>::iterator iter; for(iter = roles_.begin(); iter != roles_.end(); ++iter ) { if( (*iter)->role_id == role_id ) { (*iter)->direct = d; return; } } } //是否提示角色資訊 void RoleInfo( bool is_enable ) { info_enable = is_enable; } //處理角色掉血資訊 void AttackInfo( int role_id, std::string txt ) { int x,y; std::vector<RoleGuiUnit*>::iterator iter; for(iter = roles_.begin(); iter != roles_.end(); ++iter ) { if( (*iter)->role_id == role_id ) { (*iter)->SetAttackInfo( txt ); break; } } } //渲染所有角色 virtual void Render() { std::vector<RoleGuiUnit*>::iterator iter; for(iter = roles_.begin(); iter != roles_.end(); ++iter ) { if( (*iter)->spr ) { (*iter)->spr->RenderStretch( (*iter)->x, (*iter)->y, (*iter)->x + (*iter)->w, (*iter)->y + (*iter)->h ); } if( (*iter)->attackinfo_show_count > 0 ) { // TO DO 增加掉血值的alpha變化和位置變化,可以做的更絢 int x = (*iter)->x + 10; int y = (*iter)->y - 20; font->Print( x,y,(*iter)->attackinfo.c_str() ); (*iter)->attackinfo_show_count--; } } } //virtual bool MouseLButton(bool bDown); //virtual void MouseOver( bool bOver ); //virtual bool MouseMove(float x, float y); private: HGE* pHGE; /* by CG 2010-1-7 這個問題調了我半個小時~總結教訓中。。 此處容器模板成員使用指標的原因: vector模板成員RoleGuiUnit內涉及到無法複製的內容,如果不使用指標的話,在vector的push_back操作中會 出現run-time error,所以使用指標容器。 使用指標容器的時候需要注意,在erase或者clear其成員的時候,需要手動delete成員指標。(因為vector預設 在erase或者delete的時候調用該類的解構函式,若是指標,則無法釋放其指向的內容。 */ std::vector<RoleGuiUnit*> roles_; bool info_enable;//是否提示角色資訊 }; #endif