本系列博客是由扭曲45原创,欢迎转载,转载时注明出处,http://blog.csdn.net/cg0206/article/details/8280463
今天我们要说在公共模块剩下的三个小模块的实现,分别是:计时器类、调试辅助类、和box2d引擎设置部分。
1、 计时器b2Timer
计时器主要是用来计算一段时间内的时间,通过对某个函数执行计时,可用来查看相关函数的效率和性能。Box2d中主要针对window系统和类unix系统(如linux、OS X)进行了实现。它们主要是通过宏开关控制的,像window系统上的宏是_WIN32,linux系统上的宏是__linux__,OS X系统上的宏则是__APPLE__,这些在不同系统的编译器中一般是有定义的,不要我们手动去改,如果真的没有不妨自己在文件中手动定义一下,碰碰运气。
好了,废话不多说,上代码:
- //计时器。这是基于特定平台上的代码,可能无法在每个平台都正常工作
- class b2Timer
- {
- public:
- /**************************************************************************
- * 功能描述:构造函数
- * 参数说明: (void)
- * 返 回 值: (void)
- ***************************************************************************/
- b2Timer();
- /**************************************************************************
- * 功能描述:重置timer
- * 参数说明: (void)
- * 返 回 值: (void)
- ***************************************************************************/
- void Reset();
- /**************************************************************************
- * 功能描述:获取time从构造或最近的重置开始
- * 参数说明: (void)
- * 返 回 值: 毫秒数
- ***************************************************************************/
- float32 GetMilliseconds() const;
- private:
- #if defined(_WIN32)
- //开始计数变量,记录开始值
- float64 m_start;
- //获取每毫秒计数的次数
- static float64 s_invFrequency;
- #elif defined(__linux__) || defined (__APPLE__)
- //开始计数的秒数、微秒数
- unsigned long m_start_sec;
- unsigned long m_start_msec;
- #endif
- };
- #if defined(_WIN32) && !defined(SHP)
- //获取每毫秒计数的次数
- float64 b2Timer::s_invFrequency = 0.0f;
- #include <windows.h>
- //构造函数
- b2Timer::b2Timer()
- {
- //
- LARGE_INTEGER largeInteger;
- //第一次开始的时候
- if (s_invFrequency == 0.0f)
- {
- //获取高精度计数器的频率
- QueryPerformanceFrequency(&largeInteger);
- s_invFrequency = float64(largeInteger.QuadPart);
- //获取每毫秒计数的次数
- if (s_invFrequency > 0.0f)
- {
- s_invFrequency = 1000.0f / s_invFrequency;
- }
- }
- //定时器的计数值
- QueryPerformanceCounter(&largeInteger);
- m_start = float64(largeInteger.QuadPart);
- }
- //重置
- void b2Timer::Reset()
- {
- LARGE_INTEGER largeInteger;
- QueryPerformanceCounter(&largeInteger);
- m_start = float64(largeInteger.QuadPart);
- }
- //获取毫秒数
- float32 b2Timer::GetMilliseconds() const
- {
- LARGE_INTEGER largeInteger;
- QueryPerformanceCounter(&largeInteger);
- //开始计数
- float64 count = float64(largeInteger.QuadPart);
- //毫秒数
- float32 ms = float32(s_invFrequency * (count - m_start));
- return ms;
- }
- #elif defined(__linux__) || defined (__APPLE__)
- #include <sys/time.h>
- //构造函数
- b2Timer::b2Timer()
- {
- Reset();
- }
- //重置
- void b2Timer::Reset()
- {
- timeval t;
- gettimeofday(&t, 0);
- m_start_sec = t.tv_sec;
- m_start_msec = t.tv_usec * 0.001f;
- }
- //获取毫秒数
- float32 b2Timer::GetMilliseconds() const
- {
- timeval t;
- gettimeofday(&t, 0);
- return (t.tv_sec - m_start_sec) * 1000 + t.tv_usec * 0.001f - m_start_msec;
- }
- #else
- b2Timer::b2Timer()
- {
- }
- void b2Timer::Reset()
- {
- }
- float32 b2Timer::GetMilliseconds() const
- {
- return 0.0f;
- }
- #endif
通过宏的编译可以看出,window和类nuix上使用的内部API是不一样的,就像软件有debug和Release版本一样,有时候debug没问题,relase则不然,孰不知,它们在编译时编译器调用的程序很有可能是不同的。同时我们也要注意下,还有其他的类型的系统没有实现此类(估计一般人也碰不上)。
2、 调试辅助类b2Draw
调试辅助类主要辅助box2d中物体的调试,通过绘制不同的调试辅助的形状,来监控并改正物体行为的正确性。首先我们看下b2Draw.h文件。
- // 调试绘制的颜色,每个值都在[0,1]之间
- struct b2Color
- {
- /**************************************************************************
- * 功能描述:默认构造函数
- * 参数说明: (void)
- * 返 回 值: (void)
- ***************************************************************************/
- b2Color() {}
- /**************************************************************************
- * 功能描述:构造函数
- * 参数说明: r : 红色值部分
- g :绿色值部分
- b :蓝色值部分
- * 返 回 值: (void)
- ***************************************************************************/
- b2Color(float32 r, float32 g, float32 b) : r(r), g(g), b(b) {}
- /**************************************************************************
- * 功能描述:设置颜色函数
- * 参数说明: ri : 红色值部分
- gi :绿色值部分
- bi :蓝色值部分
- * 返 回 值: (void)
- ***************************************************************************/
- void Set(float32 ri, float32 gi, float32 bi) { r = ri; g = gi; b = bi; }
- //代表红、绿、蓝的变量
- float32 r, g, b;
- };
- //在b2World中实现并注册这个类,以便提供调试绘制不同的物理实体在你的游戏中
- class b2Draw
- {
- public:
- /**************************************************************************
- * 功能描述:构造函数
- * 参数说明: (void)
- * 返 回 值: (void)
- ***************************************************************************/
- b2Draw();
- /**************************************************************************
- * 功能描述:析构函数
- * 参数说明: (void)
- * 返 回 值: (void)
- ***************************************************************************/
- virtual ~b2Draw() {}
- enum
- {
- e_shapeBit = 0x0001, ///< 绘制形状
- e_jointBit = 0x0002, ///< 绘制关节联系
- e_aabbBit = 0x0004, ///< 绘制轴对齐边框
- e_pairBit = 0x0008, ///< 绘制broad-phase pairs
- e_centerOfMassBit = 0x0010 ///< 绘制质心框架
- };
- /**************************************************************************
- * 功能描述:设置绘制标志位
- * 参数说明: flags:标志
- * 返 回 值: (void)
- ***************************************************************************/
- void SetFlags(uint32 flags);
- /**************************************************************************
- * 功能描述:获得绘制标志位
- * 参数说明: (void)
- * 返 回 值: 绘制标志
- ***************************************************************************/
- uint32 GetFlags() const;
- /**************************************************************************
- * 功能描述:追加绘制标志位
- * 参数说明: flags:绘制标志
- * 返 回 值: (void)
- ***************************************************************************/
- void AppendFlags(uint32 flags);
- /**************************************************************************
- * 功能描述:从当前标志中清除标志
- * 参数说明: flags:绘制标志
- * 返 回 值: (void)
- ***************************************************************************/
- void ClearFlags(uint32 flags);
- /**************************************************************************
- * 功能描述:按照提供的顶点绘制逆时针方式闭合的多边形
- * 参数说明: vertices :顶点
- vertextexCount: 顶点数量
- color : 颜色
- * 返 回 值: (void)
- ***************************************************************************/
- virtual void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0;
- /**************************************************************************
- * 功能描述:按照提供的顶点绘制逆时针方式闭合的并填充颜色的多边形
- * 参数说明: vertices :顶点
- vertextexCount: 顶点数量
- color : 颜色
- * 返 回 值: (void)
- ***************************************************************************/
- virtual void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0;
- /**************************************************************************
- * 功能描述:绘制一个圆
- * 参数说明: center :向量
- radius : 半径
- color : 颜色
- * 返 回 值: (void)
- ***************************************************************************/
- virtual void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color) = 0;
- /**************************************************************************
- * 功能描述:绘制一个填充颜色的圆
- * 参数说明: center :向量
- radius : 半径
- color : 颜色
- * 返 回 值: (void)
- ***************************************************************************/
- virtual void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color) = 0;
- /**************************************************************************
- * 功能描述:绘制一段线段
- * 参数说明: p1 :开始点
- p2 : 结束点
- color : 颜色
- * 返 回 值: (void)
- ***************************************************************************/
- virtual void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) = 0;
- /**************************************************************************
- * 功能描述:绘制一个变换,选择你的长度比例。
- * 参数说明: xf :变换
- * 返 回 值: (void)
- ***************************************************************************/
- virtual void DrawTransform(const b2Transform& xf) = 0;
- protected:
- //绘制标志
- uint32 m_drawFlags;
- };
通过代码我们可以看到有个b2Color的结构体的定义,它主要作为调试颜色使用的。
再看看b2Draw的实现部分
- //构造函数
- b2Draw::b2Draw()
- {
- m_drawFlags = 0;
- }
- //设置标志位
- void b2Draw::SetFlags(uint32 flags)
- {
- m_drawFlags = flags;
- }
- //获取标志位
- uint32 b2Draw::GetFlags() const
- {
- return m_drawFlags;
- }
- //追加标志位
- void b2Draw::AppendFlags(uint32 flags)
- {
- m_drawFlags |= flags;
- }
- //清除标志位
- void b2Draw::ClearFlags(uint32 flags)
- {
- m_drawFlags &= ~flags;
- }
通过观察b2Draw的实现,我们发现有点不对劲,定义的函数那么多,怎么实现就这几个函数呢?那其他的函数在哪里实现的呢?我们不禁要问难道是要我们使用者自己实现吗?真被我们猜中了,这个是要我们那实现的,可以看到没有实现的函数前面都有virtual做修饰,这就是虚函数,是等着用户自己用的时候去实现的,不能直接调用。
3、 Box2d设置
设置中主要定义了宏、常量、和一些辅助的公共函数。我们就来看看相关的定义。
在b2Settings.h文件中:
- //主要是因为有的编译器将提示相关语句的值是未使用的,
- //所以你必须告诉它忽略所有(void)。
- //即消除编译器的警告
- #define B2_NOT_USED(x) ((void)(x))
- //对断言宏进行重新封装
- #define b2Assert(A) assert(A)
- //重新封装类型,这样做为了方便而且很好的移植到不同的平台
- typedef signed char int8;
- typedef signed short int16;
- typedef signed int int32;
- typedef unsigned char uint8;
- typedef unsigned short uint16;
- typedef unsigned int uint32;
- typedef float float32;
- typedef double float64;
- //float类型最大值
- #define b2_maxFloat FLT_MAX
- //float类型最小值
- #define b2_epsilon FLT_EPSILON
- //pi的值
- #define b2_pi 3.14159265359f
- /// 全局常量参数 基于米-千克-秒(MKS)单位
- //碰撞
- //在两个凸形状上的接触点最大数量,不要修改它的值
- #define b2_maxManifoldPoints 2
- //凸多边形的顶点数量的最大值。你不能将这个宏修改的太大,因为b2BolckAlloctor函数有一个物体内存大小的上限
- #define b2_maxPolygonVertices 8
- // 用这个在动态树上填充AABB,它允许代理少量移动不必去调整这个树
- // 单位是米
- #define b2_aabbExtension 0.1f
- // 用这个在动态树上填充AABBs,这是基于当前位移用来预测未来的位置。
- // 没有单位
- #define b2_aabbMultiplier 2.0f
- //一个小的长度作为碰撞和约束误差,通常它被选为数字意义重大,但视觉上无足轻重。
- #define b2_linearSlop 0.005f
- //一个小的角度作为碰撞和约束误差,通常它被选为数字意义重大,但视觉上无足轻重。
- #define b2_angularSlop (2.0f / 180.0f * b2_pi)
- ///半径的多边形/边缘形状的皮肤。这应该不会被修改。使
- ///这意味着将有一个小的多边形数不足为连续碰撞缓冲。
- ///使它更大的可能创建工件为顶点碰撞。
- #define b2_polygonRadius (2.0f * b2_linearSlop)
- ///在连续物理模拟里,在每次接触中子步骤的最大数值
- #define b2_maxSubSteps 8
- //动态
- //接触的最大数用于处理解决一个撞击时间内的撞击
- #define b2_maxTOIContacts 32
- //弹性碰撞的一个速度阈值,任何与一个相对线速度碰撞,低于这个阈值的将被视为非弹性碰撞
- #define b2_velocityThreshold 1.0f
- // 线性速度位置的最大值校正当解决约束使用,这有助于阻止穿越物体
- #define b2_maxLinearCorrection 0.2f
- // 角位置的最大值校正当解决约束使用,这有助于阻止穿越物体
- #define b2_maxAngularCorrection (8.0f / 180.0f * b2_pi)
- // 物体【刚体】的最大线速度,这限制是非常大的,用于防止数值问题。你不需要去适应这个
- #define b2_maxTranslation 2.0f
- #define b2_maxTranslationSquared (b2_maxTranslation * b2_maxTranslation)
- // 物体【刚体】的最大线速度,这限制是非常大的,用于防止数值问题。你不需要去适应这个
- #define b2_maxRotation (0.5f * b2_pi)
- #define b2_maxRotationSquared (b2_maxRotation * b2_maxRotation)
- //这个比例因子控制怎样快速解决重叠问题。理想的情况下,这将是1,这样重叠将在一个时间步内被移除
- #define b2_baumgarte 0.2f
- #define b2_toiBaugarte 0.75f
- // 休眠
- //最小休眠时间
- #define b2_timeToSleep 0.5f
- //刚体[body]要想休眠,线的最大值,即当角速度超过它时刚体[body]无法休眠。
- #define b2_linearSleepTolerance 0.01f
- //刚体[body]要想休眠,角速度的最大值,即当角速度超过它时刚体[body]无法休眠。
- #define b2_angularSleepTolerance (2.0f / 180.0f * b2_pi)
- // 内存申请
- //申请内存函数,实现这个函数作为你自己的内存分配器。
- void* b2Alloc(int32 size);
- //释放内存函数,如果你实现b2Alloc,你也应该实现这个功能。
- void b2Free(void* mem);
- //打印日志函数
- void b2Log(const char* string, ...);
- //版本编号方案
- //见 http://en.wikipedia.org/wiki/Software_versioning
- struct b2Version
- {
- int32 major; ///重大更新
- int32 minor; ///较大更新
- int32 revision; ///修复bug
- };
- //box2d当前版本号
- extern b2Version b2_version;
在这里还想再强调说明下B2_NOT_USED(x),很多人不理解为什么要转化为((void)x),这样做的有什么作用或者好处吗?当然是有的,以下网上查找的解释
Mainly becauseat least one compiler will complain that the resulting statement's value isunused, so you have to tell it to ignore it all with (void).
翻译了一下,也就是消除有的编译器编译时候发出的警告。这里借此说一下,编程时不要无视编译器时候发出的警告,警告的出现往往多是我们编写的时候不规范造成的,当然有一部分是错误和还有一部分编译器的原因。我们要尽量去修复它,不要因为一个无视了一个未初始化一个指针的警告,你的程序出现了莫名其妙的情况时,再满头大汗的到处说指针很坑爹。
接着看b2Settings.cpp文件中的实现:
- //box2d当前版本号
- b2Version b2_version = {2, 2, 1};
- /**************************************************************************
- * 功能描述:申请内存
- * 参数说明:size : 申请大小
- * 返 回 值: (void)
- **************************************************************************/
- void* b2Alloc(int32 size)
- {
- return malloc(size);
- }
- /**************************************************************************
- * 功能描述:释放内存
- * 参数说明:mem : 内存头
- * 返 回 值: (void)
- **************************************************************************/
- void b2Free(void* mem)
- {
- free(mem);
- }
- /**************************************************************************
- * 函数名称:b2Log
- * 功能描述:打印log
- * 参数说明:string :打印字符串
- ... :参数列表
- * 返 回 值: (void)
- **************************************************************************/
- void b2Log(const char* string, ...)
- {
- #if defined(SHP)
- #ifdef _DEBUG
- __App_info(__PRETTY_FUNCTION__ , __LINE__, string);
- #endif
- #else
- va_list args;
- va_start(args, string);
- vprintf(string, args);
- va_end(args);
- #endif
- }
通过这过我们可以看到,我们使用的是box2d 版本号2.2.1,接下来是对c中内存管理函数malloc和free函数的封装,好处就是如果使用了不同与malloc/free的接口,我们可以在此次快速的替换。而不需要找其他任何文件。
公共部分终于讲完了,下面我们将会学习碰撞部分。以上部分,根据本人理解所写,若有不妥或错误之处,还请大家多多指正。