瘸腿蛤蟆原创笔记,欢迎转载,转载请标明出处:
上篇回顾
本篇名言:凡是内心能够想到、相信的,都是可以达到的。 [Napoleon Hill]
在最早的时候,蛤蟆学习过cocos2d-x示例架构。这次在这个基础上,蛤蟆要学习Box2dTestBed这个物理引擎的DEMO架构。这样大家可以自己深入研究之了。
架构详解
首先从我们点到controller.cpp文件中。找到第43行如下:
{ "Box2d - TestBed", []() {return new Box2dTestBedScene(); } },
通过这行,我们跟踪 Box2dTestBedScene到Box2dView.h头文件中。这个文件是在
\cocos2d-x-3.2\tests\cpp-tests\Classes\Box2DTestBed\目录中的。
该头文件中,定义了3个类,1个结构体,1个结构体。
三个类是:
Box2dTestBedScene: 这个类继承于TestScene类,这个类大家可以看蛤蟆之前的cpptests框架的笔记,不过这个我们现在不用去管它,主要记住是继承于CCScene类的即可,不会对我们理解有任何影响。这个类只有一个runThisTest()函数。
MenuLayer:
这个类也继承于Layer,定义了事件监听变量,定义了restartCallback,nextCallback,nextCallback这3个函数用于实现Box2d测试用例的切换。不过我们主要理解函数menuWithEntryID和initWithEntryID。menuWithEntryID这个函数会调用initWithEntryID,并返回MenuLayer类指针。而initWithEntryID函数用来初始化Layer,添加菜单图片,注册菜单等事件,最后调用Box2DView。
Box2DView: 这个类继承于Layer类。定义并实现了触摸函数,按键函数。还定义了一个变量CustomCommand,该类继承于RenderCommand,来自文件\cocos2d-x-3.2\cocos\renderer。是源码自带的,该类的主要作用是 渲染物理(正如它的类名字,在此先不过多展开,展开多了就收不回来了哈)。此外就是其初始化函数了initWithEntryID 和 viewWithEntryID 。viewWithEntryID 调用initWithEntryID 并返回Box2DView 类指针。initWithEntryID实现 初始化Layer层,定义了监听函数,注册监听函数,不过最主要的还是调用Box2dTestBed中的具体用例,例如RayCast::Create。
OK,接着我们讲下那个结构体和类:TestEntry; 这个结构体定义在Test.h文件中,如下:
struct TestEntry
{
constchar*name;
TestCreateFcn *createFcn;
};这个结构体很明显一个是测试用例的名字,另一个是一个类指针,指向test类。Test类也定义在Test.h文件中。 这个是Box2DView测试用例的基类。我们来看下这个test类。
Test类
这个类是所有测试用例的基类,继承于b2ContactListener类,这个类由源码实现,主要是用于实现后获取碰撞信息。由4个虚函数组成,virtualvoidBeginContact(b2Contact*contact),virtualvoidEndContact(b2Contact*contact),virtualvoidPreSolve(b2Contact*contact, const b2Manifold* oldManifold),virtual void PostSolve(b2Contact*contact, const b2ContactImpulse*impulse)。
Test类中继承了这个4个虚函数,但是本身并没有去全部实现它(只实现了PreSolve 函数)其他的通过具体的测试示例来实现的。此外test类还定义了几个虚函数,需要具体的测试示例自己实现它。其他的函数和变量时所有测试示例都通用的类。这个Test的构造函数,会创建一个物理的世界。析构函数会摧毁这个物理的世界。
OK,接下去我们梳理下整体的调用步骤如下:
首先从controller.cpp文件中的第43行
{ "Box2d - TestBed", []() {return new Box2dTestBedScene(); } },
跳跃到Box2dTestBedScene类(这个类在Box2dView.h文件中),该类只有一个函数runThisTest();
函数如下:
void Box2dTestBedScene::runThisTest() { addChild(MenuLayer::menuWithEntryID(0)); Director::getInstance()->replaceScene(this); } |
这个函数会调用MenuLayer::menuWithEntryID() ,创建一个MenuLayer类,并初始化它。
在MenuLayer::menuWithEntryID 函数中,还会调用initWithEntryID 函数。
函数如下:
MenuLayer* MenuLayer::menuWithEntryID(intentryId) { auto layer =new MenuLayer(); layer->initWithEntryID(entryId); layer->autorelease(); return layer; } |
initWithEntryID 函数会创建Box2dView类。函数如下:
bool MenuLayer::initWithEntryID(intentryId) { auto director =Director::getInstance(); Vec2 visibleOrigin = director->getVisibleOrigin(); Size visibleSize = director->getVisibleSize(); m_entryID = entryId; Box2DView* view =Box2DView::viewWithEntryID(entryId ); addChild(view, 0, kTagBox2DNode); ………………….//此处省略 return true; } |
创建Box2DView这个类的时候,首先是运行Box2DView::viewWithEntryID ,该函数调用initWithEntryID 函数。如下图
Box2DView* Box2DView::viewWithEntryID(intentryId) { Box2DView* pView =new Box2DView(); pView->initWithEntryID(entryId); pView->autorelease(); return pView; } |
在initWithEntryID
中最终指向具体的测试类,如RayCast类。
bool Box2DView::initWithEntryID(intentryId) { m_entry = g_testEntries + entryId; m_test = m_entry->createFcn();//就是此处实现跳转 ….. return true; } |
总结
OK,终于完成了。洗洗睡去了。