COCOS2DX,cocostudio::ColliderDetector 简单介绍 骨骼动画绑定碰撞区域进行碰撞检测

来源:互联网 发布:淘宝双十一百度百科 编辑:程序博客网 时间:2024/05/24 06:51
/

#ifndef __CCCOLLIDERDETECTOR_H__

#define __CCCOLLIDERDETECTOR_H__

#include "cocostudio/CCArmatureDefine.h"

#include "cocostudio/CCDatas.h"

#ifndef PT_RATIO

#define PT_RATIO 32

#endif

#if ENABLE_PHYSICS_CHIPMUNK_DETECT

#include "chipmunk.h"

#elif ENABLE_PHYSICS_BOX2D_DETECT

#include "Box2D/Box2D.h"

#endif

namespace cocostudio {

class Bone;

/**

 *  @js NA

 *  @lua NA

 */

class ColliderFilter

{

public:

    virtual ~ColliderFilter() { }

#if ENABLE_PHYSICS_BOX2D_DETECT

public:

    ColliderFilter(uint16 categoryBits = 0x0001, uint16 maskBits = 0xFFFF, int16 groupIndex = 0);

    void updateShape(b2Fixture *fixture);

    virtual void setCategoryBits(uint16 categoryBits) { _categoryBits = categoryBits; }

    virtual uint16 getCategoryBits() const { return _categoryBits; }

    virtual void setMaskBits(uint16 maskBits) { _maskBits = maskBits; }

    virtual uint16 getMaskBits() const { return _maskBits; }

    virtual void setGroupIndex(int16 groupIndex) { _groupIndex = groupIndex; }

    virtual int16 getGroupIndex() const { return _groupIndex; }

protected:

    uint16 _categoryBits;

    uint16 _maskBits;

    int16 _groupIndex;

#elif ENABLE_PHYSICS_CHIPMUNK_DETECT

public:

    ColliderFilter(cpCollisionType collisionType = 0, cpGroup group = 0);

    void updateShape(cpShape *shape);

    virtual void setCollisionType(cpCollisionType collisionType) { _collisionType = collisionType; }

    virtual cpCollisionType getCollisionType() const { return _collisionType; }

    virtual void setGroup(cpGroup group) { _group = group; }

    virtual cpGroup getGroup() const { return _group; }

protected:

    cpCollisionType _collisionType;

    cpGroup _group;

#endif

};

//碰撞框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; }#endifprivate:#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;#endifprotected:  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)));}
参考原地址:http://www.tuicool.com/articles/bUz6BrM
0 0
原创粉丝点击