// // RedBakeNode.hpp // cocos2d_libs // // Created by Liang zhong on 2022/11/11. // #ifndef RedBakeNode_h #define RedBakeNode_h #include "2d/CCNode.h" #include #include "cocos2d.h" #include "RedSpineBakeManage.h" #if COCOS2D_VERSION < 0x00040000 #include //v3/ #include //v3/ #else #include #include #endif using namespace std; using namespace cocos2d; struct RedBakeNodeFrame { std::string animationName; // 时间线名字 float elapsedTime = .0; // 当前播放过的时间 bool loop = true; // 是否循环 RedBakeNodeFrame() : animationName(""), elapsedTime(0.0f), loop(true) {} RedBakeNodeFrame(const std::string& _animationName, float _elapsedTime, bool _loop) : animationName(_animationName), elapsedTime(_elapsedTime), loop(_loop) {} }; enum RBN_STATE {Unknown,Complete,Break,Pause,Resume,MixPreAniEnd}; typedef std::function RBNListener; class RedBakeNode : public Node { public: static RedBakeNode *create(const std::string aFileName); static RedBakeNode *create(); RedBakeNode(const std::string aFileName); RedBakeNode(); ~RedBakeNode(); // 属性设置 void setBakeDataFile(const std::string& aFileName); const std::string& getBakeDataFile() const; // 当前选中播放中的时间线 // 时间线K帧支持 std::vector getAnimations(); // 所有的时间线列表 void setBakeFrame(RedBakeNodeFrame frame); // 设置节点为指定时间线,指定时间的状态 RedBakeNodeFrame getBakeFrame(); // 打开或者关闭自动绘制(每帧自动绘制) void startAutoDraw(); void stopAutoDraw(); // 获取时间线的长度 float getAnimDuration(const std::string& tl); bool playAnimation (const std::string& animationName, bool loop, float spdRate = 1.f); bool stopCurrentAnimation(); bool pauseCurrentAnimation(); bool resumeCurrentAnimation(); bool currentAnimationIsPaused(); bool playMixAnimation(const std::string& animationName, bool loop,float aMixTime); bool playMixAnimation(const std::string& animationName, bool loop,float aMixTime,Point aDis);//Point aDis用来处理上下节点连接时,初始位置有偏移,单一节点不需要 bool IscurrentAnimationFinished(); void updateLoop(bool loop); void setFlipX(bool aFlipX); //当前动画是否X翻转 bool isFlipX(); //当前动画是否翻转 void draw (cocos2d::Renderer* renderer, const cocos2d::Mat4& transform, uint32_t transformFlags) override; void drawBake (cocos2d::Renderer* renderer, const cocos2d::Mat4& transform, uint32_t transformFlags) ; void drawMixBake (cocos2d::Renderer* renderer, const cocos2d::Mat4& transform, uint32_t transformFlags) ; void setBakeSpineID(std::string aId); void resetPlayInfo(); void setRBNListener(RBNListener& aListener); void update (float deltaTime) override; void updateSelfFunc(float deltaTime, bool bInFrameMode = false); //组合bakenode的时候调整绘制顺序 void drawSelfFunc(cocos2d::Renderer *renderer, const cocos2d::Mat4 &transform, uint32_t transformFlags); void addAttachNodeBeforeSlot(std::string aSlotName,RedBakeNode * aBakeNode);//添加一个绘制附件,并指定一个slot绑定,绘制层时先绘制bakenode再绘制slot void removeAttachNode(std::string aSlotName);//删除一个slot void removeAllAttachNode();//删除全部slot void attachNodeBeUpdated();//当Attach修改的时候,需要更新下singleattch和attchsize //组合Bakenode时候父子连动 void addFatherNodeBindMove(std::string aBoneName,RedBakeNode * aBakeNode);//添加父Bakenode,确保自己和父node一起运动,aBoneName是父node关于自己的连接点 void removeFatherNode();//移除父Bakenode,确保自己和父node一起运动,aBoneName是父node关于自己的连接点 const Point getFatherBoneOffset(std::string aBoneName);//获取父节点对应bone的偏移量 const Point getFatherBoneOffsetByIndex(int aIndex);//获取父节点对应bone的偏移量 int getFatherBoneOffsetIndex(std::string aBoneName);//获取父节点对应bone的偏移量对应的数组索引,用来加速性能 //用来记录多个spine合并播放时,骨骼连接点初始的位置差 void setDisPos(Point aPos); void updateRealCurrentBakeFrame(float aReal);//用来指定动画起始位子,这样上下半身走路可以同步,不会同手同脚 float getRealCurrentBakeFrame();//获取当前播放的位置 // 设置纹理 void setTexture(Texture2D*); void setEventCallBack(std::function cb); void handleEvent(std::function cb); Vec2 getSpeechPos(); protected: bool animationIsInscreen(); //判断某个Slot是否在屏幕内 void _stopSelfDraw(); //关闭自我绘制功能,由其他RedBakeNode来绘制 void _startSelfDraw(); //开启自我绘制功能 //通过BakeFrame的小数部分合并两个Traingle中的顶点Vert的数据,相当于给动画做差值,因为帧率没有这么稳定,卡的时候走的可能是一帧半 void mergeTwoVert(V3F_C4B_T2F *beginVert,V3F_C4B_T2F *endVert,int aCount,Point offsetPos); void _reloadVertMap(); bool switchAnimation(const std::string& animationName, bool loop); RedBakeNodeFrame _curFrame; std::vector _vertArr; int _totalBakeFrame = -1; //指定当前的Animation最大的BakeFrame int _currentBakeFrame = -1; //当前的Animation播放到第几个BakeFrame float _realCurrentBakeFrame = -1;//当前的Animation播放到第几个BakeFrame,这个是实际值,因为帧无法完全对齐,每帧间隔在卡的时候会变 float _currentFrameFracpart = 0.0; //当前的Animation播放到第几个BakeFrame的小数部分,rs = (1-_currentFrameFracpart)begin+end std::map _slotFrameArray; //记录当前slot各属性播放进度 std::vector _slotFrameArrayVect; //_slotFrameArray的加速版本,解决性能问题 int _currentDrawOrderIndex = 0; std::string _bakeSpineID; bool _isLoop = false; //当前动画是否时Loop bool _firstDraw = true; //当前动画是否是首日调用 bool _currentAnimationIsFinished = true; //当前动画是否播放完 bool _currentAnimationIsPaused = false; //当前动画是否播暂停 bool _isFlipX = false; //当前动画是否X翻转 bool _isFirstReset = false; //每次调用playAnimation的时候设置成ture,每次resetPlayInfo设置成false,这样确保第一次resetPlayInfo能创建没有slot RedAnimationBakeModel *_currentBakeAnimation = nullptr; std::string _fileName; std::string _fileNameFull; RBNListener _listener = nullptr; SEL_SCHEDULE _schUpdate = nullptr; std::map _attachNodeMap; //记录挂载的RedBakeNode节点,用来组合RedBakeNode一起绘制的 //判断_attachNodeMap是否改变,updateSelfFunc里面有遍历_attachNodeMap的,但是上半身结束的时候可能会导致下半身的_attachNodeMap重置,导致遍历出问题 bool _attachNodeMapHasChanged = false; RedBakeNode *_singleAttachNode = nullptr;//当_attachNodeMap中size为1的时候,_singleAttachNode等于这个唯一,用于加速 int _attachNodeMapSize = 0;//表示_attachNodeMap的数量 bool _drawSelf = true; //是否自我绘制,默认true,自己会绘制自己,否就由其他RedBakeNode来调用Draw函数 RedBakeNode *_fatherNode = nullptr; //记录当前节点需要跟随一起动的父节点 std::string _fatherNodeBoneName; //记录当前节点需要跟随一起动的父节点的骨骼名字,这个骨骼定义了自己的偏移 Point _disPos = {0,0}; //用来记录多个spine合并播放时,骨骼连接点初始的位置差 Vec2 zeroPos;//默认的原点 bool isInScreen = true; //当前Node是否在屏幕内 int _fatherNodePosIndex = -1; //用来索引_fatherNode中Bone偏移放在数组的什么位子,这个数组是用来加快性能的,之前是Map,所以需要记录 cocos2d::Mat4 newTransform;//用于draw里面处理flip Texture2D* _texture = nullptr; std::function _eventCallBack; Vec2 _speechPos = Vec2(0,0); }; #endif /* RedBakeNode_h */