目前我的cocos2d-x编辑器的动画部分接口采用的是spriter动画编辑器提供的接口,spriter动画编辑器虽然简陋,但一般的需求基本上能够满足。可以在http://www.brashmonkey.com/spriter.htm下载,另外cocos2d-x的接口可以在论坛http://www.brashmonkey.com/forum/viewtopic.php?f=3&t=870下载。
接口导入进来之后,一切都很正常,然而在采用该接口进行开发时,发现有几个比较严重的问题。
问题1:资源采用多文件夹形式存储,渲染效率低
问题2:一个png只能有一个ccsprite,在编辑器是正常的,然而采用论坛那个接口导入到cocos2d-x就有问题。
问题3:精灵不能flip
问题4:不支持scale变换
陆续修改了上述4个问题
资源采用Sprite Frame实现
png的bug线性实现,时间复杂度O(1)
flip的实现参考cocos2d-x源码中CCTransitionFlipX的实现——摄像头换位
scale参考angle的变换就OK了
代码如下:
(代码中掺杂了编辑器部分的代码,精力有限,本代码仅供参考)
头文件:
  1. //------------------------------------------------------------------------
  2. //
  3. // SCMLAnimator : KickStarter project Spriter renderer for cocos2d-x.
  4. //
  5. // Spriter website : http://www.kickstarter.com/projects/539087245/spriter
  6. //
  7. // Licensed under the BSD license, see LICENSE in root for details.
  8. //
  9. // Copyright (c) 2012 James Hui (a.k.a. Dr.Watson)
  10. //
  11. // For latest updates, please visit http://jameshui.com
  12. //
  13. //------------------------------------------------------------------------
  14. #ifndef _CC_SPRITER_X_H_
  15. #define _CC_SPRITER_X_H_
  16. #include <vector>
  17. #include <string>
  18. #include "JEvent.h"
  19. #include "cocos2d.h"
  20. #include "TouchSprite.h"
  21. #include "tinyxml.h"
  22. class CCSpriterX;
  23. #define FILE_SPRITE_SIZE 128
  24. namespace SCMLHelper
  25. {
  26. struct File
  27. {
  28. File();
  29. ~File();
  30. void Init(TiXmlNode *node);
  31. int id;
  32. std::string name;
  33. float width;
  34. float height;
  35. //一个文件可能有多个关联
  36. cocos2d::CCSprite* sprites[FILE_SPRITE_SIZE];
  37. };
  38. class Folder
  39. {
  40. public:
  41. Folder();
  42. ~Folder();
  43. void Init(TiXmlNode *node);
  44. int GetFileCount();
  45. File *GetFile(int index);
  46. private:
  47. int mId;
  48. std::string mName;
  49. std::vector <File *> mFiles;
  50. };
  51. struct ObjectRef
  52. {
  53. void Init(TiXmlNode *node);
  54. int id;
  55. int timeline;
  56. int key;
  57. int z_index;
  58. };
  59. struct Object
  60. {
  61. void Init(TiXmlNode *node, CCSpriterX *animator, int timelineId);
  62. int folder;
  63. int file;
  64. float x;
  65. float y;
  66. float angle;
  67. float scaleX;
  68. float scaleY;
  69. float pivot_x;
  70. float pivot_y;
  71. int z_index;
  72. cocos2d::CCSprite *sprite;
  73. };
  74. class Key
  75. {
  76. public:
  77. Key();
  78. ~Key();
  79. void Init(TiXmlNode *node, CCSpriterX *animator, int timelineId);
  80. int GetObjectRefCount();
  81. ObjectRef *GetObjectRef(int index);
  82. int GetObjectCount();
  83. Object *GetObject(int index);
  84. float GetTime();
  85. bool IsSpinCounterClockwise();
  86. private:
  87. int mId;
  88. float mTime;
  89. bool mSpinCounterClockwise;
  90. std::vector <Object *> mObjects;
  91. std::vector <ObjectRef *> mObjectRefs;
  92. // will have bones later
  93. };
  94. class Timeline
  95. {
  96. public:
  97. Timeline();
  98. ~Timeline();
  99. void Init(TiXmlNode *node, CCSpriterX *animator);
  100. int GetKeyframeCount();
  101. Key *GetKeyframe(int index);
  102. private:
  103. int mId;
  104. std::vector <Key *> mKeyframes;
  105. };
  106. class Animation
  107. {
  108. public:
  109. CC_SYNTHESIZE(JEvent *, event, Event);
  110. CC_SYNTHESIZE(std::string, afterAction, AfterAction);
  111. CCSpriterX * spr;
  112. public:
  113. void Restart();
  114. Animation(CCSpriterX * spr);
  115. ~Animation();
  116. void Update(float dt);
  117. void Init(TiXmlNode *node, CCSpriterX *animator);
  118. void Render();
  119. bool IsDone();
  120. public:
  121. std::string getName(){return mName;}
  122. private:
  123. int mId;
  124. std::string mName;
  125. float mLength;
  126. bool mLooping;
  127. bool mDone;
  128. Timeline *mMainline;
  129. int mCurrKeyframe;
  130. std::vector <Timeline *> mTimelines;
  131. float mTimer;
  132. cocos2d::CCPoint mPosition;
  133. };
  134. class Entity
  135. {
  136. private:
  137. CCSpriterX * spr;
  138. public:
  139. Entity(CCSpriterX * spr);
  140. ~Entity();
  141. void StartWithEvent(const char * name, JEvent * event);
  142. std::string CurrentAction();
  143. void Update(float dt);
  144. void Render();
  145. void Start(const char * name,const char* _afterAction);
  146. void SetId(int id);
  147. void SetName(const char *name);
  148. void AddAnimation(Animation *animation);
  149. void NextAnimation();
  150. private:
  151. int mId;
  152. std::string mName;
  153. std::vector <Animation *> mAnimations;
  154. int mCurrAnimation;
  155. };
  156. }
  157. class CCSpriterX : public TouchSprite
  158. {
  159. private:
  160. struct Pit{
  161. int fileId;
  162. int id;
  163. int folderId;
  164. };
  165. Pit fileSprites[FILE_SPRITE_SIZE];
  166. CC_SYNTHESIZE(ccColor3B, colorX, ColorX);
  167. public:
  168. CCSpriterX();
  169. ~CCSpriterX();
  170. virtual void setFlipX(bool bFlipX);
  171. bool initWithFile(const char *filename);
  172. std::string CurrentAction();
  173. virtual void draw(void);
  174. virtual void update(float dt);
  175. static CCSpriterX * create(const char *filename);
  176. cocos2d::CCSprite * getSprite(int folderId, int fileId, int timelineId);
  177. void PlayNext();
  178. void PlayWithEvent(const char * name, JEvent * event);
  179. void Play(const char* name,const char* _afterAction = 0);
  180. private:
  181. std::vector <SCMLHelper::Folder *> mFolders;
  182. std::vector <SCMLHelper::Entity *> mEntities;
  183. int mCurrEntity;
  184. };
  185. #endif

