Box2d源码学习<五>b2Timer、b2Draw和b2Settings的实现

本系列博客是由扭曲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__,这些在不同系统的编译器中一般是有定义的,不要我们手动去改,如果真的没有不妨自己在文件中手动定义一下,碰碰运气。大笑

好了,废话不多说,上代码:

[cpp]  view plain copy
  1. //计时器。这是基于特定平台上的代码,可能无法在每个平台都正常工作  
  2. class b2Timer  
  3. {  
  4. public:  
  5.     /************************************************************************** 
  6.     * 功能描述:构造函数 
  7.     * 参数说明: (void) 
  8.     * 返 回 值: (void) 
  9.     ***************************************************************************/  
  10.     b2Timer();  
  11.     /************************************************************************** 
  12.     * 功能描述:重置timer 
  13.     * 参数说明: (void) 
  14.     * 返 回 值: (void) 
  15.     ***************************************************************************/  
  16.     void Reset();  
  17.     /************************************************************************** 
  18.     * 功能描述:获取time从构造或最近的重置开始 
  19.     * 参数说明: (void) 
  20.     * 返 回 值: 毫秒数 
  21.     ***************************************************************************/  
  22.     float32 GetMilliseconds() const;  
  23.   
  24. private:  
  25.   
  26. #if defined(_WIN32)  
  27.     //开始计数变量,记录开始值  
  28.     float64 m_start;  
  29.     //获取每毫秒计数的次数  
  30.     static float64 s_invFrequency;  
  31. #elif defined(__linux__) || defined (__APPLE__)  
  32.     //开始计数的秒数、微秒数  
  33.     unsigned long m_start_sec;  
  34.     unsigned long m_start_msec;  
  35. #endif  
  36. };  
上面有何详细的注解,不多说了,下面我们看下实现部分:

[cpp]  view plain copy
  1. #if defined(_WIN32) && !defined(SHP)  
  2. //获取每毫秒计数的次数  
  3. float64 b2Timer::s_invFrequency = 0.0f;  
  4.   
  5. #include <windows.h>  
  6. //构造函数  
  7. b2Timer::b2Timer()  
  8. {  
  9.     //  
  10.     LARGE_INTEGER largeInteger;  
  11.     //第一次开始的时候  
  12.     if (s_invFrequency == 0.0f)  
  13.     {  
  14.         //获取高精度计数器的频率  
  15.         QueryPerformanceFrequency(&largeInteger);  
  16.         s_invFrequency = float64(largeInteger.QuadPart);  
  17.         //获取每毫秒计数的次数  
  18.         if (s_invFrequency > 0.0f)  
  19.         {  
  20.             s_invFrequency = 1000.0f / s_invFrequency;  
  21.         }  
  22.     }  
  23.     //定时器的计数值  
  24.     QueryPerformanceCounter(&largeInteger);  
  25.     m_start = float64(largeInteger.QuadPart);  
  26. }  
  27. //重置  
  28. void b2Timer::Reset()  
  29. {  
  30.     LARGE_INTEGER largeInteger;  
  31.     QueryPerformanceCounter(&largeInteger);  
  32.     m_start = float64(largeInteger.QuadPart);  
  33. }  
  34. //获取毫秒数  
  35. float32 b2Timer::GetMilliseconds() const  
  36. {  
  37.     LARGE_INTEGER largeInteger;  
  38.     QueryPerformanceCounter(&largeInteger);  
  39.     //开始计数  
  40.     float64 count = float64(largeInteger.QuadPart);  
  41.     //毫秒数  
  42.     float32 ms = float32(s_invFrequency * (count - m_start));  
  43.     return ms;  
  44. }  
  45.   
  46. #elif defined(__linux__) || defined (__APPLE__)  
  47.   
  48. #include <sys/time.h>  
  49. //构造函数  
  50. b2Timer::b2Timer()  
  51. {  
  52.     Reset();  
  53. }  
  54. //重置  
  55. void b2Timer::Reset()  
  56. {  
  57.     timeval t;  
  58.     gettimeofday(&t, 0);  
  59.     m_start_sec = t.tv_sec;  
  60.     m_start_msec = t.tv_usec * 0.001f;  
  61. }  
  62. //获取毫秒数  
  63. float32 b2Timer::GetMilliseconds() const  
  64. {  
  65.     timeval t;  
  66.     gettimeofday(&t, 0);  
  67.     return (t.tv_sec - m_start_sec) * 1000 + t.tv_usec * 0.001f - m_start_msec;  
  68. }  
  69.   
  70. #else  
  71.   
  72. b2Timer::b2Timer()  
  73. {  
  74. }  
  75.   
  76. void b2Timer::Reset()  
  77. {  
  78. }  
  79.   
  80. float32 b2Timer::GetMilliseconds() const  
  81. {  
  82.     return 0.0f;  
  83. }  
  84.   
  85. #endif  

