~~~~我的生活,我的点点滴滴!!
文章的分析我不说了,全在代码里面,贴出重要的代码,里面有注释,完整的demo代码下载链接地址:点击打开链接
1、触摸开始代码:
bool HelloWorld::onTouchBegan(Touch *touch, Event *unused_event) { auto touchPosition = touch->getLocation(); m_dragOffStartX = touchPosition.x; m_dragOffStartY = touchPosition.y; m_ballX = m_dragOffStartX; m_ballY = m_dragOffStartY; if( m_existBall ) { m_world->DestroyBody(m_body); } //这样设置后,会有一个瞬变的过程,即球突然现在你鼠标点的地方 m_ball->setPosition(m_ballX, m_ballY); return true; }
2、触摸移动
在鼠标按下后,不停的移动时会显示出一个弹道,这是球将要进行的移动轨道,弹道的模拟显示主要在下面的代码中:
void HelloWorld::onTouchMoved(Touch *touch, Event *unused_event) { auto touchPosition = touch->getLocation(); m_dragOffEndX = touchPosition.x; m_dragOffEndY = touchPosition.y; float dragDistX = m_dragOffStartX - m_dragOffEndX; float dragDistY = m_dragOffStartY - m_dragOffEndY; //显示dot图片模拟出来的弹道,也就是球走的轨道 simulateTrajectory(b2Vec2(dragDistX * POWER / PTM_RATIO, dragDistY * POWER / PTM_RATIO)); } void HelloWorld::simulateTrajectory(b2Vec2 vec) { int velocityIterations = 10; int positionIterations = 8; //此函数反复创建刚体,但是要注意了,后面一定要根着刚体的摧毁 //不然会内存泄露的,因为他不停的指定新的内存块,旧的内存块直 //接成为野空间了。 defineBall(); //给刚体一个速度,这样下面的m_dots在设置位置时就各不相同了 m_body->SetLinearVelocity(vec); for(int i = 0 ;i < DOTSNUM; ++ i) { m_world->Step(m_deltaTime, velocityIterations, positionIterations); log("%f %f", m_body->GetPosition().x, m_body->GetPosition().y); //由于上面给刚体一个速度,所以这里的GetPosition()返回的值是不同的。 m_dots.at(i)->setPosition(m_body->GetPosition().x * PTM_RATIO, m_body->GetPosition().y * PTM_RATIO); //清空所有施加在物体上的力,这样可以分步清楚的看到物体的运动, //在同一个力场完成多个分步。 m_world->ClearForces(); } //配合defineBall() m_world->DestroyBody(m_body); }
simulateTrajectory()模拟了刚体和球一起运行的轨迹,用dot显示出来,然后摧毁掉刚体,在触摸结束里面真正运行此轨迹。
3、触摸结束
触摸结束后,应该显示球顺着这弹道移动,代码如下:
void HelloWorld::onTouchEnded(Touch *touch, Event *unused_event) { m_existBall = true; //此处的配对摧毁在onTouchBegan里面 defineBall(); auto touchPosition = touch->getLocation(); m_dragOffEndX = touchPosition.x; m_dragOffEndY = touchPosition.y; float dragDistX = m_dragOffStartX - m_dragOffEndX; float dragDistY = m_dragOffStartY - m_dragOffEndY; //水平与竖直方面的速度 m_body->SetLinearVelocity(b2Vec2(dragDistX * POWER / PTM_RATIO, dragDistY * POWER / PTM_RATIO)); }
4、更新
cocos2dx本身的update函数会刷新帧,为了让刚体和物体一起移动,需要在里面这样设置:
void HelloWorld::update(float dt) { //迭代次数控制了约束求解器扫描世界中所有接触和连接器的次数。 //更多的迭代总是能够产生更高质量的模拟。但是不要为一个小的 //时间步长设置一个大的迭代数。60Hz搭配10次迭代要远好于30Hz //搭配20次迭代。 int velocityIterations = 10; int positionIterations = 8; m_world->Step(dt, velocityIterations, positionIterations); m_deltaTime = dt; //更新精灵与刚体的位置同步 for(b2Body *b = m_world->GetBodyList(); b; b=b->GetNext()) { if( b && b->GetUserData() ) { auto sprite = (Sprite*)b->GetUserData(); //Box2D定义的物体有三个约束,X方向,Y方向及旋转角度 //X方向,Y方向 sprite->setPosition(Point(b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO)); //旋转角度 sprite->setRotation(-1 * CC_RADIANS_TO_DEGREES(b->GetAngle())); //这样模拟的更真实 } } //清空所有施加在物体上的力,这样可以分步清楚的看到物体的运动, //在同一个力场完成多个分步。 m_world->ClearForces(); //重新显示DebugDraw框 m_world->DrawDebugData(); }
5、绑定刚体与精灵
刚体是属于Box2D的,精灵是属于cocos2dx,那么他们怎么合为一体了,看下面代码:
void HelloWorld::defineBall() { b2BodyDef bodyDef; bodyDef.type = b2_dynamicBody; //这里的useData是个void*,那意味可以存放任何类型 //这里把精灵对象给他了,他们成功绑定。 bodyDef.userData = m_ball; log("ball:%f %f",m_ballX,m_ballY); //设置刚体和精灵相同位置,这样看起来才像一体吗 bodyDef.position.Set(m_ballX / PTM_RATIO, m_ballY / PTM_RATIO); b2CircleShape circleShape; //图片是90x90的,所以我们的半径为45 circleShape.m_radius = BALLSIZE * 0.5 / PTM_RATIO; b2FixtureDef fixtureDef; //密度 fixtureDef.density = 10.0f; fixtureDef.shape = &circleShape; //摩擦力0-1范围 fixtureDef.friction = 0.6f; //恢复力0-1范围 fixtureDef.restitution = 0.4f; m_body = m_world->CreateBody(&bodyDef); m_body->CreateFixture(&fixtureDef); //抵消重力,这是新版本新加的至少在v2.2.1 //以前的版本是在Step()不停的施加反向力,那样耗时 //这样设置后,刚体就悬浮的 m_body->SetGravityScale(9.8f); }
简单的贴了点代码,大家可以自己下载后运行看看。