~~~~我的生活,我的点点滴滴!!
文章的分析我不说了,全在代码里面,贴出重要的代码,里面有注释,完整的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);
}
简单的贴了点代码,大家可以自己下载后运行看看。
效果图如下: