/Juego/SpaceAsteroids/CocosBuilder/CCControlExtension/CCControl/Utils/CCScale9Sprite.m

https://bitbucket.org/imh2/ios-mostrar · Objective C · 650 lines · 500 code · 109 blank · 41 comment · 30 complexity · 5b0be664a6425ab312d2df86b4440ebd MD5 · raw file

  1. //
  2. // Scale9Sprite.m
  3. //
  4. // Creates a 9-slice sprite.
  5. //
  6. #import "CCScale9Sprite.h"
  7. enum positions
  8. {
  9. pCentre = 0,
  10. pTop,
  11. pLeft,
  12. pRight,
  13. pBottom,
  14. pTopRight,
  15. pTopLeft,
  16. pBottomRight,
  17. pBottomLeft
  18. };
  19. @interface CCScale9Sprite ()
  20. - (id)initWithBatchNode:(CCSpriteBatchNode *)batchnode rect:(CGRect)rect capInsets:(CGRect)capInsets;
  21. - (void)updateWithBatchNode:(CCSpriteBatchNode*)batchnode rect:(CGRect)rect rotated:(BOOL)rotated capInsets:(CGRect)capInsets;
  22. - (void)updatePosition;
  23. @end
  24. @implementation CCScale9Sprite
  25. @synthesize originalSize = originalSize_;
  26. @synthesize capInsets = capInsets_;
  27. @synthesize opacity = opacity_;
  28. @synthesize color = color_;
  29. @synthesize opacityModifyRGB = opacityModifyRGB_;
  30. @synthesize insetTop = insetTop_;
  31. @synthesize insetLeft = insetLeft_;
  32. @synthesize insetBottom = insetBottom_;
  33. @synthesize insetRight = insetRight_;
  34. @synthesize preferedSize = preferedSize_;
  35. - (void)dealloc
  36. {
  37. [topLeft release];
  38. [top release];
  39. [topRight release];
  40. [left release];
  41. [centre release];
  42. [right release];
  43. [bottomLeft release];
  44. [bottom release];
  45. [bottomRight release];
  46. [scale9Image release];
  47. [super dealloc];
  48. }
  49. #pragma mark Constructor - Initializers
  50. - (id)initWithBatchNode:(CCSpriteBatchNode *)batchnode rect:(CGRect)rect rotated:(BOOL)rotated capInsets:(CGRect)capInsets
  51. {
  52. if ((self = [super init]))
  53. {
  54. if (batchnode)
  55. {
  56. [self updateWithBatchNode:batchnode rect:rect rotated:rotated capInsets:capInsets];
  57. anchorPoint_ = ccp(0.5f, 0.5f);
  58. }
  59. positionsAreDirty_ = YES;
  60. }
  61. return self;
  62. }
  63. - (id)initWithBatchNode:(CCSpriteBatchNode *)batchnode rect:(CGRect)rect capInsets:(CGRect)capInsets
  64. {
  65. return [self initWithBatchNode:batchnode rect:rect rotated:NO capInsets:capInsets];
  66. }
  67. - (id)initWithFile:(NSString *)file rect:(CGRect)rect capInsets:(CGRect)capInsets
  68. {
  69. NSAssert(file != nil, @"Invalid file for sprite");
  70. CCSpriteBatchNode *batchnode = [CCSpriteBatchNode batchNodeWithFile:file capacity:9];
  71. return [self initWithBatchNode:batchnode rect:rect capInsets:capInsets];
  72. }
  73. + (id)spriteWithFile:(NSString *)file rect:(CGRect)rect capInsets:(CGRect)capInsets
  74. {
  75. return [[[self alloc] initWithFile:file rect:rect capInsets:capInsets] autorelease];
  76. }
  77. - (id)initWithFile:(NSString *)file rect:(CGRect)rect
  78. {
  79. NSAssert(file != nil, @"Invalid file for sprite");
  80. return [self initWithFile:file rect:rect capInsets:CGRectZero];
  81. }
  82. + (id)spriteWithFile:(NSString *)file rect:(CGRect)rect
  83. {
  84. return [[[self alloc] initWithFile:file rect:rect] autorelease];
  85. }
  86. - (id)initWithFile:(NSString *)file capInsets:(CGRect)capInsets
  87. {
  88. NSAssert(file != nil, @"Invalid file for sprite");
  89. return [self initWithFile:file rect:CGRectZero capInsets:capInsets];
  90. }
  91. + (id)spriteWithFile:(NSString *)file capInsets:(CGRect)capInsets
  92. {
  93. return [[[self alloc] initWithFile:file capInsets:capInsets] autorelease];
  94. }
  95. - (id)initWithFile:(NSString *)file
  96. {
  97. NSAssert(file != nil, @"Invalid file for sprite");
  98. return [self initWithFile:file rect:CGRectZero];
  99. }
  100. + (id)spriteWithFile:(NSString *)file
  101. {
  102. return [[[self alloc] initWithFile:file] autorelease];
  103. }
  104. - (id)initWithSpriteFrame:(CCSpriteFrame *)spriteFrame capInsets:(CGRect)capInsets
  105. {
  106. NSAssert(spriteFrame != nil, @"Sprite frame must be not nil");
  107. CCSpriteBatchNode *batchnode = [CCSpriteBatchNode batchNodeWithTexture:spriteFrame.texture capacity:9];
  108. return [self initWithBatchNode:batchnode rect:spriteFrame.rect rotated:spriteFrame.rotated capInsets:capInsets];
  109. }
  110. + (id)spriteWithSpriteFrame:(CCSpriteFrame *)spriteFrame capInsets:(CGRect)capInsets
  111. {
  112. return [[[self alloc] initWithSpriteFrame:spriteFrame capInsets:capInsets] autorelease];
  113. }
  114. - (id)initWithSpriteFrame:(CCSpriteFrame *)spriteFrame
  115. {
  116. NSAssert(spriteFrame != nil, @"Invalid spriteFrame for sprite");
  117. return [self initWithSpriteFrame:spriteFrame capInsets:CGRectZero];
  118. }
  119. + (id)spriteWithSpriteFrame:(CCSpriteFrame *)spriteFrame
  120. {
  121. return [[[self alloc] initWithSpriteFrame:spriteFrame] autorelease];
  122. }
  123. - (id)initWithSpriteFrameName:(NSString *)spriteFrameName capInsets:(CGRect)capInsets
  124. {
  125. NSAssert(spriteFrameName != nil, @"Invalid spriteFrameName for sprite");
  126. CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:spriteFrameName];
  127. return [self initWithSpriteFrame:frame capInsets:capInsets];
  128. }
  129. + (id)spriteWithSpriteFrameName:(NSString *)spriteFrameName capInsets:(CGRect)capInsets
  130. {
  131. return [[[self alloc] initWithSpriteFrameName:spriteFrameName capInsets:capInsets] autorelease];
  132. }
  133. - (id)initWithSpriteFrameName:(NSString *)spriteFrameName
  134. {
  135. NSAssert(spriteFrameName != nil, @"Invalid spriteFrameName for sprite");
  136. return [self initWithSpriteFrameName:spriteFrameName capInsets:CGRectZero];
  137. }
  138. + (id)spriteWithSpriteFrameName:(NSString *)spriteFrameName
  139. {
  140. return [[[self alloc] initWithSpriteFrameName:spriteFrameName] autorelease];
  141. }
  142. - (id)init
  143. {
  144. return [self initWithBatchNode:NULL rect:CGRectZero capInsets:CGRectZero];
  145. }
  146. - (void) updateWithBatchNode:(CCSpriteBatchNode*)batchnode rect:(CGRect)rect rotated:(BOOL)rotated capInsets:(CGRect)capInsets
  147. {
  148. GLubyte opacity = opacity_;
  149. ccColor3B color = color_;
  150. // Release old sprites
  151. [self removeAllChildrenWithCleanup:YES];
  152. [centre release];
  153. [top release];
  154. [topLeft release];
  155. [topRight release];
  156. [left release];
  157. [right release];
  158. [bottomLeft release];
  159. [bottom release];
  160. [bottomRight release];
  161. if (scale9Image != batchnode)
  162. {
  163. [scale9Image release];
  164. scale9Image = [batchnode retain];
  165. }
  166. [scale9Image removeAllChildrenWithCleanup:YES];
  167. capInsets_ = capInsets;
  168. spriteFrameRotated_ = rotated;
  169. // If there is no given rect
  170. if (CGRectEqualToRect(rect, CGRectZero))
  171. {
  172. // Get the texture size as original
  173. CGSize textureSize = [[[scale9Image textureAtlas] texture] contentSize];
  174. rect = CGRectMake(0, 0, textureSize.width, textureSize.height);
  175. }
  176. // Set the given rect's size as original size
  177. spriteRect = rect;
  178. originalSize_ = rect.size;
  179. preferedSize_ = originalSize_;
  180. capInsetsInternal_ = capInsets;
  181. // Get the image edges
  182. float l = rect.origin.x;
  183. float t = rect.origin.y;
  184. float h = rect.size.height;
  185. float w = rect.size.width;
  186. // If there is no specified center region
  187. if (CGRectEqualToRect(capInsetsInternal_, CGRectZero))
  188. {
  189. // Apply the 3x3 grid format
  190. if (rotated)
  191. {
  192. capInsetsInternal_ = CGRectMake(l+h/3, t+w/3, w/3, h/3);
  193. }
  194. else
  195. {
  196. capInsetsInternal_ = CGRectMake(l+w/3, t+h/3, w/3, h/3);
  197. }
  198. }
  199. //
  200. // Set up the image
  201. //
  202. if (rotated)
  203. {
  204. // Sprite frame is rotated
  205. // Centre
  206. centre = [[CCSprite alloc] initWithTexture:scale9Image.texture rect:capInsetsInternal_ rotated:YES];
  207. [scale9Image addChild:centre z:0 tag:pCentre];
  208. // Bottom
  209. bottom = [[CCSprite alloc]
  210. initWithTexture:scale9Image.texture
  211. rect:CGRectMake(l,
  212. capInsetsInternal_.origin.y,
  213. capInsetsInternal_.size.width,
  214. capInsetsInternal_.origin.x - l)
  215. rotated:rotated
  216. ];
  217. [scale9Image addChild:bottom z:1 tag:pBottom];
  218. // Top
  219. top = [[CCSprite alloc]
  220. initWithTexture:scale9Image.texture
  221. rect:CGRectMake(capInsetsInternal_.origin.x + capInsetsInternal_.size.height,
  222. capInsetsInternal_.origin.y,
  223. capInsetsInternal_.size.width,
  224. h - capInsetsInternal_.size.height - (capInsetsInternal_.origin.x - l))
  225. rotated:rotated
  226. ];
  227. [scale9Image addChild:top z:1 tag:pTop];
  228. // Right
  229. right = [[CCSprite alloc]
  230. initWithTexture:scale9Image.texture
  231. rect:CGRectMake(capInsetsInternal_.origin.x,
  232. capInsetsInternal_.origin.y+capInsetsInternal_.size.width,
  233. w - (capInsetsInternal_.origin.y-t)-capInsetsInternal_.size.width,
  234. capInsetsInternal_.size.height)
  235. rotated:rotated
  236. ];
  237. [scale9Image addChild:right z:1 tag:pRight];
  238. // Left
  239. left = [[CCSprite alloc]
  240. initWithTexture:scale9Image.texture
  241. rect:CGRectMake(capInsetsInternal_.origin.x,
  242. t,
  243. capInsetsInternal_.origin.y - t,
  244. capInsetsInternal_.size.height)
  245. rotated:rotated
  246. ];
  247. [scale9Image addChild:left z:1 tag:pLeft];
  248. // Top right
  249. topRight = [[CCSprite alloc]
  250. initWithTexture:scale9Image.texture
  251. rect:CGRectMake(capInsetsInternal_.origin.x + capInsetsInternal_.size.height,
  252. capInsetsInternal_.origin.y + capInsetsInternal_.size.width,
  253. w - (capInsetsInternal_.origin.y-t)-capInsetsInternal_.size.width,
  254. h - capInsetsInternal_.size.height - (capInsetsInternal_.origin.x - l))
  255. rotated:rotated
  256. ];
  257. [scale9Image addChild:topRight z:2 tag:pTopRight];
  258. // Top left
  259. topLeft = [[CCSprite alloc]
  260. initWithTexture:scale9Image.texture
  261. rect:CGRectMake(capInsetsInternal_.origin.x + capInsetsInternal_.size.height,
  262. t,
  263. capInsetsInternal_.origin.y - t,
  264. h - capInsetsInternal_.size.height - (capInsetsInternal_.origin.x - l))
  265. rotated:rotated
  266. ];
  267. [scale9Image addChild:topLeft z:2 tag:pTopLeft];
  268. // Bottom right
  269. bottomRight = [[CCSprite alloc]
  270. initWithTexture:scale9Image.texture
  271. rect:CGRectMake(l,
  272. capInsetsInternal_.origin.y + capInsetsInternal_.size.width,
  273. w - (capInsetsInternal_.origin.y-t)-capInsetsInternal_.size.width,
  274. capInsetsInternal_.origin.x - l)
  275. rotated:rotated
  276. ];
  277. [scale9Image addChild:bottomRight z:2 tag:pBottomRight];
  278. // Bottom left
  279. bottomLeft = [[CCSprite alloc]
  280. initWithTexture:scale9Image.texture
  281. rect:CGRectMake(l,
  282. t,
  283. capInsetsInternal_.origin.y - t,
  284. capInsetsInternal_.origin.x - l)
  285. rotated:rotated
  286. ];
  287. [scale9Image addChild:bottomLeft z:2 tag:pBottomLeft];
  288. }
  289. else
  290. {
  291. // Sprite frame is not rotated
  292. // Centre
  293. centre = [[CCSprite alloc] initWithTexture:scale9Image.texture rect:capInsetsInternal_ rotated:rotated];
  294. [scale9Image addChild:centre z:0 tag:pCentre];
  295. // Top
  296. top = [[CCSprite alloc]
  297. initWithTexture:scale9Image.texture
  298. rect:CGRectMake(capInsetsInternal_.origin.x,
  299. t,
  300. capInsetsInternal_.size.width,
  301. capInsetsInternal_.origin.y - t)
  302. rotated:rotated
  303. ];
  304. [scale9Image addChild:top z:1 tag:pTop];
  305. // Bottom
  306. bottom = [[CCSprite alloc]
  307. initWithTexture:scale9Image.texture
  308. rect:CGRectMake(capInsetsInternal_.origin.x,
  309. capInsetsInternal_.origin.y + capInsetsInternal_.size.height,
  310. capInsetsInternal_.size.width,
  311. h - (capInsetsInternal_.origin.y - t + capInsetsInternal_.size.height))
  312. rotated:rotated
  313. ];
  314. [scale9Image addChild:bottom z:1 tag:pBottom];
  315. // Left
  316. left = [[CCSprite alloc]
  317. initWithTexture:scale9Image.texture
  318. rect:CGRectMake(l,
  319. capInsetsInternal_.origin.y,
  320. capInsetsInternal_.origin.x - l,
  321. capInsetsInternal_.size.height)
  322. rotated:rotated
  323. ];
  324. [scale9Image addChild:left z:1 tag:pLeft];
  325. // Right
  326. right = [[CCSprite alloc]
  327. initWithTexture:scale9Image.texture
  328. rect:CGRectMake(capInsetsInternal_.origin.x + capInsetsInternal_.size.width,
  329. capInsetsInternal_.origin.y,
  330. w - (capInsetsInternal_.origin.x - l + capInsetsInternal_.size.width),
  331. capInsetsInternal_.size.height)
  332. rotated:rotated
  333. ];
  334. [scale9Image addChild:right z:1 tag:pRight];
  335. // Top left
  336. topLeft = [[CCSprite alloc]
  337. initWithTexture:scale9Image.texture
  338. rect:CGRectMake(l,
  339. t,
  340. capInsetsInternal_.origin.x - l,
  341. capInsetsInternal_.origin.y - t)
  342. rotated:rotated
  343. ];
  344. [scale9Image addChild:topLeft z:2 tag:pTopLeft];
  345. // Top right
  346. topRight = [[CCSprite alloc]
  347. initWithTexture:scale9Image.texture
  348. rect:CGRectMake(capInsetsInternal_.origin.x + capInsetsInternal_.size.width,
  349. t,
  350. w - (capInsetsInternal_.origin.x - l + capInsetsInternal_.size.width),
  351. capInsetsInternal_.origin.y - t)
  352. rotated:rotated
  353. ];
  354. [scale9Image addChild:topRight z:2 tag:pTopRight];
  355. // Bottom left
  356. bottomLeft = [[CCSprite alloc]
  357. initWithTexture:scale9Image.texture
  358. rect:CGRectMake(l,
  359. capInsetsInternal_.origin.y + capInsetsInternal_.size.height,
  360. capInsetsInternal_.origin.x - l,
  361. h - (capInsetsInternal_.origin.y - t + capInsetsInternal_.size.height))
  362. rotated:rotated
  363. ];
  364. [scale9Image addChild:bottomLeft z:2 tag:pBottomLeft];
  365. // Bottom right
  366. bottomRight = [[CCSprite alloc]
  367. initWithTexture:scale9Image.texture
  368. rect:CGRectMake(capInsetsInternal_.origin.x + capInsetsInternal_.size.width,
  369. capInsetsInternal_.origin.y + capInsetsInternal_.size.height,
  370. w - (capInsetsInternal_.origin.x - l + capInsetsInternal_.size.width),
  371. h - (capInsetsInternal_.origin.y - t + capInsetsInternal_.size.height))
  372. rotated:rotated
  373. ];
  374. [scale9Image addChild:bottomRight z:2 tag:pBottomRight];
  375. }
  376. [self setContentSize:rect.size];
  377. [self addChild:scale9Image];
  378. if (spritesGenerated_)
  379. {
  380. // Restore color and opacity
  381. self.opacity = opacity;
  382. self.color = color;
  383. }
  384. spritesGenerated_ = YES;
  385. }
  386. #pragma mark Properties
  387. - (void)setContentSize:(CGSize)size
  388. {
  389. super.contentSize = size;
  390. positionsAreDirty_ = YES;
  391. }
  392. - (void)updatePosition
  393. {
  394. CGSize size = contentSize_;
  395. float sizableWidth = size.width - topLeft.contentSize.width - topRight.contentSize.width;
  396. float sizableHeight = size.height - topLeft.contentSize.height - bottomRight.contentSize.height;
  397. float horizontalScale = sizableWidth/centre.contentSize.width;
  398. float verticalScale = sizableHeight/centre.contentSize.height;
  399. centre.scaleX = horizontalScale;
  400. centre.scaleY = verticalScale;
  401. float rescaledWidth = centre.contentSize.width * horizontalScale;
  402. float rescaledHeight = centre.contentSize.height * verticalScale;
  403. float leftWidth = bottomLeft.contentSize.width;
  404. float bottomHeight = bottomLeft.contentSize.height;
  405. // Set anchor points
  406. bottomLeft.anchorPoint = ccp(0,0);
  407. bottomRight.anchorPoint = ccp(0,0);
  408. topLeft.anchorPoint = ccp(0,0);
  409. topRight.anchorPoint = ccp(0,0);
  410. left.anchorPoint = ccp(0,0);
  411. right.anchorPoint = ccp(0,0);
  412. top.anchorPoint = ccp(0,0);
  413. bottom.anchorPoint = ccp(0,0);
  414. centre.anchorPoint = ccp(0,0);
  415. // Position corners
  416. bottomLeft.position = ccp(0,0);
  417. bottomRight.position = ccp(leftWidth+rescaledWidth,0);
  418. topLeft.position = ccp(0, bottomHeight+rescaledHeight);
  419. topRight.position = ccp(leftWidth+rescaledWidth, bottomHeight+rescaledHeight);
  420. // Scale and position borders
  421. left.position = ccp(0, bottomHeight);
  422. left.scaleY = verticalScale;
  423. right.position = ccp(leftWidth+rescaledWidth,bottomHeight);
  424. right.scaleY = verticalScale;
  425. bottom.position = ccp(leftWidth,0);
  426. bottom.scaleX = horizontalScale;
  427. top.position = ccp(leftWidth,bottomHeight+rescaledHeight);
  428. top.scaleX = horizontalScale;
  429. // Position centre
  430. centre.position = ccp(leftWidth, bottomHeight);
  431. }
  432. - (void)setPreferedSize:(CGSize)preferedSize
  433. {
  434. self.contentSize = preferedSize;
  435. preferedSize_ = preferedSize;
  436. }
  437. #pragma mark Properties
  438. - (void)setColor:(ccColor3B)color
  439. {
  440. color_ = color;
  441. for (CCNode<CCRGBAProtocol> *child in scale9Image.children)
  442. {
  443. [child setColor:color];
  444. }
  445. }
  446. - (void)setOpacity:(GLubyte)opacity
  447. {
  448. opacity_ = opacity;
  449. for (CCNode<CCRGBAProtocol> *child in scale9Image.children)
  450. {
  451. [child setOpacity:opacity];
  452. }
  453. }
  454. - (void)setOpacityModifyRGB:(BOOL)boolean
  455. {
  456. opacityModifyRGB_ = boolean;
  457. for (CCNode<CCRGBAProtocol> *child in scale9Image.children)
  458. {
  459. [child setOpacityModifyRGB:boolean];
  460. }
  461. }
  462. - (void)setSpriteFrame:(CCSpriteFrame *)spriteFrame
  463. {
  464. CCSpriteBatchNode *batchnode = [CCSpriteBatchNode batchNodeWithTexture:spriteFrame.texture capacity:9];
  465. [self updateWithBatchNode:batchnode rect:spriteFrame.rect rotated:spriteFrame.rotated capInsets:CGRectZero];
  466. // Reset insets
  467. insetLeft_ = 0;
  468. insetTop_ = 0;
  469. insetRight_ = 0;
  470. insetBottom_ = 0;
  471. }
  472. - (void)setCapInsets:(CGRect)capInsets
  473. {
  474. CGSize contentSize = contentSize_;
  475. [self updateWithBatchNode:scale9Image rect:spriteRect rotated:spriteFrameRotated_ capInsets:capInsets];
  476. [self setContentSize:contentSize];
  477. }
  478. - (void) updateCapInset_
  479. {
  480. CGRect insets;
  481. if (insetLeft_ == 0 && insetTop_ == 0 && insetRight_ == 0 && insetBottom_ == 0)
  482. {
  483. insets = CGRectZero;
  484. }
  485. else
  486. {
  487. if (spriteFrameRotated_)
  488. {
  489. insets = CGRectMake(spriteRect.origin.x + insetBottom_,
  490. spriteRect.origin.y + insetLeft_,
  491. spriteRect.size.width-insetRight_-insetLeft_,
  492. spriteRect.size.height-insetTop_-insetBottom_);
  493. }
  494. else
  495. {
  496. insets = CGRectMake(spriteRect.origin.x + insetLeft_,
  497. spriteRect.origin.y + insetTop_,
  498. spriteRect.size.width-insetLeft_-insetRight_,
  499. spriteRect.size.height-insetTop_-insetBottom_);
  500. }
  501. }
  502. [self setCapInsets:insets];
  503. }
  504. - (void) setInsetLeft:(float)insetLeft
  505. {
  506. insetLeft_ = insetLeft;
  507. [self updateCapInset_];
  508. }
  509. - (void) setInsetTop:(float)insetTop
  510. {
  511. insetTop_ = insetTop;
  512. [self updateCapInset_];
  513. }
  514. - (void) setInsetRight:(float)insetRight
  515. {
  516. insetRight_ = insetRight;
  517. [self updateCapInset_];
  518. }
  519. - (void) setInsetBottom:(float)insetBottom
  520. {
  521. insetBottom_ = insetBottom;
  522. [self updateCapInset_];
  523. }
  524. #pragma mark -
  525. #pragma mark CCScale9Sprite Public Methods
  526. - (CCScale9Sprite *)resizableSpriteWithCapInsets:(CGRect)capInsets
  527. {
  528. return [[[CCScale9Sprite alloc] initWithBatchNode:scale9Image rect:spriteRect capInsets:capInsets] autorelease];
  529. }
  530. #pragma mark -
  531. #pragma mark Overridden
  532. - (void)visit
  533. {
  534. if (positionsAreDirty_)
  535. {
  536. [self updatePosition];
  537. positionsAreDirty_ = NO;
  538. }
  539. [super visit];
  540. }
  541. @end