第二章 虚与实的谐韵
传说,从前有个谁用七天创造了世界,第一天创造了光。Small World里暂时没有光,也没有影,第一天的创建,从简单的实体开始。
在构建实体之前,先粗略的列一下仿真的步骤,能够清晰一下思路:
1.构建实体存储状态信息,如物理参数,空间大小
2.构建一个集合来管理这些物体
3.初始化所有的环境与实体
4.仿真计算物理世界的变化,如施加在物体上的重力
5.计算并更新物理世界,如计算物体的速度,根据仿真时间推进
6.解决仿真过程中发生的问题,如碰撞
有了仿真的大纲,可见实体存放在整个物理世界中,为了方便以后进行碰撞等物理仿真,实体应该组织成一种特殊的结构,如Kd树或是八叉树。所以所有实体由一个EntityTree统一进行管理,也便于以后进行多线程或是GPU加速。实体定义为一个抽象类Entity。由Entity派生出物理世界中各种的子类。为了满足系统对不同物体仿真的需求。定义一下几种基本实体:RigidEntity,最传统的刚体;SoftEntity,软体,如史莱姆形状的物体;HydroEntity,流体,如水流,烟等;StaticEntity,静态物体,如大地。目前不考虑可粉碎,可分裂的物体。因为物理仿真中物体的基本属性是形状,而不同类型的物体可能有相同的形状,所以定义了Entity的一个属性Body,Body的子类有如BoxBody,方形或是PolyBody,多变形(二维),多面体(三维)。Entity与Body之间的关系如下图所示:
Entity包含需要识别的oID,实体形状body和一个可以屏蔽实体属性的标示simMask以及移动的函数:
class Entity
{
public:
Entity(SWID id = ""):simMask(NOMASK),oID(id),body(NULL){}
virtual ~Entity(void){
if (body != NULL) delete body;
}
virtual bool operator != (Entity& entity) const{
return oID.compare(entity.getID()) != 0;
}
virtual void transform(Transform& trans){body->transform(trans);}
virtual bool isMask(int mask){ return (mask & simMask) != NOMASK;}
virtual void setMask(int mask){simMask |= mask;}
virtual SWID getID(){return oID;}
virtual Body* getBody(){return body;}
virtual AABB getAABB(){return body->getAABB();}
protected:
SWID oID;
int simMask;
Body *body;
};
同样对于Body,包括质量,速度等属性,用于之后物体相互作用。
class Body
{
public:
Body(){}
~Body(void){}
virtual void transform(Transform & trans) = 0;
virtual AABB getAABB() = 0;
virtual DirectSpeed getSpeed() = 0;
virtual double getMass() = 0;
};
至于EntityTree,目前就以vector来保存所有Entity,通过全局函数:
Entity* swGetEntity(SWID wid, SWID oid);
void swRegisteEntity(SWID wid, Entity *obj);
void swd::swRegisteEntity(SWID wid, Entity *obj){
szSmallWorlds[wid]->registe(obj);
}
bool SmallWorld::registe(Entity *obj){
entityTree.add(obj);
return true;
}
void EntityTree::add(Entity *obj){
entitys.push_back(obj);
}
向ID为wid的物理世界中的EntityTree注册(push_back)实体,每个实体通过上一篇介绍的swUpdateWorld更新各个实体。
void SmallWorld::updateEntitys(){
entityTree.update(timer);
}
void EntityTree::update(Timer &timer){
for(unsigned i = 0; i < entitys.size(); ++i){
entitys[i]->...
}
}
第一天过后,这样简单的实体就加入到整个仿真的循环当中了,不过现在还没有实现任何功能,下一篇就是要能够对每个实体施加物理操作,如重力,摩擦力等。