之前談到模擬百戰(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
7
namespace 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
22
using namespace GType;
23
class GVector2d
24

{
25
/**//* 待實(shí)現(xiàn) */
26
};
27
28
class GShape
29

{
30
public:
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
};
41
class GBox:public GShape
42

{
43
44
};
45
class GCircle:public GShape
46

{
47
48
};
49
class GPoly:public GShape
50

{
51
52
};
53
54
55
56
57
class 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
85
public:
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
105
class GForce/**//* 主要封裝作用力向量的計算方法, */
106

{
107
public:
108
};
109
110
class GElasForce:public GForce
111

{
112
113
114
};
115
116
class GElecForce:public GForce
117

{
118
};
119
class GMagForce:public GForce
120

{
121
};
122
class GFricForce:public GForce
123

{
124
125
};
126
127
128
129
class 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
138
public:
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
175
private:
176
GWorld::GDominator &god;
177
public:
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影響物理世界的其他因素)。
對物理引擎簡化的使用代碼如下:
1
GPlayer player[5];//GPlayer and GSubstance inherit from GBody
2
GSubstance substance[8];
3
God god;//god inherits from GWorld::GDominator
4
5
6
GWorld World;
7
World.Appear(0,god,5);
8
9
for(int i=0;i!=5;i++)
10
World.god.MakeBody(&player[i]);
11
12
for(int i=0;i!=8;i++)
13
World.god.MakeBody(&substance[i]);
14
15
for(;;)
16
{
17
World.Run();
18
}
19
20
World.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%左右。
歡迎各位全圖靈組員開噴~
另一方面,給出一個游戲整體框架: