第一章 框架设计
总体的类如下图所表示。
Shape作为形状基类。存储了与形状有关的物理量
class Shape
{
public:
float I = 0.0f, invI = 0.0f;//转动惯量和逆
};
Rectangle和Circle派生于Shape,存储了实际的形状信息。
class Rectangle :public Shape
{
public:
//存储矩形的长宽
agl::vec2f r;
};
class Circle :public Shape
{
public:
float r;
};
PhyAttr中存放的是各种物理属性,这些属性是不限于任何物体都有的属性。
namespace phy2d
{
class PhyAttr
{
public:
PhyAttr()
{
velocity = agl::vec2f(0.0f);
position = agl::vec2f(0.0f);
force = agl::vec2f(0.0f);
}
agl::vec2f velocity;//速度
agl::vec2f position;//位置
float rotation = 0.0f;//旋转角度
float angularVelocity = 0.0f;//角速度
agl::vec2f force;//力
float torque = 0.0f;//转矩
float friction = 0.0f;//摩擦力
float mass = 0.0f, invMass = 0.0f;//质量和逆
~PhyAttr() {}
};
};
PhyObj是PhyRect与PhyCircle的父类,其主要作用是做为基类指针,支持动态类型使用,分别继承了形状和物理特性,组成了有物理特性的形状。
namespace phy2d
{
class PhyObj {};
class PhyRect :public PhyObj,public Rectangle, public PhyAttr
{
public:
};
class PhyCircle :public PhyObj, public Circle, public PhyAttr
{
public:
};
};
World中负责整个物理世界的运行,存储物体和碰撞信息。协调整个物理引擎的流程。
namespace phy2d
{
class World
{
//存储物体
std::vector<PhyObj*> objects;
//存储碰撞信息
std::unordered_map<std::tuple<PhyObj*, PhyObj*>, Contact> collisions;
public:
};
}
Contact是存储碰撞信息的结构体,Impulse是存储冲量的,因为我们要实现冲量累积方法,所以碰撞信息中保留上一次的冲量信息。Driver是存储两个物体指针和其碰撞信息的结构体,这个结构是存放碰撞后结果的直接结构体,并且其中要有计算两个物体冲量变化的能力。
namespace phy2d
{
class Impulse
{
public:
//正面和侧面的动量
float ImpulseNormal;
float ImpulseSide;
};
//碰撞信息
class Contact
{
public:
Contact() {}
agl::vec2f position;//碰撞点位置
agl::vec2f normal;//分离轴方向
//agl::vec2f r1, r2;//半径//现场算
float separation;//最小相交距离
};
class Driver
{
public:
//碰撞信息列表
std::vector<Contact> contacts;
//碰撞物体
PhyObj *a, *b;
//运动执行函数
void ApplyImpulse()
{
//计算好必要的值
//由于之前的冲量计算是在连个形状相交情况下计算,
//所以一旦两个物体分开,计算将不会连续
//循环迭代
}
};
}
还有一些数学计算,向量计算的类,这些类可以自己写,也可以用现成的比如GLM,这里就使用自己写的向量矩阵计算库了。