之前談到模擬百戰(zhàn)天蟲的游戲類型,團(tuán)隊(duì)開始準(zhǔn)備設(shè)計“百戰(zhàn)天神”(Gods),需要一個統(tǒng)一的設(shè)計接口。

由于最核心的部分是2D Physics Engine ,所以先給出了一個公共實(shí)現(xiàn)框架性的代碼(整個游戲代碼的基礎(chǔ)類庫準(zhǔn)備用vczh的vlpp庫,vlpp_def是自己設(shè)定的統(tǒng)一vczh庫調(diào)用頭文件):

  1#ifndef _GODSPHY2D_
  2#define _GODSPHY2D_
  3
  4#include "vlpp_def.h"
  5
  6
  7namespace GType
  8{
  9
 10    typedef bool GBool;
 11    typedef double GUReal;
 12    typedef unsigned long GULong;
 13    typedef float GReal;
 14    typedef int GInt;
 15    typedef unsigned int GUInt;
 16    typedef __int64 GInt64;
 17    typedef char GChar;
 18    static const GUInt MAX_BODIES=2000;
 19}
;
 20
 21
 22using namespace GType;
 23class GVector2d
 24{
 25    /* 待實(shí)現(xiàn) */
 26}
;
 27
 28class GShape
 29{
 30public:
 31    virtual GUInt IsZero()=0;//是否無形狀
 32    virtual GUInt GetCG()=0;//幾何中心
 33    virtual GUInt GetArea()=0;
 34    virtual GUInt GetGeoCentre()=0;
 35    virtual GUInt Rotate(GUInt _rotAngle)=0;
 36    virtual GUInt Scale(GUReal factor)=0;
 37    virtual GUInt Minus(const GShape* _shape)=0;
 38    virtual GUInt Add(const GShape* _shape)=0;
 39
 40}
;
 41class GBox:public GShape
 42{
 43
 44}
;
 45class GCircle:public GShape
 46{
 47
 48}
;
 49class GPoly:public GShape
 50{
 51
 52}