源文件:
  1. //------------------------------------------------------------------------
  2. //
  3. // CCSpriterX : KickStarter project Spriter renderer for cocos2d-x.
  4. //
  5. // Spriter website : http://www.kickstarter.com/projects/539087245/spriter
  6. //
  7. // Licensed under the BSD license, see LICENSE in root for details.
  8. //
  9. // Copyright (c) 2012 James Hui (a.k.a. Dr.Watson)
  10. //
  11. // For latest updates, please visit http://jameshui.com
  12. //
  13. //------------------------------------------------------------------------
  14. #include "CCSpriterX.h"
  15. #include "Common.h"
  16. #include "jerror.h"
  17. USING_NS_CC;
  18. namespace SCMLHelper
  19. {
  20. ///////////////////////////////////////////////////////////////////////////////////
  21. File::File()
  22. {
  23. for(size_t i=0; i<FILE_SPRITE_SIZE; ++i){
  24. sprites[i] = 0;
  25. }
  26. }
  27. File::~File()
  28. {
  29. for(size_t i=0; i<FILE_SPRITE_SIZE; ++i){
  30. if(sprites[i] != NULL){
  31. sprites[i]->release();
  32. }
  33. }
  34. }
  35. void File::Init(TiXmlNode *node)
  36. {
  37. TiXmlElement *element = node->ToElement();
  38. if (element)
  39. {
  40. int intValue;
  41. float floatValue;
  42. if (element->QueryIntAttribute("id", &intValue) == TIXML_SUCCESS)
  43. id = intValue;
  44. else
  45. id = 0;
  46. name = element->Attribute("name");
  47. if (element->QueryFloatAttribute("width", &floatValue) == TIXML_SUCCESS)
  48. width = floatValue;
  49. else
  50. width = 0;
  51. if (element->QueryFloatAttribute("height", &floatValue) == TIXML_SUCCESS)
  52. height = floatValue;
  53. else
  54. height = 0;
  55. if (name.size()>0)
  56. {
  57. //资源全部放到scml目录中!
  58. std::string path = workPath+gConfig->read<std::string>("res")+"/";
  59. //sprite = CCSprite::create((path+"scml/"+name).c_str());
  60. sprites[0] = CCSprite::createWithSpriteFrameName(name.c_str());
  61. sprites[0]->retain();
  62. }
  63. }
  64. }
  65. ///////////////////////////////////////////////////////////////////////////////////
  66. Folder::Folder()
  67. : mId(0)
  68. {
  69. mFiles.reserve(50);
  70. }
  71. Folder::~Folder()
  72. {
  73. int count = mFiles.size();
  74. for (int i=0;i<count;i++)
  75. CC_SAFE_DELETE(mFiles[i]);
  76. mFiles.clear();
  77. }
  78. int Folder::GetFileCount()
  79. {
  80. return mFiles.size();
  81. }
  82. File *Folder::GetFile(int index)
  83. {
  84. if (index < (int)mFiles.size())
  85. return mFiles[index];
  86. return NULL;
  87. }
  88. void Folder::Init(TiXmlNode *node)
  89. {
  90. TiXmlElement *element = node->ToElement();
  91. if (element)
  92. {
  93. int intValue;
  94. if (element->QueryIntAttribute("id", &intValue) == TIXML_SUCCESS)
  95. mId= intValue;
  96. mName = element->Attribute("name")==0?".":element->Attribute("name");
  97. for (TiXmlNode* fileNode = node->FirstChild(); fileNode; fileNode = fileNode->NextSibling())
  98. {
  99. File *file = new File();
  100. file->Init(fileNode);
  101. mFiles.push_back(file);
  102. }
  103. }
  104. }
  105. ///////////////////////////////////////////////////////////////////////////////////
  106. void ObjectRef::Init(TiXmlNode *node)
  107. {
  108. TiXmlElement *element = node->ToElement();
  109. if (element)
  110. {
  111. int intValue;
  112. if (element->QueryIntAttribute("id", &intValue) == TIXML_SUCCESS)
  113. id = intValue;
  114. else
  115. id = 0;
  116. if (element->QueryIntAttribute("timeline", &intValue) == TIXML_SUCCESS)
  117. timeline = intValue;
  118. else
  119. timeline = 0;
  120. if (element->QueryIntAttribute("key", &intValue) == TIXML_SUCCESS)
  121. key = intValue;
  122. else
  123. key = 0;
  124. if (element->QueryIntAttribute("z_index", &intValue) == TIXML_SUCCESS)
  125. z_index = intValue;
  126. else
  127. z_index = 0;
  128. }
  129. }
  130. ///////////////////////////////////////////////////////////////////////////////////
  131. void Object::Init(TiXmlNode *node, CCSpriterX *animator, int timelineId)
  132. {
  133. sprite = NULL;
  134. float scaleFactor = CCDirector::sharedDirector()->getContentScaleFactor();
  135. TiXmlElement *element = node->ToElement();
  136. if (element)
  137. {
  138. int intValue;
  139. float floatValue;
  140. if (element->QueryIntAttribute("folder", &intValue) == TIXML_SUCCESS)
  141. folder = intValue;
  142. else
  143. folder = 0;
  144. if (element->QueryIntAttribute("file", &intValue) == TIXML_SUCCESS)
  145. file = intValue;
  146. else
  147. file = 0;
  148. if (element->QueryFloatAttribute("x", &floatValue) == TIXML_SUCCESS)
  149. x = floatValue/scaleFactor;
  150. else
  151. x = 0;
  152. if (element->QueryFloatAttribute("y", &floatValue) == TIXML_SUCCESS)
  153. y = floatValue/scaleFactor;
  154. else
  155. y = 0;
  156. if (element->QueryFloatAttribute("angle", &floatValue) == TIXML_SUCCESS)
  157. angle = floatValue;
  158. else
  159. angle = 0;
  160. if (element->QueryFloatAttribute("scale_x", &floatValue) == TIXML_SUCCESS)
  161. scaleX = floatValue;
  162. else
  163. scaleX = 1;
  164. if(scaleX < 1){
  165. jlog("shit");
  166. }
  167. if (element->QueryFloatAttribute("scale_y", &floatValue) == TIXML_SUCCESS)
  168. scaleY = floatValue;
  169. else
  170. scaleY = 1;
  171. if (element->QueryFloatAttribute("pivot_x", &floatValue) == TIXML_SUCCESS)
  172. pivot_x = floatValue;
  173. else
  174. pivot_x = 0;
  175. if (element->QueryFloatAttribute("pivot_y", &floatValue) == TIXML_SUCCESS)
  176. pivot_y = floatValue;
  177. else
  178. pivot_y = 1;
  179. if (element->QueryIntAttribute("z_index", &intValue) == TIXML_SUCCESS)
  180. z_index = intValue;
  181. else
  182. z_index = 0;
  183. sprite = animator->getSprite(folder, file, timelineId);
  184. }
  185. }
  186. ///////////////////////////////////////////////////////////////////////////////////
  187. Key::Key()
  188. : mId(0)
  189. , mTime(0)
  190. , mSpinCounterClockwise(true)
  191. {
  192. mObjects.reserve(50);
  193. mObjectRefs.reserve(50);
  194. }
  195. Key::~Key()
  196. {
  197. int count = mObjects.size();
  198. for (int i=0;i<count;i++)
  199. CC_SAFE_DELETE(mObjects[i]);
  200. mObjects.clear();
  201. count = mObjectRefs.size();
  202. for (int i=0;i<count;i++)
  203. CC_SAFE_DELETE(mObjectRefs[i]);
  204. mObjectRefs.clear();
  205. }
  206. int Key::GetObjectRefCount()
  207. {
  208. return mObjectRefs.size();
  209. }
  210. ObjectRef *Key::GetObjectRef(int index)
  211. {
  212. if (index < (int)mObjectRefs.size())
  213. return mObjectRefs[index];
  214. return NULL;
  215. }
  216. int Key::GetObjectCount()
  217. {
  218. return mObjects.size();
  219. }
  220. Object *Key::GetObject(int index)
  221. {
  222. if (index < (int)mObjects.size())
  223. return mObjects[index];
  224. return NULL;
  225. }
  226. float Key::GetTime()
  227. {
  228. return mTime;
  229. }
  230. bool Key::IsSpinCounterClockwise()
  231. {
  232. return mSpinCounterClockwise;
  233. }
  234. void Key::Init(TiXmlNode *node, CCSpriterX *animator, int timelineId)
  235. {
  236. TiXmlElement *element = node->ToElement();
  237. if (element)
  238. {
  239. int intValue;
  240. float floatValue;
  241. if (element->QueryIntAttribute("id", &intValue) == TIXML_SUCCESS)
  242. mId = intValue;
  243. float time = 0;
  244. if (element->QueryFloatAttribute("time", &floatValue) == TIXML_SUCCESS) // was in milliseconds, convert to seconds instead
  245. time = floatValue/1000.0f;
  246. mTime = time;
  247. if (element->QueryIntAttribute("spin", &intValue) == TIXML_SUCCESS)
  248. mSpinCounterClockwise = !(intValue == -1);
  249. for (TiXmlNode* objNode = node->FirstChild(); objNode; objNode = objNode->NextSibling())
  250. {
  251. element = objNode->ToElement();
  252. const char *tabObj = element->Value();
  253. if (strcmp(tabObj, "object_ref")==0)
  254. {
  255. ObjectRef *ref = new ObjectRef();
  256. ref->Init(objNode);
  257. mObjectRefs.push_back(ref);
  258. }
  259. else if (strcmp(tabObj, "object")==0)
  260. {
  261. Object *obj = new Object();
  262. obj->Init(objNode, animator, timelineId);
  263. mObjects.push_back(obj);
  264. }
  265. }
  266. }
  267. }
  268. ///////////////////////////////////////////////////////////////////////////////////
  269. Timeline::Timeline()
  270. : mId(0)
  271. {
  272. mKeyframes.reserve(50);
  273. }
  274. Timeline::~Timeline()
  275. {
  276. int count = mKeyframes.size();
  277. for (int i=0;i<count;i++)
  278. {
  279. CC_SAFE_DELETE(mKeyframes[i]);
  280. }
  281. }
  282. int Timeline::GetKeyframeCount()
  283. {
  284. return mKeyframes.size();
  285. }
  286. Key *Timeline::GetKeyframe(int index)
  287. {
  288. if (index < (int)mKeyframes.size())
  289. {
  290. return mKeyframes[index];
  291. }
  292. return NULL;
  293. }
  294. void Timeline::Init(TiXmlNode *node, CCSpriterX *animator)
  295. {
  296. int intValue;
  297. TiXmlElement *element = node->ToElement();
  298. if (element)
  299. {
  300. if (element->QueryIntAttribute("id", &intValue) == TIXML_SUCCESS)
  301. mId = intValue;
  302. for (TiXmlNode* keyNode = node->FirstChild(); keyNode; keyNode = keyNode->NextSibling())
  303. {
  304. element = keyNode->ToElement();
  305. if (element)
  306. {
  307. Key *keyframe = new Key();
  308. keyframe->Init(keyNode, animator, mId);
  309. mKeyframes.push_back(keyframe);
  310. }
  311. }
  312. }
  313. }
  314. ///////////////////////////////////////////////////////////////////////////////////
  315. Animation::Animation(CCSpriterX * _spr)
  316. : mId(0)
  317. , spr(_spr)
  318. , mCurrKeyframe(0)
  319. , mMainline(NULL)
  320. , mDone(false)
  321. , mTimer(0)
  322. ,event(0),afterAction("")
  323. {
  324. mTimelines.reserve(50);
  325. }
  326. Animation::~Animation()
  327. {
  328. int count = mTimelines.size();
  329. for (int i=0;i<count;i++)
  330. CC_SAFE_DELETE(mTimelines[i]);
  331. mTimelines.clear();
  332. }
  333. void Animation::Init(TiXmlNode *node, CCSpriterX *animator)
  334. {
  335. int intValue;
  336. float floatValue;
  337. TiXmlElement *element = node->ToElement();
  338. if (element)
  339. {
  340. if (element->QueryIntAttribute("id", &intValue) == TIXML_SUCCESS)
  341. mId = intValue;
  342. mName = element->Attribute("name");
  343. if (element->QueryFloatAttribute("length", &floatValue) == TIXML_SUCCESS)
  344. mLength = floatValue/1000.0f; // was in milliseconds, convert to seconds instead
  345. const char *looping = element->Attribute("looping"); // was set to "false" in alpha, but in fact looping all the time
  346. mLooping = true;
  347. for (TiXmlNode* lineNode = node->FirstChild(); lineNode; lineNode = lineNode->NextSibling())
  348. {
  349. element = lineNode->ToElement();
  350. const char *tabLine = element->Value();
  351. if (strcmp(tabLine, "mainline")==0) // 1 mainline only
  352. {
  353. mMainline = new Timeline();
  354. mMainline->Init(lineNode, animator);
  355. }
  356. else if (strcmp(tabLine, "timeline")==0)
  357. {
  358. Timeline *timeline = new Timeline();
  359. timeline->Init(lineNode, animator);
  360. mTimelines.push_back(timeline);
  361. }
  362. }
  363. }
  364. }
  365. bool Animation::IsDone()
  366. {
  367. return mDone;
  368. }
  369. void Animation::Restart()
  370. {
  371. mDone = false;
  372. mTimer = 0;
  373. mCurrKeyframe = 0;
  374. }
  375. float lerp(float a, float b, float t){
  376. return a+(b-a)*t;
  377. }
  378. void Animation::Update(float dt)
  379. {
  380. mTimer += dt;
  381. if (mTimer >= mLength)
  382. {
  383. mDone = true;
  384. Restart(); // always looping for now
  385. }
  386. int count = mMainline->GetKeyframeCount();
  387. Key *keyframe = mMainline->GetKeyframe(mCurrKeyframe);
  388. float currTime = keyframe->GetTime();
  389. Key *keyframeNext = NULL;
  390. int next = mCurrKeyframe+1;
  391. if (next > count-1) // looping
  392. next = 0;
  393. keyframeNext = mMainline->GetKeyframe(next);
  394. if (keyframeNext)
  395. {
  396. float nextTime = keyframeNext->GetTime();
  397. if (next == 0)
  398. nextTime = mLength;
  399. if (mTimer >= nextTime)
  400. {
  401. mCurrKeyframe = next;
  402. keyframe = keyframeNext;
  403. currTime = keyframe->GetTime();
  404. next = mCurrKeyframe+1;
  405. if (next > count-1) // looping
  406. next = 0;
  407. keyframeNext = mMainline->GetKeyframe(next);
  408. if (keyframeNext == NULL)
  409. return;
  410. nextTime = keyframeNext->GetTime();
  411. if (next == 0)
  412. nextTime = mLength;
  413. }
  414. float t = (mTimer-currTime)/(nextTime-currTime);
  415. int count = keyframe->GetObjectRefCount();
  416. for (int i=0;i<count;i++)
  417. {
  418. ObjectRef *ref = keyframe->GetObjectRef(i);
  419. ObjectRef *refNext = keyframeNext->GetObjectRef(i);
  420. if (ref && refNext)
  421. {
  422. Key *keyRef = mTimelines[ref->timeline]->GetKeyframe(ref->key);
  423. Object *obj = keyRef->GetObject(0); // should be only 1 object
  424. Key *keyRefNext = mTimelines[refNext->timeline]->GetKeyframe(refNext->key);
  425. Object *objNext = keyRefNext->GetObject(0);
  426. float x = lerp(obj->x, objNext->x, t);
  427. float y = lerp(obj->y, objNext->y, t);
  428. float scaleX = lerp(obj->scaleX, objNext->scaleX, t);
  429. float scaleY = lerp(obj->scaleY, objNext->scaleY, t);
  430. float angle = objNext->angle-obj->angle;
  431. if (keyRef->IsSpinCounterClockwise())
  432. {
  433. if (angle < 0)
  434. angle = (objNext->angle+360)-obj->angle;
  435. }
  436. else
  437. {
  438. if (angle > 0)
  439. {
  440. angle = (objNext->angle-360)-obj->angle;
  441. }
  442. }
  443. if (ref->timeline != refNext->timeline)
  444. t = 0;
  445. angle = obj->angle+(angle)*t;
  446. if (angle >= 360)
  447. angle -= 360;
  448. float px = obj->pivot_x+(objNext->pivot_x-obj->pivot_x)*t;
  449. float py = obj->pivot_y+(objNext->pivot_y-obj->pivot_y)*t;
  450. CCPoint newPos = ccp(x, y);
  451. obj->sprite->setPosition(newPos);
  452. obj->sprite->setRotation(-angle);
  453. obj->sprite->setScaleX(scaleX);
  454. obj->sprite->setScaleY(scaleY);
  455. obj->sprite->setAnchorPoint(ccp(px, py));
  456. }
  457. }
  458. }
  459. }
  460. void Animation::Render()
  461. {
  462. Key *keyframe = mMainline->GetKeyframe(mCurrKeyframe);
  463. int count = keyframe->GetObjectRefCount();
  464. for (int i=0;i<count;i++)
  465. {
  466. ObjectRef *ref = keyframe->GetObjectRef(i);
  467. if (ref)
  468. {
  469. Key *keyRef = mTimelines[ref->timeline]->GetKeyframe(ref->key);
  470. Object *obj = keyRef->GetObject(0); // should be only 1 object
  471. obj->sprite->setColor(spr->getColorX());
  472. obj->sprite->visit();
  473. }
  474. }
  475. }
  476. ///////////////////////////////////////////////////////////////////////////////////
  477. Entity::Entity(CCSpriterX * _spr)
  478. : mCurrAnimation(0)
  479. , mId(0)
  480. , spr(_spr)
  481. {
  482. mAnimations.reserve(50);
  483. };
  484. Entity::~Entity()
  485. {
  486. int count = mAnimations.size();
  487. for (int i=0;i<count;i++)
  488. CC_SAFE_DELETE(mAnimations[i]);
  489. mAnimations.clear();
  490. }
  491. void Entity::Update(float dt)
  492. {
  493. Animation *animation = mAnimations[mCurrAnimation];
  494. animation->Update(dt);
  495. }
  496. std::string Entity::CurrentAction()
  497. {
  498. return mAnimations[mCurrAnimation]->getName();
  499. }
  500. void Entity::StartWithEvent(const char * name, JEvent * event)
  501. {
  502. for(size_t i=0; i<mAnimations.size(); ++i){
  503. if(mAnimations[i]->getName() == std::string(name)){
  504. mCurrAnimation = i;
  505. mAnimations[i]->setEvent(event);
  506. mAnimations[i]->Restart();
  507. }
  508. }
  509. }
  510. void Entity::Start(const char * name, const char * _afterAction)
  511. {
  512. for(size_t i=0; i<mAnimations.size(); ++i){
  513. if(mAnimations[i]->getName() == std::string(name)){
  514. mCurrAnimation = i;
  515. mAnimations[i]->setAfterAction(_afterAction);
  516. mAnimations[i]->Restart();
  517. }
  518. }
  519. }
  520. void Entity::Render()
  521. {
  522. Animation *animation = mAnimations[mCurrAnimation];
  523. animation->Render();
  524. }
  525. void Entity::NextAnimation()
  526. {
  527. mCurrAnimation++;
  528. if (mCurrAnimation >= (int)mAnimations.size())
  529. mCurrAnimation = 0;
  530. Animation *animation = mAnimations[mCurrAnimation];
  531. animation->Restart();
  532. }
  533. void Entity::SetId(int id)
  534. {
  535. mId = id;
  536. }
  537. void Entity::SetName(const char *name)
  538. {
  539. mName = name;
  540. }
  541. void Entity::AddAnimation(Animation *animation)
  542. {
  543. mAnimations.push_back(animation);
  544. }
  545. }
  546. ///////////////////////////////////////////////////////////////////////////////////
  547. using namespace SCMLHelper;
  548. CCSpriterX::CCSpriterX()
  549. {
  550. mFolders.reserve(50);
  551. mEntities.reserve(50);
  552. for(int i=0; i<FILE_SPRITE_SIZE; ++i){
  553. fileSprites[i].fileId = -1;
  554. fileSprites[i].id = -1;
  555. fileSprites[i].folderId = -1;
  556. }
  557. }
  558. CCSpriterX::~CCSpriterX()
  559. {
  560. }
  561. CCSpriterX *CCSpriterX::create(const char *filename)
  562. {
  563. CCSpriterX *animator = new CCSpriterX();
  564. animator->type = SCML;
  565. animator->m_state = kLivingStateUngrabbed;
  566. if (animator && animator->initWithFile(filename))
  567. {
  568. //由于是动画层,没有大小,这里设置大小,使之能够拾取
  569. animator->setContentSize(CCSizeMake(100, 100));
  570. animator->autorelease();
  571. return animator;
  572. }
  573. CC_SAFE_DELETE(animator);
  574. return NULL;
  575. }
  576. void CCSpriterX::update(float dt)
  577. {
  578. if (dt > 0.0167f)
  579. dt = 0.0167f;
  580. Entity *entity = mEntities[mCurrEntity];
  581. entity->Update(dt);
  582. }
  583. void CCSpriterX::draw(void)
  584. {
  585. Entity *entity = mEntities[mCurrEntity];
  586. entity->Render();
  587. }
  588. std::string CCSpriterX::CurrentAction()
  589. {
  590. Entity *entity = mEntities[mCurrEntity];
  591. return entity->CurrentAction();
  592. }
  593. void CCSpriterX::PlayWithEvent(const char * name, JEvent * event)
  594. {
  595. Entity *entity = mEntities[mCurrEntity];
  596. entity->StartWithEvent(name, event);
  597. }
  598. void CCSpriterX::Play(const char* name, const char * _afterAction)
  599. {
  600. Entity *entity = mEntities[mCurrEntity];
  601. entity->Start(name, _afterAction == 0?"":_afterAction);
  602. }
  603. void CCSpriterX::PlayNext()
  604. {
  605. Entity *entity = mEntities[mCurrEntity];
  606. entity->NextAnimation();
  607. }
  608. CCSprite *CCSpriterX::getSprite(int folderId, int fileId, int timelineId)
  609. {
  610. if (folderId < (int)mFolders.size())
  611. {
  612. Folder *folder = mFolders[folderId];
  613. if (folder)
  614. {
  615. File *file = folder->GetFile(fileId);
  616. if (file){
  617. int id = this->fileSprites[timelineId].id;
  618. if(id == -1){
  619. for(int i=0; i<FILE_SPRITE_SIZE; ++i){
  620. if(fileSprites[i].fileId == fileId && fileSprites[i].folderId == folderId){
  621. ++id;
  622. }
  623. }
  624. id += 1;
  625. fileSprites[timelineId].folderId = folderId;
  626. fileSprites[timelineId].fileId = fileId;
  627. fileSprites[timelineId].id = id;
  628. }
  629. if(file->sprites[id] == 0){
  630. file->sprites[id] = CCSprite::createWithSpriteFrameName(file->name.c_str());
  631. file->sprites[id]->retain();
  632. }
  633. return file->sprites[id];
  634. }
  635. }
  636. }
  637. return NULL;
  638. }
  639. void CCSpriterX::setFlipX(bool bFlipX)
  640. {
  641. if(bFlipX != m_bFlipX){
  642. float ex,ey,ez;
  643. this->getCamera()->getEyeXYZ(&ex, &ey, &ez);
  644. this->getCamera()->setEyeXYZ(ex, ey, bFlipX?-fabs(ez):fabs(ez));
  645. this->m_bFlipX = bFlipX;
  646. }
  647. }
  648. bool CCSpriterX::initWithFile(const char *filename)
  649. {
  650. char cfilename[256];
  651. strcpy(cfilename, filename);
  652. string name = strtok(cfilename, ".");
  653. string suffix = strtok(cfilename, ".");
  654. mCurrEntity = 0;
  655. unsigned long filesize;
  656. string path = workPath+gConfig->read<string>("res")+"/"+filename;
  657. char *buffer = (char *)CCFileUtils::sharedFileUtils()->getFileData(path.c_str(), "rb", &filesize);
  658. if (buffer == NULL)
  659. return false;
  660. //加载大图
  661. string sfplist = workPath+gConfig->read<string>("res")+"/scml/"+name+".plist";
  662. string sfpng = workPath+gConfig->read<string>("res")+"/scml/"+name+".png";
  663. CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile(sfplist.c_str(), sfpng.c_str());
  664. TiXmlDocument doc;
  665. doc.Parse(buffer);
  666. TiXmlNode *root = doc.FirstChild("spriter_data");
  667. if (root)
  668. {
  669. TiXmlElement *element = root->ToElement();
  670. const char *version = element->Attribute("scml_version");
  671. const char *generator = element->Attribute("generator");
  672. const char *generatorVersion = element->Attribute("generator_version");
  673. for (TiXmlNode* entityNode = root->FirstChild(); entityNode; entityNode = entityNode->NextSibling())
  674. {
  675. element = entityNode->ToElement();
  676. if (element)
  677. {
  678. const char *tab = element->Value();
  679. if (strcmp(tab, "folder")==0)
  680. {
  681. Folder *folder = new Folder();
  682. folder->Init(entityNode);
  683. mFolders.push_back(folder);
  684. }
  685. else if (strcmp(tab, "entity")==0)
  686. {
  687. int intValue;
  688. Entity *entity = new Entity(this);
  689. if (element->QueryIntAttribute("id", &intValue) == TIXML_SUCCESS)
  690. entity->SetId(intValue);
  691. entity->SetName(element->Attribute("name"));
  692. for (TiXmlNode* animationNode = entityNode->FirstChild(); animationNode; animationNode = animationNode->NextSibling())
  693. {
  694. Animation *animation = new Animation(this);
  695. animation->Init(animationNode, this);
  696. entity->AddAnimation(animation);
  697. }
  698. mEntities.push_back(entity);
  699. }
  700. }
  701. }
  702. }
  703. CC_SAFE_DELETE_ARRAY(buffer);
  704. this->scheduleUpdate();
  705. return true;
  706. }