cocos2d 中有很多中关节类,关节是为了让两个独立物体之间建立某种联系,使之犹如一体
常见的关节类有:
PhysicsJointXXX
类 | 含义 | 举例说明 |
---|---|---|
PhysicsJointDistance | 设定两个刚体间的固定距离 | |
PhysicsJointFixed | 将两个刚体结合在了一起 | |
PhysicsJointGear | 使一对刚提的角速度比率保持一定比例 | 比如齿轮 |
PhysicsJointGroove | 一个刚体连到线上,另一个连到点上 | |
PhysicsJointLimit | 限制两个刚体间的最大距离 | 比如流星锤 |
PhysicsJointMotor | 两个刚体的相对角速度保持一个常数 | |
PhysicsJointPin | 两个刚体独立的围绕锚点进行旋转 | |
PhysicsJointRatchet | 与套筒扳手的工作类似,单向旋转,不能转回来,比如自行车的飞轮,正想踏实有动力的,反向是没有动力的 | |
PhysicsJointRotoryLimit | 与限制关节类似,增加了自旋 | 地球绕太阳运动(地球同时在自旋)) |
PhysicsJointRotarySpring | 与弹簧关节相似,增加自旋 | 汽车的悬挂系统 |
PhysicsJointSpring | 永泰黄来连接两个物理刚体 |
使用方式 (绳子为例)
使用 PhysicsJointDistance 将多个节点连接起来,实现绳子下落摆动的效果
基本步骤:
- 固定一个端点,并且设置body
- 循环增加节点,将节点addChild() 添加到场景中
- 相邻选两个节点创建一个关节 PhysicsJointDistance::cons
- 将关节 添加到PhysicsWorld对象 中
demo代码片段:
#include "HelloWorldScene.h"
#include "cocostudio/CocoStudio.h"
#include "ui/CocosGUI.h"
USING_NS_CC;
using namespace cocostudio::timeline;
#define PHYSICS_MATERIAL1 PhysicsMaterial(1,1,0)
#define PHYSICS_MATERIAL2 PhysicsMaterial(1,0,0)
PhysicsWorld * world;
Scene* HelloWorld::createScene()
{
// 'scene' is an autorelease object
//auto scene = Scene::create();
// 创建带物理特性的世界
auto scene = Scene::createWithPhysics();
world = scene->getPhysicsWorld();
scene->getPhysicsWorld()->setGravity(Vec2(0, -980));
//scene->getPhysicsWorld()->setAutoStep(false);
//PhysicsWorld::DEBUGDRAW_JOINT
//scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);
// 'layer' is an autorelease object
auto layer = HelloWorld::create();
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
// on "init" you need to initialize your instance
bool HelloWorld::init()
{
// 1. super init first
if ( !Layer::init() )
{
return false;
}
/* auto rootNode = CSLoader::createNode("MainScene.csb");
addChild(rootNode);*/
Size visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
auto rootNode = CSLoader::createNode("MainScene.csb");
Sprite * edgeBox = dynamic_cast<Sprite*>(rootNode->getChildByName("Default"));
auto edgeBody = PhysicsBody::createEdgeBox(visibleSize, PHYSICS_MATERIAL1,3);
edgeBody->setDynamic(false);
edgeBox->setPhysicsBody(edgeBody);
addChild(rootNode);
// 使用关节 实现绳子效果
Sprite * nodes[10];
PhysicsBody * bodys[10];
PhysicsJointDistance * pjd[10];
// 1. 固定第一个节点
nodes[0] = Sprite::create();
Vec2 point(visibleSize.width / 2, 9* visibleSize.height /10);
nodes[0]->setPosition(point);
addChild(nodes[0]);
bodys[0] = PhysicsBody::createCircle(20, PHYSICS_MATERIAL1);
bodys[0]->setCategoryBitmask(0);
bodys[0]->setDynamic(false);
nodes[0]->setPhysicsBody(bodys[0]);
for (int i = 1; i < 10; i++) {
nodes[i] = Sprite::create("rope05HA.png");
nodes[i]->setPosition(point.x+40*i,point.y);
addChild(nodes[i]);
bodys[i]= PhysicsBody::createCircle(20, PHYSICS_MATERIAL1);
bodys[i]->setCategoryBitmask(0);
nodes[i]->setPhysicsBody(bodys[i]);
pjd[i - 1] = PhysicsJointDistance::construct(bodys[i - 1], bodys[i], Vec2(18,0), Vec2(-18, 0));
world->addJoint(pjd[i - 1]);// 将关节加入世界
}
return true;
}
效果(这是失败的效果):

解决:
出现问题是因为在设置关节时,设置前后两个节点的关节作用锚点位置弄错了,都弄到各自的中心去了
一个节点的尺寸是 40x18 的
A-B
中间的**-** 表示关节
我们想做的当然是A的末端与B的起端相连接,达到下面的效果
而锚点默认是在sprite 的中间,也就是(0.5,0.5) //这是按照尺寸的百分比来的
锚点位置坐标也可以小于0,也可以大于1,也就是说锚点可以不在sprite 内部
pjd[i - 1] = PhysicsJointDistance::construct(bodys[i - 1], bodys[i], Vec2(18,0), Vec2(-18, 0));
// 由于 每个节点的尺寸都是40*18 ,我们通过指定关节连接作用的相对于锚点的一个位置.建立连接
Vec2(18,0): 关节的第一个点作用于A节点的相对于锚点靠右18个像素的位置
Vec2(-18,0):关节的第二个点作用于B节点的相对于锚点靠左18个像素的位置
达到的效果大体是A节点的末端与B节点的起端相连接,这点可以指定
scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL); 来观察
开启 scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);
效果:
如果把那个相对位置设置大一些,可能更加直观,看出相邻两个节点的之间的关节作用位置(图中绿色的点)
设置为30吧
成功的效果:
完整的资源以及代码已上传至github
https://github.com/TopForethought/cocos2dx/tree/master/关节绳子
后序会尝试做一个带有悬挂系统的越野车,哈哈!
蹦蹦救护车已上线
代码资源:
https://github.com/TopForethought/cocos2dx/tree/master/关节-蹦蹦车