首先,我說說對C++的最直觀的感受吧!熟悉了.net 智能提示,開始一開始發現C++根本沒有提示了。後來google了一下,下載了一個visual assist 這個插件,比vs自動提示強多了。 然後,就是習慣了在.net中,把所有的聲明和方法實現寫在同一文件中。可是C++不是這麼回事。 他一個聲明在頭文件中,實現 在源文件中,說實在話,一開始並怎麼習慣。後來漸漸就習慣了。然後,寫C++的文件就是真他媽的痛苦,他不比.net,微軟已經比你封裝好了,在C++中,好多東西需要自己寫。 首先,一個析構函數,需要自己釋放資源。而.net有一個gc自動進行垃圾回收,資源釋不釋放,關你鳥事。沒辦法,只有自己釋放.做一個遵守規則的好程序員。這是我對C++最直觀感受。
言歸正卷,說一說這個超級瑪麗的游戲。 先看看,我對游戲的類結構的分類,如果有不妥的地方,懇請大家指正。
從層次結構來看,分成這幾個層①圖像層,②邏輯層,③結構和表。
圖像層包括①圖像基類MYBITMAP,②游戲背景MYBKSKYàMYBITMAP,③游戲圖片MYANIOBJàMYBITMAP,④魔法攻擊MYANIMAGICàMYBITMA.
邏輯層包括①游戲邏輯GAMEMAP,②時鐘處理MYCLOCK,③字體處理MYFONT,④跟蹤打印FILEREPORT,⑥玩家控制MYROLEàMYBITMAP。
結構和表包括①精靈結構ROLE,②物品結構MapObject,③地圖信息表MAPINFO。
那每個類的結構又是那麼樣子的,是騾子還是馬拉出來溜溜。我們在往下看一看。
圖像層的結構就這樣簡單,邏輯層只需要確定“哪個圖像,哪一幀”這兩個參數,就能在屏幕上繪制出所有圖片。
說一說一個圖片的基類。他的源代碼的架構又是這個樣子的。
今天先講最基礎的圖像類 MYBITMAP:
成員函數功能列表:
代碼如下:
//功能 根據一個位圖文件,初始化圖像
//入參 應用程序實例句柄 資源ID 橫向位圖個數 縱向位圖個數
void Init(HINSTANCE hInstance,int iResource,int row,int col);
//功能 設置環境信息
//入參 目的DC(要繪制圖像的DC),臨時DC,要繪制區域的寬 高
void SetDevice(HDC hdest,HDC hsrc,int wwin,int hwin);--媽的,C++中畫圖需要一個hdc,設備上下文需要是一種包含有關某個設備(如顯示器或打印機)的繪制屬性信息的 Windows 數據結構。所有繪制調用都通過設備上下文對象進行,這些對象封裝了用於繪制線條、形狀和文本的 Windows API。設備上下文允許在 Windows 中進行與設備無關的繪制。設備上下文可用於繪制到屏幕、打印機或者圖元文件。.net不需要了這個 上下文對象,他有了一個.netframework 就不需要這個屁玩意了。
//功能 設置圖片位置1
//入參 設置方法 橫縱坐標
void SetPos(int istyle,int x,int y);
//功能 圖片顯示
//入參 圖片顯示方式
void Draw(DWORD dwRop);
//功能 圖片縮放顯示
//入參 橫縱方向縮放比例
void Stretch(int x,int y);
//功能 圖片縮放顯示
//入參 橫縱方向縮放比例 縮放圖像ID(縱向第幾個)
void Stretch(int x,int y,int id);
//功能 在指定位置顯示圖片
//入參 橫縱坐標
void Show(int x,int y);
//功能 橫向居中顯示圖片
//入參 縱坐標
void ShowCenter(int y);
//功能 將某個圖片平鋪在一個區域內
//入參 左上右下邊界的坐標 圖片ID(橫向第幾個)
void ShowLoop(int left,int top,int right,int bottom,int iframe);
//功能 不規則圖片顯示
//入參 橫縱坐標 圖片ID(橫向第幾個)
void ShowNoBack(int x,int y,int iFrame);
//功能 不規則圖片橫向平鋪
//入參 橫縱坐標 圖片ID(橫向第幾個) 平鋪個數
void ShowNoBackLoop(int x,int y,int iFrame,int iNum);
//動畫播放
//功能 自動播放該圖片的所有幀,函數沒有實現,但以後肯定要用:)
//入參 無
void ShowAni();
//功能 設置動畫坐標
//入參 橫縱坐標
void SetAni(int x,int y);
成員數據
//跟蹤打印類
// FILEREPORT f;
//圖像句柄
HBITMAP hBm;
//按照行列平均分成幾個
int inum;
int jnum;
//按行列分割後,每個圖片的寬高(顯然各個圖片大小一致,派生後,這裡的寬高已沒有使用意義)
int width;
int height;
//屏幕寬高
int screenwidth;
int screenheight;
//要繪制圖片的dc
HDC hdcdest;
//用來選擇圖片的臨時dc
HDC hdcsrc;
//當前位置
int xpos;
int ypos;
//是否處於動畫播放中(功能沒有實現)
int iStartAni;
這個基類的部分函數和變量,在這個游戲中沒有使用,是從前幾個游戲中保留下來的,所以看起來有些零亂.這個游戲的主要圖像功能,由它的派生類完成.由於基類封裝了物理層信息(dc和句柄),派生類的編寫就容易一些,可以讓我專注於邏輯含義.
基類的函數實現上,很簡單,主要是以下幾點:
1.圖片初始化:
代碼如下:
//根據程序實例句柄,位圖文件的資源ID,導入該位圖,得到位圖句柄
hBm=LoadBitmap(hInstance,MAKEINTRESOURCE(iResource));
//獲取該位圖文件的相關信息
GetObject(hBm,sizeof(BITMAP),&bm);
//根據橫縱方向的圖片個數,計算出每個圖片的寬高(對於超級瑪麗,寬高信息由派生類處理)
width=bm.bmWidth/inum;
height=bm.bmHeight/jnum;
下面再來說一說 游戲背景 類MYBKSKY
類說明:這是一個專門處理游戲背景的類。在橫版游戲或射擊游戲中,都有一個背景畫面,如山、天空、雲、星空等等。這些圖片一般只有1到2倍屏幕寬度,然後像一個卷軸一樣循環移動,連成一片,感覺上像一張很長的圖片。這個類就是專門處理這個背景的。在超級瑪麗增強版中,主要關卡是3關,各有一張背景圖片;從水管進去,有兩關,都用一張全黑圖片。共四張圖。這四張圖大小一致,縱向排列在一個位圖文件中。MYBKSKY這個類,派生於MYBITMAP。由於背景圖片只需要完成循環移動的效果,只需要實現一個功能,而無需關心其他任何問題(例如句柄、dc)。編碼起來很簡單,再次反映出面向對象的好處。
實現的原理:
怎樣讓一張圖片像卷軸一樣不停移動呢?很簡單,假設有一條垂直分割線,把圖片分成左右兩部分。先顯示右邊部分,再把左邊部分接到圖片末尾。不停移動向右移動分割線,圖片就會循環地顯示。
成員函數功能列表:
代碼如下:
class MYBKSKY:public MYBITMAP
{
public:
MYBKSKY();
~MYBKSKY();--析構函數,怎麼樣 C++中,你有了資源 自己釋放。我們.net 有一個終結者函數也有點析構函數的味道,但不一定自己釋放資源嗎。
//show
//功能 顯示一個背景.
//入參 無
void DrawRoll(); //循環補空
//功能 顯示一個背景,並縮放圖片
//入參 橫縱方向縮放比例
void DrawRollStretch(int x,int y);
//功能 指定顯示某一個背景,並縮放圖片,游戲中用的就是這個函數
//入參 橫縱方向縮放比例 背景圖片ID(縱向第幾個)
void DrawRollStretch(int x,int y,int id);--進行中橫坐標的操作
//功能 設置圖片位置
//入參 新的橫縱坐標
void MoveTo(int x,int y);
//功能 循環移動分割線
//入參 分割線移動的距離
void MoveRoll(int x);
//data
//分割線橫坐標
int xseparate;
};
看一看圖片顯示 類MYANIOBJ
類說明:這個類負責游戲中的圖片顯示。菜單背景、通關和游戲結束的提示圖片,由MYBITMAP處理(大小一致的靜態圖片)。游戲背景由MYBKSKY處理。其余圖片,也就是游戲過程中的所有圖片,都是MYANIOBJ處理。
技術原理:游戲中的圖片大小不一致,具體在超級瑪麗中,可以分成兩類:矩形圖片和不規則圖片。在位圖文件中,都是縱向排列各個圖片,橫向排列各幀。用兩個數組存儲各個圖片的寬和高。為了方便顯示某一個圖片,用一個數組存儲各個圖片的縱坐標(即位圖文件中左上角的位置)。使用時,由邏輯層指定“哪個圖片”的“哪一幀”,顯示在“什麼位置”。這樣圖片的顯示功能就實現了。
成員函數功能列表:
代碼如下:
class MYANIOBJ:public MYBITMAP
{
public:
MYANIOBJ();
~MYANIOBJ();
//init list
//功能 初始化寬度數組 高度數組 縱坐標數組 是否有黑白圖
//入參 寬度數組地址 高度數組地址 圖片數量 是否有黑白圖(0 沒有, 1 有)
//(圖片縱坐標信息由函數計算得出)
void InitAniList(int *pw,int *ph,int inum,int ismask);
//功能 初始化一些特殊的位圖,例如各圖片大小一致,或者有其他規律
//入參 初始化方式 參數1 參數2
//(留作以後擴展, 目的是為了省去寬高數組的麻煩)
void InitAniList(int style,int a,int b);
//show
//功能 顯示圖片(不規則圖片)
//入參 橫縱坐標(要顯示的位置) 圖片id(縱向第幾個), 圖片幀(橫向第幾個)
void DrawItem(int x,int y,int id,int iframe);
//功能 顯示圖片(矩形圖片)
//入參 橫縱坐標(要顯示的位置) 圖片id(縱向第幾個), 圖片幀(橫向第幾個)
void DrawItemNoMask(int x,int y,int id,int iframe);
//功能 指定寬度, 顯示圖片的一部分(矩形圖片)
//入參 橫縱坐標(要顯示的位置) 圖片id(縱向第幾個), 顯示寬度 圖片幀(橫向第幾個)
void DrawItemNoMaskWidth(int x,int y,int id,int w,int iframe);
//功能 播放一個動畫 即循環顯示各幀
//入參 橫縱坐標(要顯示的位置) 圖片id(縱向第幾個)
void PlayItem(int x,int y,int id);
//寬度數組 最多支持20個圖片
int wlist[20];
//高度數組 最多支持20個圖片
int hlist[20];
//縱坐標數組 最多支持20個圖片
int ylist[20];
//動畫播放時的當前幀
int iframeplay;
};
看一看 魔法攻擊 類MYANIMAGIC
類說明:玩家有兩種攻擊方式:普通攻擊(子彈),魔法攻擊(旋風)。這個類是專門處理旋風的。我最初的想法是用一些特殊的bitblt方法制造特效,例如或、與、異或。試了幾次,都失敗了。最後只能用“先與後或”的老方法。這個類可看成MYANIOBJ的一個簡化版,只支持不規則圖片的顯示。
成員函數功能列表:
代碼如下:
class MYANIMAGIC:public MYBITMAP
{
public:
MYANIMAGIC();
~MYANIMAGIC();
//init list
//功能 初始化寬度數組 高度數組 縱坐標數組(必須有黑白圖)
//入參 寬度數組地址 高度數組地址 圖片數量
//(圖片縱坐標信息由函數計算得出)
void InitAniList(int *pw,int *ph,int inum);
//功能 設置dc
//入參 顯示dc 臨時dc(用於圖片句柄選擇) 臨時dc(用於特效實現)
void SetDevice(HDC hdest,HDC hsrc,HDC htemp);
//show
//功能 顯示某個圖片的某幀
//入參 橫縱坐標(顯示位置) 圖片id(縱向第幾個) 幀(橫向第幾個)
void DrawItem(int x,int y,int id,int iframe);
//寬度數組
int wlist[20];
//高度數組
int hlist[20];
//縱坐標數組
int ylist[20];
//用於特效的臨時dc, 功能沒有實現L
HDC hdctemp;
};
這就是我的一些架構