//碰撞框
class ColliderBody : public cocos2d::Ref
{
public:
ColliderBody(ContourData *contourData);
~ColliderBody();
inline ContourData *getContourData() { return _contourData; }
#if ENABLE_PHYSICS_BOX2D_DETECT || ENABLE_PHYSICS_CHIPMUNK_DETECT
void setColliderFilter(ColliderFilter *filter);
ColliderFilter *getColliderFilter();
#endif
#if ENABLE_PHYSICS_BOX2D_DETECT
virtual void setB2Fixture(b2Fixture *fixture) { _fixture = fixture; }
virtual b2Fixture *getB2Fixture() const { return _fixture; }
#elif ENABLE_PHYSICS_CHIPMUNK_DETECT
virtual void setShape(cpShape *shape) { _shape = shape; }
virtual cpShape *getShape() const { return _shape; }
#elif ENABLE_PHYSICS_SAVE_CALCULATED_VERTEX
virtual const std::vector<cocos2d::Point> &getCalculatedVertexList() const { return _calculatedVertexList; }
#endif
private:
#if ENABLE_PHYSICS_BOX2D_DETECT
b2Fixture *_fixture;
ColliderFilter *_filter;
#elif ENABLE_PHYSICS_CHIPMUNK_DETECT
cpShape *_shape;
ColliderFilter *_filter;
#elif ENABLE_PHYSICS_SAVE_CALCULATED_VERTEX
std::vector<cocos2d::Point> _calculatedVertexList;//所有顶点
#endif
ContourData *_contourData;//轮廓数据
friend class ColliderDetector;
};
/*
* @brief ContourSprite used to draw the contour of the display
* @js NA
* @lua NA
*/
class ColliderDetector : public cocos2d::Ref
{
public:
static ColliderDetector *create();
static ColliderDetector *create(Bone *bone);
public:
/**
* @js ctor
*/
ColliderDetector();
/**
* @js NA
* @lua NA
*/
~ColliderDetector(void);
virtual bool init();
virtual bool init(Bone *bone);
void addContourData(ContourData *contourData);//手动添加 一个 轮廓顶点信息数据
void addContourDataList(cocos2d::Vector<ContourData*> &contourDataList);//手动添加 一组 轮廓顶点信息数据
void removeContourData(ContourData *contourData);//手动移除 一个 轮廓顶点信息数据
void removeAll();//手动添加 所有 轮廓顶点信息数据
void updateTransform(kmMat4 &t);//旋转更新
void setActive(bool active);//设置激活状态
bool getActive();
const cocos2d::Vector<ColliderBody*>& getColliderBodyList();//得到所有轮廓框信息
#if ENABLE_PHYSICS_BOX2D_DETECT || ENABLE_PHYSICS_CHIPMUNK_DETECT
virtual void setColliderFilter(ColliderFilter *filter);
virtual ColliderFilter *getColliderFilter();
#endif
virtual void setBone(Bone *bone) { _bone = bone; }
virtual Bone *getBone() const { return _bone; }
#if ENABLE_PHYSICS_BOX2D_DETECT
virtual void setBody(b2Body *body);
virtual b2Body *getBody() const;
#elif ENABLE_PHYSICS_CHIPMUNK_DETECT
virtual void setBody(cpBody *body);
virtual cpBody *getBody() const;
#endif
protected:
cocos2d::Vector<ColliderBody*> _colliderBodyList;//碰撞body
Bone *_bone;//骨骼
#if ENABLE_PHYSICS_BOX2D_DETECT
b2Body *_body;
ColliderFilter *_filter;
#elif ENABLE_PHYSICS_CHIPMUNK_DETECT
cpBody *_body;
ColliderFilter *_filter;
#endif
protected:
bool _active;//是否激活
};
}
#endif /*__CCCOLLIDERDETECTOR_H__*/
class TestColliderDetector : public ArmatureTestLayer
{
public:
~TestColliderDetector();
virtual void onEnter() override;
virtual std::string title() const override;
virtual void update(float delta);
virtual void draw(Renderer *renderer, const kmMat4 &transform, bool transformUpdated) override;
void onDraw(const kmMat4 &transform, bool transformUpdated);
void onFrameEvent(cocostudio::Bone *bone, const std::string& evt, int originFrameIndex, int currentFrameIndex);
void initWorld() {};
cocostudio::Armature *armature;
cocostudio::Armature *armature2;
CustomCommand _customCommand; //new render needed this for drawing primitives
cocos2d::Sprite *bullet;
};
void TestColliderDetector::update(float delta){ armature2->setVisible(true);//// CCNode中两个个方法方法:// getContentSize用来获得节点原始大小。返回CGSize类型// getBoundingBox获得节点当前大小,即如果经过缩放那么就是缩放后的大小。返回CGRect类型。// 有个问题最近才遇到,父精灵进行缩放处理,会对子精灵进行标记(boolean值),在实际绘制过程中会影响子精灵显示大小,但并不改变子精灵的getBoundingBox所获得的值,也就是只有直接setscale才会影响getBoundingBox数值。// CCSprite中有个方法:// getTextureRect返回精灵纹理大小,返回CGRect类型,并且是原始纹理大小,无关缩放。在一般情况下和getContentSize作用一样,但如果用TP处理过,还回值是实际纹理大小,留白部分会去除。这个在碰撞检测过程中经常用到。 Rect rect = bullet->getBoundingBox(); // This code is just telling how to get the vertex. // For a more accurate collider detection, you need to implemente yourself. const Map<std::string, Bone*>& map = armature2->getBoneDic();//得到骨骼字典 for(const auto& element : map)//遍历字典 { Bone *bone = element.second; ColliderDetector *detector = bone->getColliderDetector(); if (!detector)//如否没有碰撞 跳过 继续遍历 continue; //得到碰撞框列表 const cocos2d::Vector<ColliderBody*>& bodyList = detector->getColliderBodyList(); for (const auto& object : bodyList) { //得到一个碰撞框 ColliderBody *body = static_cast<ColliderBody*>(object); //一个碰撞框包含的所有顶点 const std::vector<Point> &vertexList = body->getCalculatedVertexList(); float minx = 0, miny = 0, maxx = 0, maxy = 0; int length = (int)vertexList.size();//顶点个数 for (int i = 0; i<length; i++) { Point vertex = vertexList.at(i); if (i == 0) { minx = maxx = vertex.x;//起点和终点 是 第一个点 miny = maxy = vertex.y; } else//遍历所有点 得到4个最值 { minx = vertex.x < minx ? vertex.x : minx; miny = vertex.y < miny ? vertex.y : miny; maxx = vertex.x > maxx ? vertex.x : maxx; maxy = vertex.y > maxy ? vertex.y : maxy; } } Rect temp = Rect(minx, miny, maxx - minx, maxy - miny);//组成一个包含所有顶点的矩形 if (temp.intersectsRect(rect)) { //子弹矩形在碰撞区域内 碰撞框不可见 armature2->setVisible(false); } } }}void TestColliderDetector::draw(Renderer *renderer, const kmMat4 &transform, bool transformUpdated){ _customCommand.init(_globalZOrder); _customCommand.func = CC_CALLBACK_0(TestColliderDetector::onDraw, this, transform, transformUpdated); renderer->addCommand(&_customCommand);}void TestColliderDetector::onDraw(const kmMat4 &transform, bool transformUpdated){ kmGLPushMatrix(); kmGLLoadMatrix(&transform); armature2->drawContour(); kmGLPopMatrix();}
TestColliderDetector::~TestColliderDetector()
{
}
void TestColliderDetector::onEnter()
{
ArmatureTestLayer::onEnter();
scheduleUpdate();
armature = Armature::create("Cowboy");
armature->getAnimation()->play("FireWithoutBullet");
armature->getAnimation()->setSpeedScale(0.2f);
armature->setScaleX(-0.2f);
armature->setScaleY(0.2f);
armature->setPosition(Point(VisibleRect::left().x + 70, VisibleRect::left().y));
/*
* Set armature's frame event callback function
* To disconnect this event, just setFrameEventCallFunc(nullptr);
*/
armature->getAnimation()->setFrameEventCallFunc(CC_CALLBACK_0(TestColliderDetector::onFrameEvent, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
addChild(armature);
armature2 = Armature::create("Cowboy");
armature2->getAnimation()->play("Walk");
armature2->setScaleX(-0.2f);
armature2->setScaleY(0.2f);
armature2->setPosition(Point(VisibleRect::right().x - 60, VisibleRect::left().y));
addChild(armature2);
#if ENABLE_PHYSICS_BOX2D_DETECT || ENABLE_PHYSICS_CHIPMUNK_DETECT
bullet = cocos2d::extension::PhysicsSprite::createWithSpriteFrameName("25.png");
#elif ENABLE_PHYSICS_SAVE_CALCULATED_VERTEX
bullet = Sprite::createWithSpriteFrameName("25.png");
#endif
addChild(bullet);
initWorld();
}
std::string TestColliderDetector::title() const
{
return "Test Collider Detector";
}
void TestColliderDetector::onFrameEvent(Bone *bone, const std::string& evt, int originFrameIndex, int currentFrameIndex)
{
CCLOG("(%s) emit a frame event (%s) at frame index (%d).", bone->getName().c_str(), evt.c_str(), currentFrameIndex);
/*
* originFrameIndex is the frame index editted in Action Editor
* currentFrameIndex is the current index animation played to
* frame event may be delay emit, so originFrameIndex may be different from currentFrameIndex.
*/
Point p = armature->getBone("Layer126")->getDisplayRenderNode()->convertToWorldSpaceAR(Point(0, 0));
bullet->setPosition(Point(p.x + 60, p.y));
bullet->stopAllActions();
bullet->runAction(CCMoveBy::create(1.5f, Point(350, 0)));
}