通过宏的编译可以看出,window和类nuix上使用的内部API是不一样的,就像软件有debug和Release版本一样,有时候debug没问题,relase则不然,孰不知,它们在编译时编译器调用的程序很有可能是不同的。同时我们也要注意下,还有其他的类型的系统没有实现此类(估计一般人也碰不上)。

 

2、 调试辅助类b2Draw

调试辅助类主要辅助box2d中物体的调试,通过绘制不同的调试辅助的形状,来监控并改正物体行为的正确性。首先我们看下b2Draw.h文件。

[cpp]  view plain copy
  1. // 调试绘制的颜色,每个值都在[0,1]之间  
  2. struct b2Color  
  3. {  
  4.     /************************************************************************** 
  5.     * 功能描述:默认构造函数 
  6.     * 参数说明: (void) 
  7.     * 返 回 值: (void) 
  8.     ***************************************************************************/  
  9.     b2Color() {}  
  10.     /************************************************************************** 
  11.     * 功能描述:构造函数 
  12.     * 参数说明: r : 红色值部分 
  13.                  g :绿色值部分 
  14.                  b :蓝色值部分 
  15.     * 返 回 值: (void) 
  16.     ***************************************************************************/  
  17.     b2Color(float32 r, float32 g, float32 b) : r(r), g(g), b(b) {}  
  18.     /************************************************************************** 
  19.     * 功能描述:设置颜色函数 
  20.     * 参数说明: ri : 红色值部分 
  21.                  gi :绿色值部分 
  22.                  bi :蓝色值部分 
  23.     * 返 回 值: (void) 
  24.     ***************************************************************************/  
  25.     void Set(float32 ri, float32 gi, float32 bi) { r = ri; g = gi; b = bi; }  
  26.     //代表红、绿、蓝的变量  
  27.     float32 r, g, b;  
  28. };  
  29. //在b2World中实现并注册这个类,以便提供调试绘制不同的物理实体在你的游戏中  
  30. class b2Draw  
  31. {  
  32. public:  
  33.     /************************************************************************** 
  34.     * 功能描述:构造函数 
  35.     * 参数说明: (void) 
  36.     * 返 回 值: (void) 
  37.     ***************************************************************************/  
  38.     b2Draw();  
  39.     /************************************************************************** 
  40.     * 功能描述:析构函数 
  41.     * 参数说明: (void) 
  42.     * 返 回 值: (void) 
  43.     ***************************************************************************/  
  44.     virtual ~b2Draw() {}  
  45.   
  46.     enum  
  47.     {  
  48.         e_shapeBit              = 0x0001,   ///< 绘制形状  
  49.         e_jointBit              = 0x0002,   ///< 绘制关节联系  
  50.         e_aabbBit               = 0x0004,   ///< 绘制轴对齐边框  
  51.         e_pairBit               = 0x0008,   ///< 绘制broad-phase pairs  
  52.         e_centerOfMassBit       = 0x0010    ///< 绘制质心框架  
  53.     };  
  54.   
  55.     /************************************************************************** 
  56.     * 功能描述:设置绘制标志位 
  57.     * 参数说明: flags:标志 
  58.     * 返 回 值: (void) 
  59.     ***************************************************************************/  
  60.     void SetFlags(uint32 flags);  
  61.     /************************************************************************** 
  62.     * 功能描述:获得绘制标志位 
  63.     * 参数说明: (void) 
  64.     * 返 回 值: 绘制标志 
  65.     ***************************************************************************/  
  66.     uint32 GetFlags() const;  
  67.     /************************************************************************** 
  68.     * 功能描述:追加绘制标志位 
  69.     * 参数说明: flags:绘制标志 
  70.     * 返 回 值: (void) 
  71.     ***************************************************************************/  
  72.     void AppendFlags(uint32 flags);  
  73.     /************************************************************************** 
  74.     * 功能描述:从当前标志中清除标志 
  75.     * 参数说明: flags:绘制标志 
  76.     * 返 回 值: (void) 
  77.     ***************************************************************************/  
  78.     void ClearFlags(uint32 flags);  
  79.     /************************************************************************** 
  80.     * 功能描述:按照提供的顶点绘制逆时针方式闭合的多边形 
  81.     * 参数说明: vertices      :顶点 
  82.                  vertextexCount: 顶点数量 
  83.                  color         : 颜色 
  84.     * 返 回 值: (void) 
  85.     ***************************************************************************/  
  86.     virtual void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0;  
  87.     /************************************************************************** 
  88.     * 功能描述:按照提供的顶点绘制逆时针方式闭合的并填充颜色的多边形 
  89.     * 参数说明: vertices      :顶点 
  90.                  vertextexCount: 顶点数量 
  91.                  color         : 颜色 
  92.     * 返 回 值: (void) 
  93.     ***************************************************************************/  
  94.     virtual void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0;  
  95.     /************************************************************************** 
  96.     * 功能描述:绘制一个圆 
  97.     * 参数说明: center      :向量 
  98.                  radius      : 半径 
  99.                  color       : 颜色 
  100.     * 返 回 值: (void) 
  101.     ***************************************************************************/  
  102.     virtual void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color) = 0;  
  103.     /************************************************************************** 
  104.     * 功能描述:绘制一个填充颜色的圆 
  105.     * 参数说明: center      :向量 
  106.                  radius      : 半径 
  107.                  color       : 颜色 
  108.     * 返 回 值: (void) 
  109.     ***************************************************************************/  
  110.     virtual void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color) = 0;  
  111.     /************************************************************************** 
  112.     * 功能描述:绘制一段线段 
  113.     * 参数说明: p1      :开始点 
  114.                  p2      : 结束点 
  115.                  color   : 颜色 
  116.     * 返 回 值: (void) 
  117.     ***************************************************************************/  
  118.     virtual void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) = 0;  
  119.     /************************************************************************** 
  120.     * 功能描述:绘制一个变换,选择你的长度比例。 
  121.     * 参数说明:  xf  :变换 
  122.     * 返 回 值: (void) 
  123.     ***************************************************************************/  
  124.     virtual void DrawTransform(const b2Transform& xf) = 0;  
  125.   
  126. protected:  
  127.     //绘制标志  
  128.     uint32 m_drawFlags;  
  129. };  

