RedreamAnim.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. //
  2. // RedreamAnim.cpp
  3. // redream_runtime
  4. //
  5. // Created by zhuge on 2023/1/17.
  6. //
  7. #include "RedreamAnim.h"
  8. #include "BezierEqualPointsAction.hpp"
  9. #include "Redream.h"
  10. redream::RedreamAnim* redream::RedreamAnim::createFromAnimFile(std::string filePath) {
  11. auto anim = new redream::RedreamAnim();
  12. if (anim && anim->init(filePath.c_str())) {
  13. anim->autorelease();
  14. return anim;
  15. }
  16. delete anim;
  17. anim = nullptr;
  18. return nullptr;
  19. }
  20. redream::RedreamAnim::~RedreamAnim() {
  21. _propKeyframes.clear();
  22. }
  23. bool redream::RedreamAnim::init(const char* filePath) {
  24. auto animationManager = _loadAnimFile(filePath);
  25. // 时间线时长
  26. _duration = animationManager->_sequences.front()->getDuration();
  27. // 节点 cocos2d::Node*
  28. auto node = animationManager->_nodeSequences.begin()->first;
  29. // 节点动画属性 cocos2d::Map<std::string, REDSequenceProperty*>&
  30. auto& seqNodeProps = animationManager->_nodeSequences.begin()->second.begin()->second;
  31. // 组织所有的关键帧入map
  32. _initPropKeyframes(animationManager, node, seqNodeProps);
  33. // 初始化默认的起止位置
  34. CC_ASSERT(_propKeyframes.find("position") != _propKeyframes.end());
  35. auto keyframes = _propKeyframes.at("position")->keyframes;
  36. _startPosition = _valueToVec2(keyframes.front()->getValue());
  37. _endPosition = _valueToVec2(keyframes.back()->getValue());
  38. return true;
  39. }
  40. cocos2d::Action* redream::RedreamAnim::getAction() {
  41. REDAnimationManager tempAnimationManager; // 调用起函数,友元
  42. // 取原始的起止位置
  43. const auto& posKeyframes = _propKeyframes.at("position")->keyframes;
  44. Vec2 oldStartPos = _valueToVec2(posKeyframes.front()->getValue());
  45. Vec2 oldEndPos = _valueToVec2(posKeyframes.back()->getValue());
  46. Vector<FiniteTimeAction*> allActions;
  47. /*
  48. 每种属性所有的keyframe生成对应类型的动画,放入一个Sequence中
  49. 所有属性最后生成的Sequence放到一个Spawn中
  50. */
  51. for (auto it = _propKeyframes.begin(); it != _propKeyframes.end(); it++) {
  52. auto propName = it->first;
  53. if (propName == "displayFrame") {
  54. // 纹理动画是无效的
  55. continue;
  56. }
  57. auto keyframes = _propKeyframes.at(propName)->keyframes;
  58. Vector<FiniteTimeAction*> actions;
  59. for (ssize_t i = 0; i < keyframes.size() - 1; i++) {
  60. auto kf0 = keyframes.at(i);
  61. auto kf1 = keyframes.at(i + 1);
  62. float duration = kf1->getTime() - kf0->getTime();
  63. cocos2d::ActionInterval* action;
  64. if (propName == "position") {
  65. std::vector<Vec2> pathPoints = kf0->getEqualPoints(); // 路径动画点
  66. std::vector<Vec2> convertedPathPoints = {};
  67. // 关键位置,应用首尾位置信息,转换中间所有坐标
  68. Vec2 toPos;
  69. // 首尾可以直接使用,无需计算
  70. if (i == 0) {
  71. toPos = _startPosition;
  72. } else if (i == keyframes.size() - 1) {
  73. toPos = _endPosition;
  74. } else {
  75. if (pathPoints.empty()) {
  76. // 转换坐标
  77. toPos = _getControlPoint(oldStartPos, oldEndPos, _valueToVec2(kf1->getValue()), _startPosition, _endPosition);
  78. } else {
  79. for (auto point: pathPoints) {
  80. auto newPoint = _getControlPoint(oldStartPos, oldEndPos, point, _startPosition, _endPosition);
  81. convertedPathPoints.push_back(newPoint);
  82. }
  83. }
  84. }
  85. if (convertedPathPoints.empty()) {
  86. action = MoveTo::create(duration, toPos);
  87. } else {
  88. action = BezierEqualPointsAction::create(duration, convertedPathPoints);
  89. }
  90. } else if (propName == "scale") {
  91. // 忽略需要节点Size的属性类型,直接取真实值
  92. Vec2 scale = _valueToVec2(kf1->getValue());
  93. action = ScaleTo::create(duration, scale.x, scale.y);
  94. } else {
  95. // 普通的动画属性,不需要节点信息,直接创建就可以
  96. action = tempAnimationManager.getAction(kf0, kf1, propName, nullptr);
  97. }
  98. // 应用easing
  99. action = tempAnimationManager.getEaseAction(action, kf0->getEasingType(), kf0->getEasingOpt());
  100. // 存好,回头放到Sequence中去
  101. actions.pushBack(action);
  102. }
  103. // 同一种类型的动画,用Sequence
  104. allActions.pushBack(Sequence::create(actions));
  105. }
  106. // 所有类型的动画,用Spawn
  107. auto action = Spawn::create(allActions);
  108. return action;
  109. }
  110. #pragma mark - private
  111. redream::REDAnimationManager* redream::RedreamAnim::_loadAnimFile(const char* filePath) {
  112. std::string fileWithoutPathExtension = REDReader::deletePathExtension(filePath);
  113. std::string outFilePath = fileWithoutPathExtension + ".redanim";
  114. redream::NodeLoaderLibrary *ccNodeLoaderLibrary = redream::NodeLoaderLibrary::newDefaultNodeLoaderLibrary();
  115. redream::REDReader *ccbReader = new redream::REDReader(ccNodeLoaderLibrary);
  116. auto node = (Node*)ccbReader->readNodeGraphFromFile(outFilePath.c_str());
  117. CC_ASSERT(node != nullptr);
  118. auto animationManager = ccbReader->getAnimationManager();
  119. // 只有一条时间线
  120. CC_ASSERT(animationManager->_sequences.size() == 1);
  121. // 只有一个节点
  122. CC_ASSERT(animationManager->_nodeSequences.size() == 1);
  123. // 只有一条时间线
  124. CC_ASSERT(animationManager->_nodeSequences.begin()->second.size() == 1);
  125. return animationManager;
  126. }
  127. void redream::RedreamAnim::_initPropKeyframes(REDAnimationManager* animationManager, cocos2d::Node* node, cocos2d::Map<std::string, REDSequenceProperty*>& seqNodeProps) {
  128. // 输入: cocos2d::Map<std::string, REDSequenceProperty*>& seqNodeProps <属性名, 该属性对应的关键帧信息(所有关键帧)>
  129. // 生成: map<属性名, PropKeyframes属性的关键帧列表>
  130. // 纹理动画忽略
  131. // 首帧/末帧不存在则补一个,其他所有帧直接放进来
  132. for (auto it = seqNodeProps.begin(); it != seqNodeProps.end(); it++) {
  133. const std::string propName = it->first;
  134. if (propName == "displayFrame") {
  135. // 纹理动画无意义
  136. continue;
  137. }
  138. redream::REDSequenceProperty *seqProp = it->second;
  139. auto& nodeKeyframes = seqProp->getKeyframes();
  140. if (nodeKeyframes.size() < 0) {
  141. // 异常状态,无任何帧信息
  142. continue;
  143. }
  144. PropKeyframes* keyframes = new PropKeyframes();
  145. keyframes->autorelease();
  146. // 如果没有首尾帧,需要补上一个
  147. redream::REDKeyframe* firstKeyframe = nodeKeyframes.front();
  148. if (firstKeyframe->getTime() < 0.000001) {
  149. // 首帧不为0
  150. const auto& baseValue = animationManager->getBaseValue(node, propName);
  151. auto frame = _createRedKeyframe(baseValue, 0);
  152. keyframes->keyframes.pushBack(frame);
  153. }
  154. // 中间所有关键帧
  155. for (auto keyframe: nodeKeyframes) {
  156. keyframes->keyframes.pushBack(keyframe);
  157. }
  158. // 如果没有尾帧,需要补上一个
  159. redream::REDKeyframe* lastKeyframe = nodeKeyframes.back();
  160. if (abs(lastKeyframe->getTime() - _duration) > 0.000001) {
  161. // 不等于时间线的长度,补
  162. auto frame = _createRedKeyframe(lastKeyframe->getValue(), _duration);
  163. keyframes->keyframes.pushBack(frame);
  164. }
  165. // 放入map中
  166. _propKeyframes.insert(propName, keyframes);
  167. }
  168. }
  169. redream::REDKeyframe* redream::RedreamAnim::_createRedKeyframe(const cocos2d::Value& value, float atTime) const {
  170. redream::REDKeyframe* frame = new redream::REDKeyframe();
  171. frame->autorelease();
  172. frame->setValue(value);
  173. frame->setTime(atTime);
  174. frame->setEasingType(redream::REDKeyframe::EasingType::LINEAR);
  175. return frame;
  176. }
  177. Vec2 redream::RedreamAnim::_getControlPoint(Vec2 A_start, Vec2 A_end, Vec2 A_control, Vec2 B_start, Vec2 B_end) {
  178. Vec2 ab = A_end - A_start;
  179. Vec2 ac = A_control - A_start;
  180. Vec2 de = B_end - B_start;
  181. float s;
  182. Vec2 ret;
  183. if (A_start != A_end){
  184. s = de.length() / ab.length();
  185. ac.scale(s);
  186. long double angle1 = std::atan2l(ab.y, ab.x);
  187. ac.rotate(Vec2::ZERO, -angle1);
  188. long double angle2 = std::atan2l(de.y, de.x);
  189. ac.rotate(Vec2::ZERO, angle2);
  190. ret = ac + B_start;
  191. } else {
  192. ret = B_start;
  193. }
  194. return ret;
  195. }
  196. Vec2 redream::RedreamAnim::_valueToVec2(const cocos2d::Value& value) {
  197. auto vector = value.asValueVector();
  198. return Vec2(vector[0].asInt(), vector[1].asInt());
  199. }