Box2D C++ 教程-旋转到指定角度
2014-04-11 13:01
337 查看
转载文章:原贴地址:http://ohcoder.com/blog/2012/11/30/given-angle/
旋转指定角度这个话题和之前的那个话题类似,只不过把直线运动改成旋转运动。旋转一个物体既可以直接设置角度也可以通过设置扭矩/冲量方法来实现,同样需要注意的问题是,如果直接设置物体的角度,其实并不算是真正的模拟物理场景。
为了做这个实验我们需要一个动态物体,如果没有重力的影响效果更好,那样物体可以停留在屏幕上。我们会给物体附加一个具有不同方向的定制器,这样我们可以查看物体是否面向正确的方向。让我们就像设置“尖尖的”定点一样设置一个多边形:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | b2Body* body; FooTest() { //body definition b2BodyDef myBodyDef; myBodyDef.type = b2_dynamicBody; //hexagonal shape definition b2PolygonShape polygonShape; b2Vec2 vertices[6]; for (int i = 0; i < 6; i++) { float angle = -i/6.0 * 360 * DEGTORAD; vertices[i].Set(sinf(angle), cosf(angle)); } vertices[0].Set( 0, 4 ); //change one vertex to be pointy polygonShape.Set(vertices, 6); //fixture definition b2FixtureDef myFixtureDef; myFixtureDef.shape = &polygonShape; myFixtureDef.density = 1; //create dynamic body myBodyDef.position.Set(0, 10); body = m_world->CreateBody(&myBodyDef); body->CreateFixture(&myFixtureDef); //zero gravity m_world->SetGravity( b2Vec2(0,0) ); } |
设置物体的点,使其朝向我们,然后设置鼠标输入方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | //class member variable //class member variable b2Vec2 clickedPoint; //in class constructor clickedPoint = b2Vec2(0,20);//initial starting point //override parent class void MouseDown(const b2Vec2& p) { //store last mouse-down position clickedPoint = p; //do normal behaviour Test::MouseDown( p ); } //inside Step() glPointSize(4); glBegin(GL_POINTS); glVertex2f( clickedPoint.x, clickedPoint.y ); glEnd(); |
这个点将会移到鼠标最后一次单击的地方。在场景中这也是一种默认的拖拽动作,虽然有一点点怪异但是还是比较好的满足了我们的需求。
直接设置角度
使用SetTransform方法来设置角度非常简单,但是首先我们需要知道设置多少个角度,给定物体本地的坐标点以及本地的目标点。然后添加到每帧都会调用的Step()方法:
1 2 3 4 5 6 7 8 9 10 | //in Step() function float bodyAngle = body->GetAngle(); b2Vec2 toTarget = clickedPoint - body->GetPosition(); float desiredAngle = atan2f( -toTarget.x, toTarget.y ); //view these in real time m_debugDraw.DrawString(5, m_textLine, "Body angle %.3f", bodyAngle * RADTODEG); m_textLine += 15; m_debugDraw.DrawString(5, m_textLine, "Target angle %.3f", desiredAngle * RADTODEG); m_textLine += 15; |
现在我们看到是如何计算行为角度的,尝试使用SetTransform方法可以让物体指向目标点,而且你会看到物体自己会立刻指向目标点。
1 | body->SetTransform( body->GetPosition(), desiredAngle ); |
试着抛出物体,之后它会慢慢接近目标点,然后你会看到这个方法所带来负面影响,物体不会像真实的物理世界一样进行模拟。我发现物体要么会远离目标点,要么以某种轨迹绕着目标点进行旋转。这是因为质心稍稍偏了的缘故,而且我认为当我们在上一帧 直接设置角度并计算的时候,角速度已经变成了无效的。在任何情况下,我们都应该注意,通过设置角速度为零来消除上一帧所引起的问题,例如:
1 | body->SetAngularVelocity(0); |
12 | float totalRotation = desiredAngle - bodyAngle; float change = 1 * DEGTORAD; //allow 1 degree rotation per time step float newAngle = bodyAngle + min( change, max(-change, totalRotation)); body->SetTransform( body->GetPosition(), newAngle ); |
12 | while ( totalRotation < -180 * DEGTORAD ) totalRotation += 360 * DEGTORAD; while ( totalRotation > 180 * DEGTORAD ) totalRotation -= 360 * DEGTORAD; |
使用扭矩
为了达到一个更真实的物理世界,可以使用扭矩来作用于物体让其旋转:我们可以这样开始:
12 | float totalRotation = desiredAngle - bodyAngle; |
既然问题是由当前角速度引起,并随着以后的时间步长所影响着。我们可以不施加扭矩情况下,计算下一帧物体的角度-这就可以知道-在没有外界作用的情况下物体会怎样变化-然后将其用在当前角度(testbed默认是60Hz):
12 | float nextAngle = bodyAngle + body->GetAngularVelocity() / 60.0; float totalRotation = desiredAngle - nextAngle;//use angle in next time step body->ApplyTorque( totalRotation < 0 ? -10 : 10 ); |
1 | float nextAngle = bodyAngle + body->GetAngularVelocity() / 3.0;// 1/3 second |
使用公式T=Iv/t,其中T是我们想要知道的扭矩,I是物体的转动惯量,v是角速度以及t是我们将要使用扭矩作用的时间,像之前一样:
12 | float nextAngle = bodyAngle + body->GetAngularVelocity() / 60.0; |
更新:如果物体的质心没有在其原点上,那么这种方法将不能正确的工作,例如这里所实现的方式:(。当前Box2D API只能允许访问原点作为物体的中心,我们只能在质心上对物体施加扭矩。希望在Box2D以后的版本中API可以灵活设置质心,以此来调整惯性。
使用冲量
就像最近话题中所说的那样,类似于上面的代码使用冲量可以达到瞬间移动的效果,但是不加时间系数:
12 | float nextAngle = bodyAngle + body->GetAngularVelocity() / 60.0; |
12 | float nextAngle = bodyAngle + body->GetAngularVelocity() / 60.0; |
相关文章推荐
- Box2D C++ 教程-旋转到指定角度
- BOX2D 自然的旋转到一个指定角度
- BOX2D 自然的旋转到一个指定角度
- BOX2D 自然的旋转到一个指定角度
- Box2D C++教程11-旋转指定角度
- box2d 旋转到指定角度
- Box2D C++ 教程-连接器-旋转
- Box2D C++教程16-碰撞剖析
- OX2D 自然的旋转到一个指定角度
- Box2D C++教程 第四节:创建测试
- Box2D C++ 教程-使用debug Draw
- Box2D C++教程3-testbed的结构
- Box2D C++教程6-定制器(Fixtures)
- Cocos2D旋转炮塔到指定角度(一)
- c++实现图像旋转任意角度
- Box2D C++ 教程-画自己的图像
- Box2D C++ 教程-射线投射
- 【Unity3d基础】Unity3d 中如何旋转一张2D图片到指定角度
- Box2D C++教程4-创建测试
- Cocos2D旋转炮塔到指定角度(一)