通过代码我们可以看到有个b2Color的结构体的定义,它主要作为调试颜色使用的。

再看看b2Draw的实现部分

[cpp]  view plain copy
  1. //构造函数  
  2. b2Draw::b2Draw()  
  3. {  
  4.     m_drawFlags = 0;  
  5. }  
  6. //设置标志位  
  7. void b2Draw::SetFlags(uint32 flags)  
  8. {  
  9.     m_drawFlags = flags;  
  10. }  
  11. //获取标志位  
  12. uint32 b2Draw::GetFlags() const  
  13. {  
  14.     return m_drawFlags;  
  15. }  
  16. //追加标志位  
  17. void b2Draw::AppendFlags(uint32 flags)  
  18. {  
  19.     m_drawFlags |= flags;  
  20. }  
  21. //清除标志位  
  22. void b2Draw::ClearFlags(uint32 flags)  
  23. {  
  24.     m_drawFlags &= ~flags;  
  25. }  

通过观察b2Draw的实现,我们发现有点不对劲,定义的函数那么多,怎么实现就这几个函数呢?那其他的函数在哪里实现的呢?我们不禁要问难道是要我们使用者自己实现吗?真被我们猜中了,这个是要我们那实现的,可以看到没有实现的函数前面都有virtual做修饰,这就是虚函数,是等着用户自己用的时候去实现的,不能直接调用。

 

3、 Box2d设置

设置中主要定义了宏、常量、和一些辅助的公共函数。我们就来看看相关的定义。

在b2Settings.h文件中:

[cpp]  view plain copy
  1. //主要是因为有的编译器将提示相关语句的值是未使用的,  
  2. //所以你必须告诉它忽略所有(void)。  
  3. //即消除编译器的警告  
  4. #define B2_NOT_USED(x) ((void)(x))  
  5.   
  6. //对断言宏进行重新封装  
  7. #define b2Assert(A) assert(A)  
  8.   
  9. //重新封装类型,这样做为了方便而且很好的移植到不同的平台  
  10. typedef signed char int8;  
  11. typedef signed short int16;  
  12. typedef signed int int32;  
  13. typedef unsigned char uint8;  
  14. typedef unsigned short uint16;  
  15. typedef unsigned int uint32;  
  16. typedef float float32;  
  17. typedef double float64;  
  18. //float类型最大值  
  19. #define b2_maxFloat     FLT_MAX  
  20. //float类型最小值  
  21. #define b2_epsilon      FLT_EPSILON  
  22. //pi的值  
  23. #define b2_pi           3.14159265359f  
  24.   
  25. /// 全局常量参数 基于米-千克-秒(MKS)单位  
  26.   
  27. //碰撞  
  28.   
  29. //在两个凸形状上的接触点最大数量,不要修改它的值  
  30. #define b2_maxManifoldPoints    2  
  31.   
  32. //凸多边形的顶点数量的最大值。你不能将这个宏修改的太大,因为b2BolckAlloctor函数有一个物体内存大小的上限  
  33. #define b2_maxPolygonVertices   8  
  34.   
  35. //  用这个在动态树上填充AABB,它允许代理少量移动不必去调整这个树  
  36. //  单位是米  
  37. #define b2_aabbExtension        0.1f  
  38.   
  39. //  用这个在动态树上填充AABBs,这是基于当前位移用来预测未来的位置。  
  40. //  没有单位  
  41. #define b2_aabbMultiplier       2.0f  
  42.   
  43. //一个小的长度作为碰撞和约束误差,通常它被选为数字意义重大,但视觉上无足轻重。  
  44. #define b2_linearSlop           0.005f  
  45.   
  46. //一个小的角度作为碰撞和约束误差,通常它被选为数字意义重大,但视觉上无足轻重。  
  47. #define b2_angularSlop          (2.0f / 180.0f * b2_pi)  
  48.   
  49. ///半径的多边形/边缘形状的皮肤。这应该不会被修改。使  
  50. ///这意味着将有一个小的多边形数不足为连续碰撞缓冲。  
  51. ///使它更大的可能创建工件为顶点碰撞。  
  52. #define b2_polygonRadius        (2.0f * b2_linearSlop)  
  53.   
  54. ///在连续物理模拟里,在每次接触中子步骤的最大数值  
  55. #define b2_maxSubSteps          8  
  56.   
  57.   
  58. //动态  
  59. //接触的最大数用于处理解决一个撞击时间内的撞击  
  60. #define b2_maxTOIContacts           32  
  61.   
  62. //弹性碰撞的一个速度阈值,任何与一个相对线速度碰撞,低于这个阈值的将被视为非弹性碰撞  
  63. #define b2_velocityThreshold        1.0f  
  64.   
  65. //  线性速度位置的最大值校正当解决约束使用,这有助于阻止穿越物体  
  66. #define b2_maxLinearCorrection      0.2f  
  67.   
  68. //  角位置的最大值校正当解决约束使用,这有助于阻止穿越物体  
  69. #define b2_maxAngularCorrection     (8.0f / 180.0f * b2_pi)  
  70.   
  71. // 物体【刚体】的最大线速度,这限制是非常大的,用于防止数值问题。你不需要去适应这个  
  72. #define b2_maxTranslation           2.0f  
  73. #define b2_maxTranslationSquared    (b2_maxTranslation * b2_maxTranslation)  
  74.   
  75. // 物体【刚体】的最大线速度,这限制是非常大的,用于防止数值问题。你不需要去适应这个  
  76. #define b2_maxRotation              (0.5f * b2_pi)  
  77. #define b2_maxRotationSquared       (b2_maxRotation * b2_maxRotation)  
  78.   
  79. //这个比例因子控制怎样快速解决重叠问题。理想的情况下,这将是1,这样重叠将在一个时间步内被移除  
  80. #define b2_baumgarte                0.2f  
  81. #define b2_toiBaugarte              0.75f  
  82.   
  83.   
  84. // 休眠  
  85. //最小休眠时间  
  86. #define b2_timeToSleep              0.5f  
  87.   
  88. //刚体[body]要想休眠,线的最大值,即当角速度超过它时刚体[body]无法休眠。  
  89. #define b2_linearSleepTolerance     0.01f  
  90.   
  91. //刚体[body]要想休眠,角速度的最大值,即当角速度超过它时刚体[body]无法休眠。  
  92. #define b2_angularSleepTolerance    (2.0f / 180.0f * b2_pi)  
  93.   
  94. // 内存申请  
  95. //申请内存函数,实现这个函数作为你自己的内存分配器。  
  96. void* b2Alloc(int32 size);  
  97.   
  98. //释放内存函数,如果你实现b2Alloc,你也应该实现这个功能。  
  99. void b2Free(void* mem);  
  100.   
  101. //打印日志函数  
  102. void b2Log(const char* string, ...);  
  103. //版本编号方案  
  104. //见 http://en.wikipedia.org/wiki/Software_versioning  
  105. struct b2Version  
  106. {  
  107.     int32 major;        ///重大更新  
  108.     int32 minor;        ///较大更新  
  109.     int32 revision;     ///修复bug  
  110. };  
  111.   
  112. //box2d当前版本号  
  113. 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文件中的实现:

