第三章,實體 PObject

2021-05-22 21:01:35 字數 4930 閱讀 8519

如前文所述,實體是構成遊戲的基礎,不僅僅是最基礎的顯示單元,也是最基礎的邏輯單元。用乙個裝b的說法,實體的二向性。

shinynova核心中最重要的模組objectmodule負責維護所有的實體。通常我們會在引擎外部建立乙個實體並註冊到核心作為遊戲邏輯的母體,而之後的開發過程將全部封裝在母體內部進行,例如:

class cmygame:public pobject

m_core.registnewobject(new cmygame);

而在母體內部建立新的實體時,標準方法是呼叫pgl_msg_class巨集,這個巨集將自動完成所有的註冊初始化工作:

void  cmygame::oninidata() //實體標準初始化函式,註冊到核心時將被呼叫

一旦註冊到核心,核心將負責維護所有的實體,包括在程序退出時自動對殘餘實體進行清理。每個註冊到核心實體將被分配乙個唯一的控制代碼,你可以呼叫函式gethandle()來獲取這個值。也可以在實體內部通過pobject* getobject(obhandle handle)來獲取其他任意註冊實體的指標。

而為了方便開發者,核心另有一套實體別名機制,你可以為實體註冊乙個唯一的別名:

void cmygame::findmydog()

「每一粒沙中都可以看到世界!」shinynova中遊戲邏輯可以在任意乙個實體中全部展開,但通常我們會把不同的功能模組封裝到不同的實體內。這樣通過實體邏輯模組的組合,就可以構建出任意複雜的遊戲來。例如最常見的標準按鈕:cxystandbutton。將多個按鈕和乙個背景板實體繫結在一起,就形成了乙個控制面板。我們可以定義乙個新的實體來處理各個按鈕之間的邏輯關係:

class ccontrlplane:public pobject

void onbtn1(){}

void onbtn2(){}}

為了處理實體間複雜的互動關係,引擎採用了與windows類似的訊息機制:

typedef struct _tagsng_msg

sng_msg,*lpsng_msg;

只要知道目標實體的控制代碼,即可通過postmsg和sendmsg實現非同步或同步通訊。每個實體都將在bool onmsg(sng_msg& msg)函式中處理自己接受的訊息。需要注意的是,shinynova中訊息投遞是一次性的,如果目標實體不存在,該訊息將被立即丟棄。同時無論該實體是否處理該訊息(msgid指定),訊息都將被投遞到onmsg函式中。

作為邏輯單元,pobject的派生類可以是完全虛擬的,即不可見。但實際上任何乙個pobject都有其物理層面,由結構:

typedef struct _tagobjectobject,*lpobject;

描述。pobject包含了一系列操作函式來實現對實體狀態的改變如:

virtual void         moveto(double x,double y);

virtual void         move(double dx,double dy);

virtual void         setsize(double width,double height);

virtual void         setfloor(double z);

virtual void         upfloor(double dz);

virtual void         uptop();

virtual void         show();

virtual void         hide();

virtual void         setalpha(double alpha);

virtual void         rotatetoangle(double angle);

virtual void         rotate(double angle);

virtual void         rotatetopoint(double x,double y,double angle);

virtual void         scale(double dw,double dh);//按比例防縮

virtual void         scaleto(double width, double height);

virtual void         setcliprect(rect rc);

一旦狀態變化,系統將自動記錄並維護實體的當前狀態,並處理實體間的相互遮掩關係。假設我們想把乙個實體,向右偏移100畫素,並半透明到0.7alpha.只需要:

pobjec* ob;

pgl_msg_class(ob,pobject);

ob->move(100,0);

ob->setalpha(0.5);

ob->updata();         //重新整理函式,將物體狀態更新到核心,重繪

想要方塊1漂浮在方塊2上面?很簡單:

pobject* rect1,rect2;

rect1->upfloor(rect2->getz()+a);//a是任意乙個正實數

rect1->updata();

現在離我們的目標是不是有些近了?我們不需要再去關心怎麼畫實體,而只需要設計它在那裡就可以了,從邏輯到實現的細節將由核心自動完成。