;
 53
 54
 55
 56
 57class GBody
 58{
 59    GUInt id;
 60
 61    Vector<GShape*> shapes;
 62    GReal fric;//Friction
 63    GReal dens;//Density
 64    GReal elas;//Elasticity
 65    GReal area;//Area of bodies
 66    GReal rigi;//Rigidity
 67
 68
 69    GReal mag;//Magnetism
 70    GReal elec;//Quantity of electric charge
 71
 72
 73    GVector2d cg;//Center of gravity 
 74    GVector2d tv;//Translational velocity
 75    GVector2d rv;//Rotational velocity
 76    GVector2d ta;//Translational acceleration
 77    GVector2d ra;//Rotational acceleration
 78    GReal x;
 79    GReal y;
 80
 81    GUInt IsDeformable;//(0,1,2)=(not,in scale,in minus)
 82    GBool IsVisible;
 83    
 84    
 85public:
 86    GBody(const GBody& _copy);
 87    GBody(const GShape* _shapes,int _n,GReal _friction,GReal _density,GReal _elasticity);
 88    GReal AddShape(const GShape& _shape);
 89    GReal GetArea(){return area;};
 90    GReal GetDens(){return dens;};
 91    GReal GetElas(){return elas;};
 92    GReal GetMass(){return area*dens;};
 93    GReal GetFric(){return fric;};
 94    GVector2d GetCG(){return cg;}
 95    GVector2d GetTV(){return tv;}
 96    GVector2d GetRV(){return rv;}
 97    GVector2d GetTA(){return ta;}
 98    GVector2d GetRA(){return ra;}
 99
100    virtual GUInt Consider();
101
102    virtual ~GBody();
103}
;
104
105class GForce/* 主要封裝作用力向量的計算方法, */
106{
107public:
108}
;
109
110class GElasForce:public GForce
111{
112
113    
114}
;
115
116class GElecForce:public GForce
117{
118}
;
119class GMagForce:public GForce
120{
121}
;
122class GFricForce:public GForce
123{
124
125}
;
126
127
128
129class GWorld
130{
131    GULong time;//世界已運(yùn)行時間
132    GUInt timeModule;//最小body狀態(tài)變更周期
133    GULong doomsday;//末日期
134
135
136    GVector2d gField;//等效重力場(單一方向),gField=0時無重力場
137    Array<GBody*> bodies;//世界內(nèi)所有body
138public:
139    class GDominator:public GBody
140    {
141        /* 世界指針,控制范圍參數(shù)等等 */
142        friend class GBody;
143        GWorld* world;
144        Array<Array<GVector2d*>> pairForces;
145
146    public:
147        class GCollision
148        {
149            /* Factors of Collision */
150        public:
151            static GUInt GetColliTime(GUInt _dTime,const GBody* _bodies,int _n);
152            static GBool DoColli(GUInt _dTime,GBody* _bodies,int _n);
153        }
;
154
155        class GBlast
156        {
157            /* 爆炸種類參數(shù)和爆炸效果、曲線范圍方法的封裝 */
158        public:
159
160
161        }
;
162        class GLog
163        {
164            /* 記錄所有bodies改變以及改變原因,以及季節(jié)變化(如果存在變化的話) */
165        }
;
166    public:
167        GUInt KillBody(int _i);//按list序號零序第_i位毀滅一個body,但保持其為空:map相對穩(wěn)定速度快
168        GUInt MakeWind(int _delayTime,GVector2d _wind);
169        GUInt MakeBody(GBody* _newBody);
170        GUInt BreakIntoPieces(GBlast& _blast);
171        GUInt MakeChanged(GBody* _body);
172        GBool ChangeGField(const GVector2d& _gField);
173    }
;
174
175private:
176    GWorld::GDominator &god;
177public:
178    
179
180    GUInt AddGod(GWorld::GDominator& _god);
181    GULong GetTime();
182    GUInt GetTimeModule();
183    GULong GetDoomsday();
184
185    GVector2d GetGField();
186
187    GBool Appear(GULong _time,GULong _doomsday,GUInt _timeModule);//初始化世界參數(shù),讀檔時讀取存檔參數(shù)傳入此處開始游戲
188    GBool Run();//世界運(yùn)行一個最小時間周期(timeModule)
189    GBool End();
190
191
192    
193}
;
194
195
196
197#endif
198




可以這么簡單描述:

要想讓引擎工作,先要創(chuàng)造一個世界(GWorld),在世界里面添加一個神(GDominator),在世界里加上萬物(GBody*),接著加入等效重力向量(GVector2d)。

到此不僅要問自己幾個問題:
1 為什么要用神來控制隨機(jī)事件和記錄游戲分?jǐn)?shù)、狀態(tài)信息、活物的生死,而不是直接是GWorld類?
     神是GWorld的內(nèi)嵌類,在GWorld層次還不能加入神的意志(Consider方法),因?yàn)槟鞘窃O(shè)計游戲邏輯階段的可配置內(nèi)容,所以所有隨機(jī)事件和記錄方式、影響審判的策略都沒有形成,總不能用GWorld加入AI類的對象,因?yàn)锳I不屬于物理引擎范疇。于是GWorld::GDominator可以被游戲設(shè)計者自己創(chuàng)造的God類繼承,God類玩家可以自由添加AI范疇,并且重載Consider方法來用AI驅(qū)動神的意志。

2 為什么世界類用“Appear”方法名開始世界對象的運(yùn)行而不用“Start”名字?如果游戲進(jìn)行到一半,存檔后退出,如何重新加載進(jìn)來呢?如果寫成Start,那么就不符合加載中途游戲的意思,那么出現(xiàn)一個世界就變得合理了。

3  力應(yīng)該屬于個體(Body)嗎?力是成對出現(xiàn)的,所以這里力不被單獨(dú)標(biāo)示,而用GVector2d直接表示,這里用一個二維表Array<Array<GVector2d*>>  表示i Body 對 j Body的力向量,每一個Body有唯一的序號,也就是說,Body被毀滅后仍然不會影響其它Body的id號和映射號、位置。因此力被設(shè)計成單獨(dú)放在神的類中管理。