[cpp]  view plain copy
  1. //box2d当前版本号  
  2. b2Version b2_version = {2, 2, 1};  
  3. /************************************************************************** 
  4. * 功能描述:申请内存 
  5. * 参数说明:size : 申请大小 
  6. * 返 回 值: (void) 
  7. **************************************************************************/  
  8. void* b2Alloc(int32 size)  
  9. {  
  10.     return malloc(size);  
  11. }  
  12. /************************************************************************** 
  13. * 功能描述:释放内存 
  14. * 参数说明:mem : 内存头 
  15. * 返 回 值: (void) 
  16. **************************************************************************/  
  17. void b2Free(void* mem)  
  18. {  
  19.     free(mem);  
  20. }  
  21. /************************************************************************** 
  22. * 函数名称:b2Log 
  23. * 功能描述:打印log 
  24. * 参数说明:string :打印字符串 
  25.             ...    :参数列表 
  26. * 返 回 值: (void) 
  27. **************************************************************************/  
  28. void b2Log(const char* string, ...)  
  29. {  
  30. #if defined(SHP)  
  31.     #ifdef _DEBUG  
  32.     __App_info(__PRETTY_FUNCTION__ , __LINE__, string);  
  33.     #endif  
  34. #else  
  35.     va_list args;  
  36.     va_start(args, string);  
  37.     vprintf(string, args);  
  38.     va_end(args);  
  39. #endif  
  40. }  

通过这过我们可以看到,我们使用的是box2d 版本号2.2.1,接下来是对c中内存管理函数malloc和free函数的封装,好处就是如果使用了不同与malloc/free的接口,我们可以在此次快速的替换。而不需要找其他任何文件。

 

公共部分终于讲完了,下面我们将会学习碰撞部分。以上部分,根据本人理解所写,若有不妥或错误之处,还请大家多多指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值