但如果遊戲中實體非常之多,那麼仍然不夠方便.比如乙個人由頭手腳屁股身子5個實體組成,我們想讓人移動一段距離,不得不分別修改5個部分的座標。如果要移動乙個英雄連,那麼這個工作量可夠嚇人的。事實上,大部分實體都具有不同程度的關聯關係。比如人的手不可能離開身體單獨移動,屁股不可能飛到頭上去,而連隊也許會排成方陣跟隨連長前進。這是實體之間物理資訊的傳遞,從乙個實體向其他實體擴散(未考慮可能衰減和反饋)。我們把這種固定的傳遞關係稱為繫結,傳遞方為父體,被傳遞方為子體。好的,那我們這樣來設計連隊的方陣移動:

offiserbject* offiser;   //省略構建部分,下同

for(int i=0;i<100;i++)

offiser->move(dx,dy); //全隊移動dx,dy畫素

offiser->updata();

是不是輕巧了很多?

實體關聯繫結是shinynova中非常重要的乙個概念,有了這個支援,我們才可以放心專注於各個功能模組的內部設計,而不用擔心多模組組合時產生的互動影響。另外,不同的實體繫結關係可能有所差異,有些只需要關聯圖層,有些需要關聯位移,有些甚至需要關聯訊息。採用何種關聯方式,由乙個標誌位決定:

//物體pobject關聯性

#define      object_lock_delete                      0x00000001  //關聯存在

#define      object_lock_angle                        0x00000002  //關聯角度

#define      object_lock_show                        0x00000004  //關聯顯示

#define      object_lock_alpha                        0x00000008  //關聯透明度

#define      object_lock_select                      0x00000010  //關聯可觸發

#define      object_lock_updata                      0x00000020  //關聯重新整理

#define      object_lock_scale                        0x00000040  //關聯放縮

#define      object_lock_size                           0x00000080  //始終等大小

#define      object_lock_memory_show         0x00001000  //關聯記憶顯示,傳遞hide時記錄show資訊

#define      object_record_show                    0x00002000  //標誌已記錄顯示

#define      object_lock_cliprect                   0x00004000  //裁剪矩形

#define      object_lock_floor                        0x00008000  //關聯圖層

#define      object_lock_coordinate              0x00010000  //關聯座標

#define      object_lock_msg                            0x00020000  //接受父體傳遞來的訊息,否則父體的sendmsgtochild將不傳送給該子體

#define      object_lock_input                         0x00040000  //接收和父體相同的訊息

#define      object_lock_position            object_lock_angle|object_lock_floor|object_lock_coordinate|object_lock_size

//全關聯性

#define      object_lock_all                  object_lock_delete /

| object_lock_updata /

| object_lock_scale/

| object_lock_size/

| object_lock_position/

| object_lock_show   /

| object_lock_alpha  /

| object_lock_cliprect/

| object_lock_msg

ps:單個模組(控制項)內各個實體的圖層差異最好小於1,模組之間的圖層差異大於1,以防止發生子體交錯(約定俗成)。

第三章 堆疊

1.基礎知識 堆疊可以實現很多的應用,遞迴的問題轉化成非遞迴形式,在本質上也是堆疊的問題.它是一種 filo 操作的資料結構,一般也有兩種儲存方式 陣列跟鍊錶實現形式,這裡我給出了鍊錶形式的堆疊模板,裡面包括了基本的堆疊所有的操作,還有兩個比較著名的應用例子,時間倉促,精力比較有限,關於迷宮老鼠還沒...

第三章 曙光

第三章 曙光 第二場校園招聘開始了。其實,洋對這個公司的不是很了解。因為前幾天突然在bbs上面看到了這個公司的招聘資訊,洋覺得這個公司不錯,就上網投了簡歷。接下來的乙個多小時,讓洋很震撼!想不到這個公司這個厲害,而且無論從哪方面來說,絕對不比之前的那個公司差。想不到自己的乙個不經意的決定到了這個大的...

第三章 遞迴

遞迴是一種強大的方法,它允許乙個物件以其自身更小的形式來定義自己。恐怕沒有什麼比觀察神秘的自然界中出現的遞迴現象更好的方法來體會遞迴的重要意義了。想想蕨類植物的葉子,每片葉子的小枝幹都是整片葉子的較小縮影 又或者兩個反光的物體,相互對映對方的漸遠的影像。這樣的例子使我們明白儘管大自然的力量是強大的,...