解决方式:
引擎版本:cocos2d2.1beta3 + box2d 2.2.1
可以有两种方式
1 b2PolygonShape 绘制 (缺点:每段刚体的大小可能不会一直,有误差)
2 b2EdgeShape绘制 (缺点:1 没找到旋转方式,问题待解决。。。 2 与b2EdgeShape绘制的地面不发生碰撞 3 鼠标关节不能移动该刚体)
两种方法其实很类似
思路:1 保存鼠标 按下及移动时的点坐标
2 通过点坐标绘制刚体
1 保存两点坐标而且还需要一些其他的值 比如:两点间距离 /两点间中心点/两点相减所构成的向量旋转角度等 而且还涉及到cocos2d-x坐标系与box2d坐标系的数值转换问题,所以我将其封装成一个类,以方便获取相应的值 (类并不全面,而且有些实现可能会有更方便的方法,希望有各位多多指点)代码如下:
///
.h 文件
#ifndef _BODYSEGMENT_H_
#define _BODYSEGMENT_H_
//像素比米比例 1米=32像素
#define PTM_RATIO 32
#include "cocos2d.h"
#include "Box2D/Box2D.h"
using namespace cocos2d;
class BodySegment
{
public:
//根据传入的两个点 计算所需要的值
BodySegment(CCPoint p1, CCPoint p2);
~BodySegment();
//将中心点位置由 CCPoint转换为b2Vec类型
void ConvertPointTob2Vec(CCPoint cp);
//返回第一个点 cocos2d-x下坐标
CCPoint ccpos_GetPoint1();
//返回第二个点 cocos2d-x下坐标
CCPoint ccpos_GetPoint2();
//返回转换为b2vec的point1
b2Vec2 b2pos_vGetPoint1();
//返回转换为b2vec的point2
b2Vec2 b2pos_vGetPoint2();
//返回第一个点 box2d-x下坐标
CCPoint b2pos_GetPoint1();
//返回第二个点 box2d-x下坐标
CCPoint b2pos_GetPoint2();
//返回中心点 cocos2d-x下坐标
b2Vec2 ccpos_GetCenter();
//返回中心点 box2d-x下坐标
b2Vec2 b2pos_GetCenter();
//返回中心点X坐标 cocos2d-x下坐标
float ccpos_GetCenterX();
//返回中心点X坐标 box2d-x下坐标
float b2pos_GetCenterX();
//返回中心点Y坐标 cocos2d-x下坐标
float ccpos_GetCenterY();
//返回中心点Y坐标 box2d-x下坐标
float b2pos_GetCenterY();
//返回两点相减后的向量旋转弧度
float GetAngle();
//返回两点间的长度 标量
float cc_GetLength(); //cocos2d-x中的长度
float b2_GetLength(); //box2d中的长度
private:
//两个点
CCPoint m_cpPoint1;
CCPoint m_cpPoint2;
//将两个点转换为b2vec 并且为box2d坐标
b2Vec2 m_bvPoint1;
b2Vec2 m_bvPoint2;
//两点中心位置
CCPoint m_cCenter; //CCPoint类型用于两点计算值
b2Vec2 m_vCenter; //由CCPoint类型转换
//向量旋转的弧度
float m_fAngle;
//两点间的长度
float m_fLength;
};
#endif
/
.cpp 文件
#include "BodySegment.h"
//根据传入的两个点 计算所需要的值
BodySegment::BodySegment(CCPoint p1, CCPoint p2)
{
//点坐标为cocos2d坐标系坐标
m_cpPoint1 = p1;
m_cpPoint2 = p2;
//计算两点的中心点
m_cCenter = ccpMidpoint(m_cpPoint1,m_cpPoint2);
//给m_vCenter 赋值
ConvertPointTob2Vec(m_cCenter);
//两点旋转的弧度值 两点相减求出向量后计算旋转角度
m_fAngle = ccpToAngle(ccpSub(m_cpPoint2,m_cpPoint1));
//求出两点间距离
m_fLength = ccpDistance(m_cpPoint1,m_cpPoint2);
}
BodySegment::~BodySegment()
{
}
//将中心点位置由 CCPoint转换为b2Vec类型
void BodySegment::ConvertPointTob2Vec(CCPoint cp)
{
m_vCenter.x = cp.x;
m_vCenter.y = cp.y;
}
//返回第一个点 cocos2d-x下坐标
CCPoint BodySegment::ccpos_GetPoint1()
{
return m_cpPoint1;
}
//返回第二个点 cocos2d-x下坐标
CCPoint BodySegment::ccpos_GetPoint2()
{
return m_cpPoint2;
}
//返回转换为b2vec的point1
b2Vec2 BodySegment::b2pos_vGetPoint1()
{
m_bvPoint1.x = m_cpPoint1.x/PTM_RATIO;
m_bvPoint1.y = m_cpPoint1.y/PTM_RATIO;
return m_bvPoint1;
}
//返回转换为b2vec的point2
b2Vec2 BodySegment::b2pos_vGetPoint2()
{
m_bvPoint2.x = m_cpPoint2.x/PTM_RATIO;
m_bvPoint2.y = m_cpPoint2.y/PTM_RATIO;
return m_bvPoint2;
}
//返回第一个点 box2d-x下坐标
CCPoint BodySegment::b2pos_GetPoint1()
{
CCPoint b2Point1;
b2Point1.x = m_cpPoint1.x/PTM_RATIO;
b2Point1.y = m_cpPoint1.y/PTM_RATIO;
return b2Point1;
}
//返回第二个点 box2d-x下坐标
CCPoint BodySegment::b2pos_GetPoint2()
{
CCPoint b2Point2;
b2Point2.x = m_cpPoint2.x/PTM_RATIO;
b2Point2.y = m_cpPoint2.y/PTM_RATIO;
return b2Point2;
}
//返回中心点 cocos2d-x下坐标
b2Vec2 BodySegment::ccpos_GetCenter()
{
return m_vCenter;
}
//返回中心点 box2d-x下坐标
b2Vec2 BodySegment::b2pos_GetCenter()
{
b2Vec2 b2Center;
b2Center.x = m_vCenter.x/PTM_RATIO;
b2Center.y = m_vCenter.y/PTM_RATIO;
return b2Center;
}
//返回中心点X坐标 cocos2d-x下坐标
float BodySegment::ccpos_GetCenterX()
{
return m_vCenter.x;
}
//返回中心点X坐标 box2d-x下坐标
float BodySegment::b2pos_GetCenterX()
{
return m_vCenter.x/PTM_RATIO;
}
//返回中心点Y坐标 cocos2d-x下坐标
float BodySegment::ccpos_GetCenterY()
{
return m_vCenter.y;
}
//返回中心点Y坐标 box2d-x下坐标
float BodySegment::b2pos_GetCenterY()
{
return m_vCenter.y/PTM_RATIO;
}
//返回两点相减后的向量旋转弧度
float BodySegment::GetAngle()
{
return m_fAngle;
}
//返回两点间的长度 标量
//cocos2d-x中的长度
float BodySegment::cc_GetLength()
{
return m_fLength;
}
//box2d中的长度
float BodySegment::b2_GetLength()
{
return m_fLength/PTM_RATIO;
}
类构建完成 下面开始创建
首先 介绍需要的变量:
//世界
b2World *m_pWorld;
//绘制线段每段的长度 超过这个长度才保存点
float m_fSegmentLength;
//保存前一个point
CCPoint m_PrePoint;
//当前的point
CCPoint m_CurPoint;
//保存片段信息vector
vector<BodySegment*> *m_Vec1;
其次 应用:
1 HelloWorld::init() 方法中 初始化 m_Vec1 = new vector<BodySegment*>();
每段绳索的小段 m_iSegmentLength = 20.0f;
2 box2d世界的创建 与 step 这个就不说了
3 触摸消息 (我用的是单点触摸)
3.1 ccTouchBegan(CCTouch* touch, CCEvent* event) 方法中
//获得点 将点转换为cocos2d-x坐标
CCPoint touchLocation = touch->getLocation();
CCPoint nodePosition = convertToNodeSpace( touchLocation );
//做个判断 清空vector1中的值
if (!m_Vec1->empty())
{
m_Vec1->clear();
}
//保存起始点
m_PrePoint = nodePosition;
3.2 ccTouchMoved(CCTouch* touch, CCEvent* event) 方法中
//获得点 将点转换为cocos2d-x坐标
CCPoint touchLocation = touch->getLocation();
CCPoint nodePosition = convertToNodeSpace( touchLocation );
//获得当前点
m_CurPoint = nodePosition;
//计算当前点到上一点的距离
float distance = ccpDistance(m_CurPoint,m_PrePoint);
//如果两点的距离大于预定长度
if (distance>=m_iSegmentLength)
{
//创建BodySegment 并用vector保存
BodySegment *sg = new BodySegment(m_PrePoint,m_CurPoint);
m_Vec1->push_back(sg);
//让上一点等于当前点
m_PrePoint = m_CurPoint;
}
3.3 ccTouchEnded(CCTouch* touch, CCEvent* event) 方法中 做绘制 怕看着乱 单独又写了两个方法
//DrawLineBody(); //刚体段绘制线段
DrawEdgeLineBody(); //片刚体绘制
重点来了:
DrawLineBody()
{
//做个m_Vec1 的迭代器
vector<BodySegment*>::iterator it = m_Vec1->begin();
//刚体定义
b2BodyDef bd;
bd.type = b2_dynamicBody;
//创建刚体
b2Body* body = m_World->CreateBody(&bd);
//迭代循环 提取保存的点信息
for (;it!=m_Vec1->end();it++)
{
//定义多边形
b2PolygonShape shape;
//创建盒子 SetAsBox在box2d中重载了 4个参数的这个
shape.SetAsBox(((*it)->b2_GetLength())/2.0f, 1.0f/PTM_RATIO, //参数一和二 是盒子的宽高
(b2Vec2((*it)->b2pos_GetCenterX(), (*it)->b2pos_GetCenterY())), //盒子绘制的中心点位置
((*it)->GetAngle()) ); //盒子旋转的角度
//盒子绘制的位置
bd.position.Set((*it)->b2pos_GetCenterX(),(*it)->b2pos_GetCenterY());
//是否旋转
bd.fixedRotation = true;
//夹具的定义
b2FixtureDef fd;
fd.density = 20.0f;
fd.friction = 0.2f;
fd.shape = &shape;
//给刚体创建夹具
body->CreateFixture(&fd);
}
}
DrawEdgeLineBody()
{
vector<BodySegment*>::iterator it = m_Vec1->begin();
b2BodyDef bd;
bd.type = b2_dynamicBody;
b2Body* body = m_World->CreateBody(&bd);
for (;it!=m_Vec1->end();it++)
{
b2EdgeShape shape;
//这里设置刚体的时候是通过点设置 其他和上面一样
shape.Set((*it)->b2pos_vGetPoint1(),(*it)->b2pos_vGetPoint2());
bd.position.Set((*it)->b2pos_GetCenterX(),(*it)->b2pos_GetCenterY());
bd.fixedRotation = true;
b2FixtureDef fd;
fd.density = 20.0f;
fd.friction = 0.2f;
fd.shape = &shape;
body->CreateFixture(&fd);
}
}
注:ccpToAngle ccpDistance 等数学函数式cocos2d-x提供的,用起来很方便, 还有很多就不一一列举了
总结来说呢,其实这个并不难,就是 实时创建刚体和在一个刚体上绑定多个夹具的应用 ,一个刚体绑定多个夹具就像BOX2D给的例子 ApplyForce 中的小飞机制作是一个道理
引擎版本:cocos2d2.1beta3 + box2d 2.2.1
可以有两种方式
1 b2PolygonShape 绘制 (缺点:每段刚体的大小可能不会一直,有误差)
2 b2EdgeShape绘制 (缺点:1 没找到旋转方式,问题待解决。。。 2 与b2EdgeShape绘制的地面不发生碰撞 3 鼠标关节不能移动该刚体)
两种方法其实很类似
思路:1 保存鼠标 按下及移动时的点坐标
2 通过点坐标绘制刚体
1 保存两点坐标而且还需要一些其他的值 比如:两点间距离 /两点间中心点/两点相减所构成的向量旋转角度等 而且还涉及到cocos2d-x坐标系与box2d坐标系的数值转换问题,所以我将其封装成一个类,以方便获取相应的值 (类并不全面,而且有些实现可能会有更方便的方法,希望有各位多多指点)代码如下:
///
.h 文件
#ifndef _BODYSEGMENT_H_
#define _BODYSEGMENT_H_
//像素比米比例 1米=32像素
#define PTM_RATIO 32
#include "cocos2d.h"
#include "Box2D/Box2D.h"
using namespace cocos2d;
class BodySegment
{
public:
//根据传入的两个点 计算所需要的值
BodySegment(CCPoint p1, CCPoint p2);
~BodySegment();
//将中心点位置由 CCPoint转换为b2Vec类型
void ConvertPointTob2Vec(CCPoint cp);
//返回第一个点 cocos2d-x下坐标
CCPoint ccpos_GetPoint1();
//返回第二个点 cocos2d-x下坐标
CCPoint ccpos_GetPoint2();
//返回转换为b2vec的point1
b2Vec2 b2pos_vGetPoint1();
//返回转换为b2vec的point2
b2Vec2 b2pos_vGetPoint2();
//返回第一个点 box2d-x下坐标
CCPoint b2pos_GetPoint1();
//返回第二个点 box2d-x下坐标
CCPoint b2pos_GetPoint2();
//返回中心点 cocos2d-x下坐标
b2Vec2 ccpos_GetCenter();
//返回中心点 box2d-x下坐标
b2Vec2 b2pos_GetCenter();
//返回中心点X坐标 cocos2d-x下坐标
float ccpos_GetCenterX();
//返回中心点X坐标 box2d-x下坐标
float b2pos_GetCenterX();
//返回中心点Y坐标 cocos2d-x下坐标
float ccpos_GetCenterY();
//返回中心点Y坐标 box2d-x下坐标
float b2pos_GetCenterY();
//返回两点相减后的向量旋转弧度
float GetAngle();
//返回两点间的长度 标量
float cc_GetLength(); //cocos2d-x中的长度
float b2_GetLength(); //box2d中的长度
private:
//两个点
CCPoint m_cpPoint1;
CCPoint m_cpPoint2;
//将两个点转换为b2vec 并且为box2d坐标
b2Vec2 m_bvPoint1;
b2Vec2 m_bvPoint2;
//两点中心位置
CCPoint m_cCenter; //CCPoint类型用于两点计算值
b2Vec2 m_vCenter; //由CCPoint类型转换
//向量旋转的弧度
float m_fAngle;
//两点间的长度
float m_fLength;
};
#endif
/
.cpp 文件
#include "BodySegment.h"
//根据传入的两个点 计算所需要的值
BodySegment::BodySegment(CCPoint p1, CCPoint p2)
{
//点坐标为cocos2d坐标系坐标
m_cpPoint1 = p1;
m_cpPoint2 = p2;
//计算两点的中心点
m_cCenter = ccpMidpoint(m_cpPoint1,m_cpPoint2);
//给m_vCenter 赋值
ConvertPointTob2Vec(m_cCenter);
//两点旋转的弧度值 两点相减求出向量后计算旋转角度
m_fAngle = ccpToAngle(ccpSub(m_cpPoint2,m_cpPoint1));
//求出两点间距离
m_fLength = ccpDistance(m_cpPoint1,m_cpPoint2);
}
BodySegment::~BodySegment()
{
}
//将中心点位置由 CCPoint转换为b2Vec类型
void BodySegment::ConvertPointTob2Vec(CCPoint cp)
{
m_vCenter.x = cp.x;
m_vCenter.y = cp.y;
}
//返回第一个点 cocos2d-x下坐标
CCPoint BodySegment::ccpos_GetPoint1()
{
return m_cpPoint1;
}
//返回第二个点 cocos2d-x下坐标
CCPoint BodySegment::ccpos_GetPoint2()
{
return m_cpPoint2;
}
//返回转换为b2vec的point1
b2Vec2 BodySegment::b2pos_vGetPoint1()
{
m_bvPoint1.x = m_cpPoint1.x/PTM_RATIO;
m_bvPoint1.y = m_cpPoint1.y/PTM_RATIO;
return m_bvPoint1;
}
//返回转换为b2vec的point2
b2Vec2 BodySegment::b2pos_vGetPoint2()
{
m_bvPoint2.x = m_cpPoint2.x/PTM_RATIO;
m_bvPoint2.y = m_cpPoint2.y/PTM_RATIO;
return m_bvPoint2;
}
//返回第一个点 box2d-x下坐标
CCPoint BodySegment::b2pos_GetPoint1()
{
CCPoint b2Point1;
b2Point1.x = m_cpPoint1.x/PTM_RATIO;
b2Point1.y = m_cpPoint1.y/PTM_RATIO;
return b2Point1;
}
//返回第二个点 box2d-x下坐标
CCPoint BodySegment::b2pos_GetPoint2()
{
CCPoint b2Point2;
b2Point2.x = m_cpPoint2.x/PTM_RATIO;
b2Point2.y = m_cpPoint2.y/PTM_RATIO;
return b2Point2;
}
//返回中心点 cocos2d-x下坐标
b2Vec2 BodySegment::ccpos_GetCenter()
{
return m_vCenter;
}
//返回中心点 box2d-x下坐标
b2Vec2 BodySegment::b2pos_GetCenter()
{
b2Vec2 b2Center;
b2Center.x = m_vCenter.x/PTM_RATIO;
b2Center.y = m_vCenter.y/PTM_RATIO;
return b2Center;
}
//返回中心点X坐标 cocos2d-x下坐标
float BodySegment::ccpos_GetCenterX()
{
return m_vCenter.x;
}
//返回中心点X坐标 box2d-x下坐标
float BodySegment::b2pos_GetCenterX()
{
return m_vCenter.x/PTM_RATIO;
}
//返回中心点Y坐标 cocos2d-x下坐标
float BodySegment::ccpos_GetCenterY()
{
return m_vCenter.y;
}
//返回中心点Y坐标 box2d-x下坐标
float BodySegment::b2pos_GetCenterY()
{
return m_vCenter.y/PTM_RATIO;
}
//返回两点相减后的向量旋转弧度
float BodySegment::GetAngle()
{
return m_fAngle;
}
//返回两点间的长度 标量
//cocos2d-x中的长度
float BodySegment::cc_GetLength()
{
return m_fLength;
}
//box2d中的长度
float BodySegment::b2_GetLength()
{
return m_fLength/PTM_RATIO;
}
类构建完成 下面开始创建
首先 介绍需要的变量:
//世界
b2World *m_pWorld;
//绘制线段每段的长度 超过这个长度才保存点
float m_fSegmentLength;
//保存前一个point
CCPoint m_PrePoint;
//当前的point
CCPoint m_CurPoint;
//保存片段信息vector
vector<BodySegment*> *m_Vec1;
其次 应用:
1 HelloWorld::init() 方法中 初始化 m_Vec1 = new vector<BodySegment*>();
每段绳索的小段 m_iSegmentLength = 20.0f;
2 box2d世界的创建 与 step 这个就不说了
3 触摸消息 (我用的是单点触摸)
3.1 ccTouchBegan(CCTouch* touch, CCEvent* event) 方法中
//获得点 将点转换为cocos2d-x坐标
CCPoint touchLocation = touch->getLocation();
CCPoint nodePosition = convertToNodeSpace( touchLocation );
//做个判断 清空vector1中的值
if (!m_Vec1->empty())
{
m_Vec1->clear();
}
//保存起始点
m_PrePoint = nodePosition;
3.2 ccTouchMoved(CCTouch* touch, CCEvent* event) 方法中
//获得点 将点转换为cocos2d-x坐标
CCPoint touchLocation = touch->getLocation();
CCPoint nodePosition = convertToNodeSpace( touchLocation );
//获得当前点
m_CurPoint = nodePosition;
//计算当前点到上一点的距离
float distance = ccpDistance(m_CurPoint,m_PrePoint);
//如果两点的距离大于预定长度
if (distance>=m_iSegmentLength)
{
//创建BodySegment 并用vector保存
BodySegment *sg = new BodySegment(m_PrePoint,m_CurPoint);
m_Vec1->push_back(sg);
//让上一点等于当前点
m_PrePoint = m_CurPoint;
}
3.3 ccTouchEnded(CCTouch* touch, CCEvent* event) 方法中 做绘制 怕看着乱 单独又写了两个方法
//DrawLineBody(); //刚体段绘制线段
DrawEdgeLineBody(); //片刚体绘制
重点来了:
DrawLineBody()
{
//做个m_Vec1 的迭代器
vector<BodySegment*>::iterator it = m_Vec1->begin();
//刚体定义
b2BodyDef bd;
bd.type = b2_dynamicBody;
//创建刚体
b2Body* body = m_World->CreateBody(&bd);
//迭代循环 提取保存的点信息
for (;it!=m_Vec1->end();it++)
{
//定义多边形
b2PolygonShape shape;
//创建盒子 SetAsBox在box2d中重载了 4个参数的这个
shape.SetAsBox(((*it)->b2_GetLength())/2.0f, 1.0f/PTM_RATIO, //参数一和二 是盒子的宽高
(b2Vec2((*it)->b2pos_GetCenterX(), (*it)->b2pos_GetCenterY())), //盒子绘制的中心点位置
((*it)->GetAngle()) ); //盒子旋转的角度
//盒子绘制的位置
bd.position.Set((*it)->b2pos_GetCenterX(),(*it)->b2pos_GetCenterY());
//是否旋转
bd.fixedRotation = true;
//夹具的定义
b2FixtureDef fd;
fd.density = 20.0f;
fd.friction = 0.2f;
fd.shape = &shape;
//给刚体创建夹具
body->CreateFixture(&fd);
}
}
DrawEdgeLineBody()
{
vector<BodySegment*>::iterator it = m_Vec1->begin();
b2BodyDef bd;
bd.type = b2_dynamicBody;
b2Body* body = m_World->CreateBody(&bd);
for (;it!=m_Vec1->end();it++)
{
b2EdgeShape shape;
//这里设置刚体的时候是通过点设置 其他和上面一样
shape.Set((*it)->b2pos_vGetPoint1(),(*it)->b2pos_vGetPoint2());
bd.position.Set((*it)->b2pos_GetCenterX(),(*it)->b2pos_GetCenterY());
bd.fixedRotation = true;
b2FixtureDef fd;
fd.density = 20.0f;
fd.friction = 0.2f;
fd.shape = &shape;
body->CreateFixture(&fd);
}
}
注:ccpToAngle ccpDistance 等数学函数式cocos2d-x提供的,用起来很方便, 还有很多就不一一列举了
总结来说呢,其实这个并不难,就是 实时创建刚体和在一个刚体上绑定多个夹具的应用 ,一个刚体绑定多个夹具就像BOX2D给的例子 ApplyForce 中的小飞机制作是一个道理