cocos2d-x物理空间与现实空间的实现及联系

用cocos-2dx制作跑酷类游戏时,会遇到物理空间与现实空间如何实现和联系的问题,以下代码实现了游戏人物在脚下没有砖块时掉落的场景。

1、实现现实空间

在类定义里添加下面两个函数,分别表示进入和退出时执行的动作:

void onEnter() override;
void onExit() override;

onEnter()函数:

cpSpace *m_space;
m_space =cpSpaceNew();//创建物理空间
cpVect gravity = {0.0f,-350.0f};//把重力设置成(0,-350)
cpSpaceSetGravity(m_space,gravity);

onExit()函数:

cpSpaceFree(m_space);
m_space=nullptr;

注:创建和物理空间有关的对象,或是那些以cp开头类型的队形都要手工释放。

由于onEnter() 和 onExit() 函数是在 Node 里定义的,此处覆盖了父类的函数(override 为C++ 11 新增),故此处还需调用父类的函数,让它做本来要做的事。
在onEnter() 最开始,加上:

Node::onEnter();

在onExit() 最后,加上:

Node::onExit();

物理空间里的”物体“有质量,速度,受力,惯性力矩等等属性
一个 body 可以由 零至多个形状 shape 组成
物理引擎用形状进行碰撞检测(比如碰到地面甚至陷入,那么就停止运动,甚至拔出来,虽然不会显示出来,但是物理引擎内部是这样做的)

2.实现物理空间

首先,在类定义里加两个变量:

cpBody *m_playerBody;
cpShape *m_playerShape;

然后,在init() 函数里初始化它们:
这里写图片描述
在 m_player 创建的后,用以下语句获取 m_player的大小 playerSize:

auto playerSize = m_player->getContactSize();

创建body:

m_body = cpBodyNew(1.0f,cpMomentForBox(1.0f, contentSize.width, contentSize.height));
//两个1.0f 都表示 质量,第三个参数求惯性力矩
contentSize -> playerSize;
m_body -> m_playerBody;
cpVect bodyPos = { 50.0f, 300.0f };
cpBodySetPos(m_body, bodyPos);//设置m_playerBody 的初始位置
cpSpaceAddBody(m_space, m_playerBody);//把m_playerBody 加入 space 中
m_playerShape = cpBoxShapeNew(m_playerBody, playerSize.width, playerSize.height);//创建一个矩形 shape
cpSpaceAddShape(m_space, m_playerShape);//把 m_playerShape 加入space,shape 在创建时就已指定了是在 m_playerBody 中,此处是为了指示space那是个矩形

至此,这个 m_playerBody是物理引擎来管理的,它与玩家m_player 没有任何关联,而接下来我们要把他们关联起来。


3.实现物理空间与现实的关联

在类定义里:

Sprite *m_player -> PhysicsSprite *m_player;
//把下面这一行也换成 PhysicsSprite
m_player = Sprite::create("player.png");
//在把 m_playerShape 加入space后加上以下语句
m_player->setCPBody(m_playerBody);

为了方便,在刚刚所有代码的后面,加入一个“物理调试节点”:

auto debugNode = PhysicsDebugNode::create(m_space);
this->addChild(m_debugNode, 10);//最后那个10是Z-order,表示绘制顺序所有Z-order小于10的元素都会在它之前画,以至于被它遮盖起来

运行程序后发现很多错误,init会在onEnter之前执行,而那时m_space还没有创建好。故把刚刚所有的代码(从m_player创建开始到物理节点添加结束)剪切到onEnter()的后面。

而 rootNode 为局部变量,故在类定义里增加一个变量:Node *m_rootNode;
把cpp文件里的所有rootNode都改成m_rootNode, 在auto rootNode那一行去掉auto;
画红线处所示
源代码中 setPosition 是这样实现的,而这时CPBody还没有设置,而且runAction也调用了setPosition,去掉 setPosition那一行,删掉

auto moveby = MoveBy::create(3.0, Vec2(860,0));
m_player->runAction(moveby);

此时程序可以运行,而框(人物)是没有动的。因为此时还在用cocos2d-x的动画机制在推着m_player动,接下来应该换成物理引擎了;
在 Update() 里,要物理引擎更新世界的状态:
这里写图片描述
接下来,把地面加入物理世界,它是静态的。
在类定义里声明一个变量:cpShape *m_ground1;
在onEnter() 后加入:

cpVect beginPoint = {0, 200.0f};
cpVect endPoint = {300.0f, 200.0f};
m_ground = cpSegmentShapeNew(cpSpaceGetStaticBody(m_space), beginPoint, endPoint, 0.0f);
cpSpaceAddStaticShape(m_space, m_ground);

接下来在onEnter() 的最后,赋予玩家一个初速度:

cpVect j= {120.0f, 0.0f};
cpBodyApplyImpulse(m_playerBody, j, cpvzero);

最后,手工释放所有的物理对象

cpShapeFree(m_shape);
m_shape = nullptr;
cpBodyFree(m_body);
m_body = nullptr;

猜你喜欢

转载自blog.csdn.net/marilynmontu/article/details/79596625