4  時間精度如何定義?這里的物理引擎完全邏輯設(shè)計,具體實(shí)現(xiàn)時間粒度與特定類型無關(guān).最小時間粒度是1,并不定義是1ms還是1ns,那是游戲?qū)崿F(xiàn)的事情,另外,時間最小粒度是1,但是不可能每1粒度刷新一次世界萬物狀態(tài),所以設(shè)置了timeModule,這是刷新世界狀態(tài)的最小時間周期,比如為timeModule=5時,每5個時間粒度刷新一次世界狀態(tài),世界狀態(tài)的刷新也有具體實(shí)現(xiàn)方法的技巧,不可能有n個body就計算n*(n-1)次body狀態(tài),必定有些規(guī)則導(dǎo)致只有特定某些物體事件發(fā)生的狀態(tài)會改變。

5  如何刷新運(yùn)動狀態(tài)?這里不可能大量使用積分?jǐn)M合,對于圓周運(yùn)動,需要用到精確運(yùn)動位移量,對于拋體運(yùn)動,可以直接從力刷新到加速度,再到速度,再到運(yùn)動位移,相當(dāng)于矩形近似擬合。

6  如何檢測碰撞?碰撞必須是接觸力或非接觸力突變幅度大的雙方物體。不可能每刷新一個時間粒度就檢測所有body之間是否存在碰撞,有一點(diǎn)是確定的,只有突變了屬性的(電荷量、質(zhì)量、磁性、位置)的body之間才可能存在碰撞,也就是每一個時間粒度的逝去之前會專門對它們之間進(jìn)行碰撞檢測并計算出碰撞結(jié)果以及影響結(jié)果(這些結(jié)果也會記錄進(jìn)神的Log中,一邊游戲結(jié)束前可以一次性分析Log得出得分,或者這些Log影響物理世界的其他因素)。


對物理引擎簡化的使用代碼如下:

 1GPlayer player[5];//GPlayer and GSubstance inherit from GBody
 2GSubstance substance[8];
 3God god;//god inherits from GWorld::GDominator 
 4
 5
 6GWorld World;
 7World.Appear(0,god,5);
 8
 9for(int i=0;i!=5;i++)
10  World.god.MakeBody(&player[i]);
11
12for(int i=0;i!=8;i++)
13  World.god.MakeBody(&substance[i]);
14
15  for(;;)
16  {
17    World.Run();
18  }

19
20World.End();

這里省略的GPlayer、GSubstance定義分別繼承自物理引擎中的GBody類
God類繼承于GWorld::GDominator類。

這種繼承的作用體現(xiàn)在是可配置的,增加策略AI是非常必要的環(huán)節(jié)。



以上接口的實(shí)現(xiàn)需要考慮更加細(xì)微的問題:
1 比如什么程度下萬有引力需要去計算(這里考慮到多個星球加入世界)
2 碰撞檢測是否需要多層形狀,不同的碰撞用不同的形狀去檢測,以增加視覺精確性
3 對于轉(zhuǎn)動慣量等內(nèi)容的計算是否要完全符合物理規(guī)則
4 怎么更好的確定擊打邊角時該依賴的支點(diǎn)或者說轉(zhuǎn)軸
5 什么程度的因素會導(dǎo)致發(fā)生碰撞后并不分離(硬度、密度、形狀?)
6 風(fēng)力系統(tǒng)的模擬是封裝在God類中的,但是風(fēng)力系統(tǒng)是用流體力學(xué)去計算還是直接用軌跡和制造轉(zhuǎn)角力矩去實(shí)現(xiàn)樹葉等物體的無規(guī)則飄散
....and so on.

目前為止應(yīng)該算實(shí)現(xiàn)了Gods 2DPhyEngine公共接口部分的65%左右。

歡迎各位全圖靈組員開噴~

另一方面,給出一個游戲整體框架: