diff --git a/Spriter/Resources/monster-hd.plist b/Spriter/Resources/monster-hd.plist
index 136b45b..849914a 100644
--- a/Spriter/Resources/monster-hd.plist
+++ b/Spriter/Resources/monster-hd.plist
@@ -7,301 +7,301 @@
foot_0.png
frame
- {{1,100},{264,294}}
+ {{1,54},{137,149}}
offset
- {-4,-4}
+ {-1,-2}
rotated
sourceColorRect
- {{4,17},{264,294}}
+ {{1,8},{137,149}}
sourceSize
- {280,320}
+ {141,161}
foot_a.png
frame
- {{296,100},{244,294}}
+ {{151,54},{122,148}}
offset
- {-10,-3}
+ {-5,-2}
rotated
sourceColorRect
- {{3,19},{244,294}}
+ {{2,10},{122,148}}
sourceSize
- {270,326}
+ {136,164}
forearm_0.png
frame
- {{1,936},{150,190}}
+ {{1,549},{76,96}}
offset
- {1,3}
+ {0,2}
rotated
sourceColorRect
- {{11,11},{150,190}}
+ {{5,5},{76,96}}
sourceSize
- {170,218}
+ {86,110}
forearm_a.png
frame
- {{552,1025},{182,138}}
+ {{298,540},{91,70}}
offset
- {-1,-3}
+ {0,-2}
rotated
sourceColorRect
- {{8,13},{182,138}}
+ {{5,7},{91,70}}
sourceSize
- {200,158}
+ {101,80}
hand_0_0.png
frame
- {{552,870},{186,154}}
+ {{203,509},{94,77}}
offset
- {-3,14}
+ {-1,7}
rotated
sourceColorRect
- {{15,27},{186,154}}
+ {{8,14},{94,77}}
sourceSize
- {222,236}
+ {112,119}
hand_0_1.png
frame
- {{192,975},{188,154}}
+ {{352,462},{94,77}}
offset
- {-2,14}
+ {-1,7}
rotated
sourceColorRect
- {{15,27},{188,154}}
+ {{8,14},{94,77}}
sourceSize
- {222,236}
+ {112,119}
hand_0_2.png
frame
- {{395,838},{188,156}}
+ {{106,473},{96,79}}
offset
- {-1,14}
+ {-1,7}
rotated
-
+
sourceColorRect
- {{16,26},{188,156}}
+ {{7,13},{96,79}}
sourceSize
- {222,236}
+ {112,119}
hand_0_3.png
frame
- {{860,364},{194,162}}
+ {{413,380},{98,81}}
offset
- {1,10}
+ {1,5}
rotated
-
+
sourceColorRect
- {{15,27},{194,162}}
+ {{8,14},{98,81}}
sourceSize
- {222,236}
+ {112,119}
hand_a_0.png
frame
- {{739,997},{130,184}}
+ {{98,553},{66,93}}
offset
- {-19,0}
+ {-10,0}
rotated
sourceColorRect
- {{21,22},{130,184}}
+ {{10,11},{66,93}}
sourceSize
- {210,228}
+ {106,115}
hand_a_1.png
frame
- {{1,1087},{140,188}}
+ {{436,284},{70,95}}
offset
- {-14,-2}
+ {-7,-1}
rotated
-
+
sourceColorRect
- {{21,22},{140,188}}
+ {{11,11},{70,95}}
sourceSize
- {210,228}
+ {106,115}
hand_a_2.png
frame
- {{1,795},{140,196}}
+ {{436,184},{70,99}}
offset
- {-16,2}
+ {-8,1}
rotated
-
+
sourceColorRect
- {{19,14},{140,196}}
+ {{10,7},{70,99}}
sourceSize
- {210,228}
+ {106,115}
hand_a_3.png
frame
- {{198,838},{136,196}}
+ {{252,440},{68,99}}
offset
- {-18,2}
+ {-9,1}
rotated
sourceColorRect
- {{19,14},{136,196}}
+ {{10,7},{68,99}}
sourceSize
- {210,228}
+ {106,115}
head_0.png
frame
- {{553,611},{258,266}}
+ {{279,309},{130,133}}
offset
- {-13,6}
+ {-7,3}
rotated
sourceColorRect
- {{3,13},{258,266}}
+ {{1,7},{130,133}}
sourceSize
- {290,304}
+ {146,153}
head_1.png
frame
- {{587,364},{246,272}}
+ {{298,184},{124,137}}
offset
- {-7,3}
+ {-4,2}
rotated
sourceColorRect
- {{15,13},{246,272}}
+ {{7,6},{124,137}}
sourceSize
- {290,304}
+ {146,153}
head_2.png
frame
- {{1,548},{246,268}}
+ {{1,285},{124,135}}
offset
- {-7,5}
+ {-4,3}
rotated
sourceColorRect
- {{15,13},{246,268}}
+ {{7,6},{124,135}}
sourceSize
- {290,304}
+ {146,153}
head_3.png
frame
- {{282,478},{246,270}}
+ {{143,245},{124,135}}
offset
- {-7,2}
+ {-4,1}
rotated
sourceColorRect
- {{15,15},{246,270}}
+ {{7,8},{124,135}}
sourceSize
- {290,304}
+ {146,153}
pelvis_0.png
frame
- {{1,365},{182,280}}
+ {{1,192},{92,141}}
offset
- {-3,-10}
+ {-2,-5}
rotated
sourceColorRect
- {{17,20},{182,280}}
+ {{8,10},{92,141}}
sourceSize
- {222,300}
+ {112,151}
shadow_idle.png
frame
- {{1,1},{628,98}}
+ {{1,1},{317,52}}
offset
- {1,5}
+ {0,3}
rotated
sourceColorRect
- {{9,11},{628,98}}
+ {{3,4},{317,52}}
sourceSize
- {644,130}
+ {323,66}
shoulder_0.png
frame
- {{860,559},{208,160}}
+ {{1,468},{104,80}}
offset
- {0,4}
+ {0,2}
rotated
-
+
sourceColorRect
- {{11,11},{208,160}}
+ {{6,6},{104,80}}
sourceSize
- {230,190}
+ {116,96}
shoulder_a.png
frame
- {{270,725},{112,212}}
+ {{1,410},{57,107}}
offset
- {-3,3}
+ {-2,2}
rotated
sourceColorRect
- {{13,7},{112,212}}
+ {{6,3},{57,107}}
sourceSize
- {144,232}
+ {73,117}
thigh_0.png
frame
- {{296,345},{132,290}}
+ {{151,177},{67,146}}
offset
- {1,3}
+ {0,2}
rotated
sourceColorRect
- {{17,9},{132,290}}
+ {{8,4},{67,146}}
sourceSize
- {164,314}
+ {83,158}
thigh_a.png
frame
- {{820,768},{228,202}}
+ {{137,370},{114,102}}
offset
- {-6,7}
+ {-3,4}
rotated
-
+
sourceColorRect
- {{7,5},{228,202}}
+ {{4,2},{114,102}}
sourceSize
- {254,226}
+ {128,114}
torso_0.png
frame
- {{630,1},{362,376}}
+ {{319,1},{182,191}}
offset
- {0,-10}
+ {0,-4}
rotated
sourceColorRect
- {{0,20},{362,376}}
+ {{0,8},{182,191}}
sourceSize
- {362,396}
+ {182,199}
metadata
@@ -311,9 +311,9 @@
realTextureFileName
monster-hd.png
size
- {1024,2048}
+ {512,1024}
smartupdate
- $TexturePacker:SmartUpdate:ed4bfc52c7e3af6b78c62ff4259e6568$
+ $TexturePacker:SmartUpdate:666a62867467761fed5c96c91f5409a9$
textureFileName
monster-hd.png
diff --git a/Spriter/Resources/monster-hd.png b/Spriter/Resources/monster-hd.png
index 5073d49..248791f 100644
Binary files a/Spriter/Resources/monster-hd.png and b/Spriter/Resources/monster-hd.png differ
diff --git a/Spriter/Resources/monster.plist b/Spriter/Resources/monster.plist
index 5a97bc0..5f14458 100644
--- a/Spriter/Resources/monster.plist
+++ b/Spriter/Resources/monster.plist
@@ -7,301 +7,301 @@
foot_0.png
frame
- {{1,54},{137,149}}
+ {{1,28},{68,76}}
offset
- {-1,-2}
+ {-1,-1}
rotated
sourceColorRect
- {{1,8},{137,149}}
+ {{1,4},{68,76}}
sourceSize
- {141,161}
+ {72,82}
foot_a.png
frame
- {{151,54},{122,148}}
+ {{78,28},{63,75}}
offset
- {-5,-2}
+ {-3,-1}
rotated
sourceColorRect
- {{2,10},{122,148}}
+ {{0,5},{63,75}}
sourceSize
- {136,164}
+ {69,83}
forearm_0.png
frame
- {{1,549},{76,96}}
+ {{215,166},{40,50}}
offset
- {0,2}
+ {0,1}
rotated
-
+
sourceColorRect
- {{5,5},{76,96}}
+ {{2,2},{40,50}}
sourceSize
- {86,110}
+ {44,56}
forearm_a.png
frame
- {{298,540},{91,70}}
+ {{51,281},{48,37}}
offset
- {0,-2}
+ {-1,0}
rotated
sourceColorRect
- {{5,7},{91,70}}
+ {{1,2},{48,37}}
sourceSize
- {101,80}
+ {52,41}
hand_0_0.png
frame
- {{203,509},{94,77}}
+ {{205,267},{45,41}}
offset
- {-1,7}
+ {1,4}
rotated
sourceColorRect
- {{8,14},{94,77}}
+ {{7,6},{45,41}}
sourceSize
- {112,119}
+ {57,61}
hand_0_1.png
frame
- {{352,462},{94,77}}
+ {{157,266},{47,41}}
offset
- {-1,7}
+ {0,4}
rotated
sourceColorRect
- {{8,14},{94,77}}
+ {{5,6},{47,41}}
sourceSize
- {112,119}
+ {57,61}
hand_0_2.png
frame
- {{106,473},{96,79}}
+ {{1,294},{47,41}}
offset
- {-1,7}
+ {0,4}
rotated
sourceColorRect
- {{7,13},{96,79}}
+ {{5,6},{47,41}}
sourceSize
- {112,119}
+ {57,61}
hand_0_3.png
frame
- {{413,380},{98,81}}
+ {{1,250},{49,43}}
offset
- {1,5}
+ {1,3}
rotated
sourceColorRect
- {{8,14},{98,81}}
+ {{5,6},{49,43}}
sourceSize
- {112,119}
+ {57,61}
hand_a_0.png
frame
- {{98,553},{66,93}}
+ {{107,266},{34,49}}
offset
- {-10,0}
+ {-5,0}
rotated
sourceColorRect
- {{10,11},{66,93}}
+ {{5,5},{34,49}}
sourceSize
- {106,115}
+ {54,59}
hand_a_1.png
frame
- {{436,284},{70,95}}
+ {{215,217},{38,49}}
offset
- {-7,-1}
+ {-4,0}
rotated
sourceColorRect
- {{11,11},{70,95}}
+ {{4,5},{38,49}}
sourceSize
- {106,115}
+ {54,59}
hand_a_2.png
frame
- {{436,184},{70,99}}
+ {{55,244},{36,51}}
offset
- {-8,1}
+ {-4,1}
rotated
-
+
sourceColorRect
- {{10,7},{70,99}}
+ {{5,3},{36,51}}
sourceSize
- {106,115}
+ {54,59}
hand_a_3.png
frame
- {{252,440},{68,99}}
+ {{132,229},{36,51}}
offset
- {-9,1}
+ {-5,1}
rotated
sourceColorRect
- {{10,7},{68,99}}
+ {{4,3},{36,51}}
sourceSize
- {106,115}
+ {54,59}
head_0.png
frame
- {{279,309},{130,133}}
+ {{153,99},{66,70}}
offset
- {-7,3}
+ {-3,2}
rotated
sourceColorRect
- {{1,7},{130,133}}
+ {{1,2},{66,70}}
sourceSize
- {146,153}
+ {74,78}
head_1.png
frame
- {{298,184},{124,137}}
+ {{144,166},{62,70}}
offset
- {-4,2}
+ {-1,1}
rotated
sourceColorRect
- {{7,6},{124,137}}
+ {{5,3},{62,70}}
sourceSize
- {146,153}
+ {74,78}
head_2.png
frame
- {{1,285},{124,135}}
+ {{1,145},{62,70}}
offset
- {-4,3}
+ {-1,2}
rotated
sourceColorRect
- {{7,6},{124,135}}
+ {{5,2},{62,70}}
sourceSize
- {146,153}
+ {74,78}
head_3.png
frame
- {{143,245},{124,135}}
+ {{73,128},{62,70}}
offset
- {-4,1}
+ {-1,1}
rotated
sourceColorRect
- {{7,8},{124,135}}
+ {{5,3},{62,70}}
sourceSize
- {146,153}
+ {74,78}
pelvis_0.png
frame
- {{1,192},{92,141}}
+ {{1,97},{47,71}}
offset
- {-2,-5}
+ {-1,-1}
rotated
sourceColorRect
- {{8,10},{92,141}}
+ {{4,4},{47,71}}
sourceSize
- {112,151}
+ {57,77}
shadow_idle.png
frame
- {{1,1},{317,52}}
+ {{1,1},{159,26}}
offset
- {0,3}
+ {0,1}
rotated
sourceColorRect
- {{3,4},{317,52}}
+ {{2,3},{159,26}}
sourceSize
- {323,66}
+ {163,34}
shoulder_0.png
frame
- {{1,468},{104,80}}
+ {{1,208},{53,41}}
offset
- {0,2}
+ {0,1}
rotated
sourceColorRect
- {{6,6},{104,80}}
+ {{3,3},{53,41}}
sourceSize
- {116,96}
+ {59,49}
shoulder_a.png
frame
- {{1,410},{57,107}}
+ {{224,99},{30,56}}
offset
- {-2,2}
+ {-1,1}
rotated
-
+
sourceColorRect
- {{6,3},{57,107}}
+ {{3,1},{30,56}}
sourceSize
- {73,117}
+ {38,60}
thigh_0.png
frame
- {{151,177},{67,146}}
+ {{78,92},{35,74}}
offset
- {0,2}
+ {0,1}
rotated
sourceColorRect
- {{8,4},{67,146}}
+ {{4,2},{35,74}}
sourceSize
- {83,158}
+ {43,80}
thigh_a.png
frame
- {{137,370},{114,102}}
+ {{72,191},{59,52}}
offset
- {-3,4}
+ {-2,2}
rotated
sourceColorRect
- {{4,2},{114,102}}
+ {{1,1},{59,52}}
sourceSize
- {128,114}
+ {65,58}
torso_0.png
frame
- {{319,1},{182,191}}
+ {{161,1},{86,97}}
offset
- {0,-4}
+ {-3,-2}
rotated
-
+
sourceColorRect
- {{0,8},{182,191}}
+ {{0,4},{86,97}}
sourceSize
- {182,199}
+ {92,101}
metadata
@@ -311,9 +311,9 @@
realTextureFileName
monster.png
size
- {512,1024}
+ {256,512}
smartupdate
- $TexturePacker:SmartUpdate:d7912141bc6dded8e7d4f2aee97d8ce9$
+ $TexturePacker:SmartUpdate:32044d1553066c11776146395049de1d$
textureFileName
monster.png
diff --git a/Spriter/Resources/monster.png b/Spriter/Resources/monster.png
index 248791f..65f5e8c 100644
Binary files a/Spriter/Resources/monster.png and b/Spriter/Resources/monster.png differ
diff --git a/Spriter/Resources/monster.tps b/Spriter/Resources/monster.tps
index b53e1dc..8812515 100644
Binary files a/Spriter/Resources/monster.tps and b/Spriter/Resources/monster.tps differ
diff --git a/Spriter/TGSpriterNode.h b/Spriter/TGSpriterNode.h
index 5ba5e91..8c0f961 100644
--- a/Spriter/TGSpriterNode.h
+++ b/Spriter/TGSpriterNode.h
@@ -8,12 +8,11 @@
/*
Notes:
-
+
1.) WARNING
- This is a fast and dirty implementation based on the spec for the BETA version. The spec
- WILL change with the development of Spriter 1.0 and this code will change with it. This
- code should be considered high unstable until the release of 1.0.
+ This is a fast and dirty implementation based on the spec for the BETA version (V2).
+ This code will change as features are added to the beta build.
2.) NSXMLParser
@@ -22,15 +21,17 @@
was additional dependcies was important to avoid. If this ends up in cocos2d proper and
they wish to use a faster parser, then a lot of the parsing code included can be cleaned up.
- This isn't the cleanest parsing implementation. I building up a simple tree as the
+ This isn't the cleanest parsing implementation. I'm building up a simple tree as the
SAX parser runs its course, and then I use that tree to build up animations and frames.
- 3.) Tweening
-
- Tweening isn't in the beta spec.
+ 3.) TGSpriterNode without a sprite sheet
+ Since I only use this as part of a batch node, that is the only method I am supporting at the
+ moment. At some point I will add support back in for using this node with out a sprite sheet.
+ I also plan on adding a method for batching the drawing of this node with other TGSpriterNodes
+ using the same sprite sheet. Reduce draw calls for the win!
-*/
+ */
#import
#import "cocos2d.h"
@@ -90,6 +91,8 @@
CGPoint anchorPoint_;
double rotation_;
int spin_;
+ double scaleX_;
+ double scaleY_;
}
@property int file;
@@ -99,6 +102,8 @@
@property CGPoint anchorPoint;
@property double rotation;
@property int spin;
+@property double scaleX;
+@property double scaleY;
+(id) spriterTimelineKey;
@@ -136,15 +141,33 @@
@end
+@interface TGSpriterSprite : CCSprite {
+ int folder;
+ int file;
+ NSString * displayFrameName;
+}
+@property int folder;
+@property int file;
+@property (nonatomic, retain) NSString * displayFrameName;
+
+@end
+
+#pragma mark -
+#pragma mark The Important Stuff
+/*
+ This is the actual node you should use.
+ */
@interface TGSpriterNode : CCNode {
NSXMLParser * parser_;
NSString * characterName_;
- NSMutableDictionary * animations_; // {name: TGSpriterAnimation,...}
- NSMutableDictionary * frames_; // {name: TGSpriterFrame,..}
+ NSMutableDictionary * animations_;
+ NSMutableDictionary * frames_;
- NSMutableDictionary * files_;
+ int * folderIndexes_;
+ int * flattenedFolder_;
+ NSMutableArray * files_; // an array of arrays, much faster access time [O(1)] than a dict lookup
TGSpriterAnimation * curAnimation_;
TGSpriterMainlineKey * curKeyFrame_;
@@ -161,14 +184,39 @@
// parsing vars
TGSpriterConfigNode * configRoot_;
TGSpriterConfigNode * curConfigNode_;
+
+ // vars for manipulating scml positions to match game world scale and coords
+ double sdScale_;
+ CGPoint offset_;
+
+ BOOL smoothTransitions_;
+ TGSpriterAnimation * prevAnimation_;
+
+ double playbackSpeed_;
+ BOOL smoothTransitions;
}
-+(id) spriterNodeWithFiles:(NSString*)scmlFile;
+/*
+ smoothTransitions is an experimental property for smoothly moving to a new animation when
+ runAnimation is called in the middle of another animation. This does not work properly at
+ this time, but it is something I plan on looking into again
+ */
+@property BOOL smoothTransitions;
+@property double playbackSpeed; // defaults to 1, allows you to play the animation faster or slower
+
+(id) spriterNodeWithFiles:(NSString *)scmlFile spriteSheet:(NSString*)spriteSheet;
--(id) initNodeWithFiles:(NSString*)scmlFile;
--(id) initNodeWithFiles:(NSString*)scmlFile spriteSheet:(NSString*)spriteSheet;
+
+// sdScale defaults to 0.5, it assumes that the Spriter assets were made with retina sized assets
+// offset lets you correct for spriter animations that were not assembled in the center of the viewport
++(id) spriterNodeWithFiles:(NSString *)scmlFile spriteSheet:(NSString*)spriteSheet sdScale:(double)sdScale offset:(CGPoint)offse;
+-(id) initNodeWithFiles:(NSString*)scmlFile spriteSheet:(NSString*)spriteSheet sdScale:(double)sdScale offset:(CGPoint)offset;
// call this to run an animation
-(void) runAnimation:(NSString*)animation;
+// hooks for classes that override this for custom behavior
+// should we be message passing to a delegate instead?
+-(BOOL) animationEnded;
+-(void) animationFrameChanged;
+
@end
\ No newline at end of file
diff --git a/Spriter/TGSpriterNode.m b/Spriter/TGSpriterNode.m
index a2e5d75..ccfc26f 100644
--- a/Spriter/TGSpriterNode.m
+++ b/Spriter/TGSpriterNode.m
@@ -30,7 +30,7 @@ +(id) configNode:(NSString*)name {
@implementation TGSpriterObjectRef
-@synthesize timelineId=timelineId_, timelineKey=timelineKey;
+@synthesize timelineId=timelineId_, timelineKey=timelineKey_;
+(id) spriterObjectRef {
return [[super alloc] init];
@@ -96,7 +96,7 @@ -(void) dealloc {
@implementation TGSpriterTimelineKey
-@synthesize file=file_, folder=folder_, position=position_, anchorPoint=anchorPoint_, rotation=rotation_, startsAt=startsAt_, spin=spin_;
+@synthesize file=file_, folder=folder_, position=position_, anchorPoint=anchorPoint_, rotation=rotation_, startsAt=startsAt_, spin=spin_, scaleX=scaleX_, scaleY=scaleY_;
+(id)spriterTimelineKey {
return [[super alloc] init];
@@ -131,40 +131,44 @@ -(void) addTimeline:(TGSpriterTimeline*)timeline {
@end
+
+@implementation TGSpriterSprite
+
+@synthesize folder, file, displayFrameName;
+
+-(void) dealloc {
+ if (displayFrameName) {
+ [displayFrameName release];
+ }
+
+ [super dealloc];
+}
+
+@end
+
+#pragma mark -
#pragma mark TGSpriterNode
@implementation TGSpriterNode
+@synthesize smoothTransitions, playbackSpeed=playbackSpeed_;
-+(id) spriterNodeWithFiles:(NSString*)scmlFile {
- return [[[super alloc] initNodeWithFiles:scmlFile] autorelease];
++(id) spriterNodeWithFiles:(NSString *)scmlFile spriteSheet:(NSString*)spriteSheet sdScale:(double)sdScale offset:(CGPoint)offset {
+ return [[[super alloc] initNodeWithFiles:scmlFile spriteSheet:spriteSheet sdScale:sdScale offset:offset] autorelease];
}
-
+(id) spriterNodeWithFiles:(NSString *)scmlFile spriteSheet:(NSString*)spriteSheet {
- return [[[super alloc] initNodeWithFiles:scmlFile spriteSheet:spriteSheet] autorelease];
-}
--(id) initNodeWithFiles:(NSString*)scmlFile {
- return nil; // not implemented
- if ( (self = [super init]) ) {
- frames_ = [[[NSMutableDictionary alloc] init] retain];
- animations_ = [[[NSMutableDictionary alloc] init] retain];
- files_ = [[[NSMutableDictionary alloc] init] retain];
-
- NSString * path = [[CCFileUtils sharedFileUtils] fullPathFromRelativePath:scmlFile];
- NSData * scmlData = [NSData dataWithContentsOfFile:path];
- parser_ = [[[NSXMLParser alloc] initWithData:scmlData] retain];
- parser_.delegate = self;
- [parser_ parse];
- }
-
- return self;
+ return [[[super alloc] initNodeWithFiles:scmlFile spriteSheet:spriteSheet sdScale:0.5 offset:ccp(0,0)] autorelease];
}
--(id) initNodeWithFiles:(NSString*)scmlFile spriteSheet:(NSString*)spriteSheet {
+-(id) initNodeWithFiles:(NSString*)scmlFile spriteSheet:(NSString*)spriteSheet sdScale:(double)sdScale offset:(CGPoint)offset {
if ( (self = [super init]) ) {
+ sdScale_ = sdScale; // assumes animation was built with retina assets
+ offset_ = offset;
+ playbackSpeed_ = 1.0;
+
frames_ = [[[NSMutableDictionary alloc] init] retain];
animations_ = [[[NSMutableDictionary alloc] init] retain];
- files_ = [[[NSMutableDictionary alloc] init] retain];
+ files_ = [[[NSMutableArray alloc] init] retain];
spriterNodes_ = [[[NSMutableArray alloc] init] retain];
useBatchNode_ = TRUE;
@@ -216,11 +220,20 @@ -(void) dealloc {
-(void) runAnimation:(NSString*)animation {
[self unschedule:@selector(update:)];
+ //CCLOG(@"running animation: %@", animation);
+
duration_ = 0;
frameIdx_ = 0;
+ if (smoothTransitions) {
+ prevAnimation_ = curAnimation_;
+ }
curAnimation_ = [animations_ objectForKey:animation];
- curKeyFrame_ = [curAnimation_.mainline objectAtIndex:0];
- nextKeyFrame_ = [curAnimation_.mainline objectAtIndex:(frameIdx_+1)%[curAnimation_.mainline count]];
+ if (smoothTransitions) {
+ nextKeyFrame_ = [curAnimation_.mainline objectAtIndex:0];
+ } else {
+ curKeyFrame_ = [curAnimation_.mainline objectAtIndex:0];
+ nextKeyFrame_ = [curAnimation_.mainline objectAtIndex:(frameIdx_+1)%[curAnimation_.mainline count]];
+ }
[self schedule:@selector(update:)];
}
@@ -228,33 +241,57 @@ -(void) runAnimation:(NSString*)animation {
-(void) update:(ccTime)dt {
// increment the time
duration_ += dt;
- int milliseconds = duration_ * 10000;
+ int milliseconds = duration_ * 1000 * playbackSpeed_;
int startTime = curKeyFrame_.startsAt;
int endTime = nextKeyFrame_.startsAt;
- if (nextKeyFrame_.startsAt == 0) {
+ BOOL lastFrame = frameIdx_+1 == [curAnimation_.mainline count];
+ if (prevAnimation_) {
+ endTime = MAX(0, prevAnimation_.duration - curKeyFrame_.startsAt);
+ } else if (nextKeyFrame_.startsAt == 0) {
endTime = curAnimation_.duration;
}
// swap the key frames if we passed the duration
if (milliseconds > endTime) {
- curKeyFrame_ = nextKeyFrame_;
- frameIdx_ = (frameIdx_+1)%[curAnimation_.mainline count];
- nextKeyFrame_ = [curAnimation_.mainline objectAtIndex:(frameIdx_+1)%[curAnimation_.mainline count]];
- startTime = curKeyFrame_.startsAt;
- endTime = nextKeyFrame_.startsAt;
- }
- if (milliseconds > curAnimation_.duration) {
- duration_ -= milliseconds * 0.0001;
- milliseconds -= 10000;
+ if (prevAnimation_) {
+ prevAnimation_ = nil; // transition has occured
+ frameIdx_ = -1;
+ duration_ = dt;
+ milliseconds = duration_ * 1000 * playbackSpeed_;
+ }
+ if (!lastFrame || (lastFrame && [self animationEnded])) {
+ curKeyFrame_ = nextKeyFrame_;
+ frameIdx_ = (frameIdx_+1)%[curAnimation_.mainline count];
+ nextKeyFrame_ = [curAnimation_.mainline objectAtIndex:(frameIdx_+1)%[curAnimation_.mainline count]];
+ startTime = curKeyFrame_.startsAt;
+ endTime = nextKeyFrame_.startsAt;
+ if (nextKeyFrame_.startsAt == 0) {
+ endTime = curAnimation_.duration;
+ }
+ [self animationFrameChanged];
+ } else {
+ return; // early exit
+ }
+ if (milliseconds > curAnimation_.duration && frameIdx_ == 0) {
+ duration_ -= curAnimation_.duration * (0.001/playbackSpeed_);
+ milliseconds -= curAnimation_.duration * playbackSpeed_;
+ }
}
// hide existing nodes (this is more important later when we have temp objects)
- for (CCNode * n in spriterNodes_) {
+ for (TGSpriterSprite * n in spriterNodes_) {
[n setVisible:FALSE];
+ n.folder = -1;
+ n.file = -1;
}
// interpolation
double interpolationFactor = ((milliseconds - startTime)/(1.0*(endTime-startTime)));
+ if (interpolationFactor == INFINITY) { interpolationFactor = 0.0; }
+ if (interpolationFactor < 0) { interpolationFactor = 0.0; }
+ if (interpolationFactor > 1) { interpolationFactor = 1.0; }
+ if (interpolationFactor == NAN) { interpolationFactor = 1.0; }
+
// walk through mainline objects
for (int keyIdx = 0; keyIdx < [curKeyFrame_.objectRefs count]; keyIdx++) {
// look up the current and next timeline keys
@@ -263,32 +300,49 @@ -(void) update:(ccTime)dt {
TGSpriterTimeline * objectTimeline = [curAnimation_.timelines objectAtIndex:[curObjectRef timelineId]];
- TGSpriterTimelineKey * curTimelineKey = [objectTimeline.keys objectAtIndex:[curObjectRef timelineKey]];
+ TGSpriterTimelineKey * curTimelineKey;
+ if (smoothTransitions && prevAnimation_) {
+ TGSpriterTimeline * curObjectTimeline = [prevAnimation_.timelines objectAtIndex:[curObjectRef timelineId]];
+ curTimelineKey = [curObjectTimeline.keys objectAtIndex:[curObjectRef timelineKey]];
+ } else {
+ curTimelineKey = [objectTimeline.keys objectAtIndex:[curObjectRef timelineKey]];
+ }
TGSpriterTimelineKey * nextTimelineKey = [objectTimeline.keys objectAtIndex:[nextObjectRef timelineKey]];
// Get the display frame
- NSString * displayFrameName = [files_ objectForKey:[NSString stringWithFormat:@"%d-%d", [curTimelineKey folder], [curTimelineKey file]]];
+ NSString * displayFrameName = [[files_ objectAtIndex:[curTimelineKey folder]] objectAtIndex:[curTimelineKey file]];
- CCSprite * sprite;
+ TGSpriterSprite * sprite;
// set this data to the first available spriterNode, create a new one if this animation has more objects
if (keyIdx >= [spriterNodes_ count]) {
- sprite = [CCSprite spriteWithSpriteFrameName:displayFrameName];
+ sprite = [TGSpriterSprite spriteWithSpriteFrameName:displayFrameName];
+ sprite.displayFrameName = displayFrameName;
[batchNode_ addChild:sprite];
[spriterNodes_ addObject:sprite];
} else {
sprite = [spriterNodes_ objectAtIndex:keyIdx];
- [sprite setDisplayFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:displayFrameName]];
+ if (![sprite.displayFrameName isEqualToString:displayFrameName]) {
+ sprite.displayFrameName = displayFrameName;
+ [sprite setDisplayFrame:
+ [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:displayFrameName]];
+ }
}
sprite.visible = TRUE;
+ sprite.folder = [curTimelineKey folder];
+ sprite.file = [curTimelineKey file];
sprite.position = ccp([self interpolate:curTimelineKey.position.x b:nextTimelineKey.position.x f:interpolationFactor],
[self interpolate:curTimelineKey.position.y b:nextTimelineKey.position.y f:interpolationFactor]);
sprite.anchorPoint = ccp([self interpolate:curTimelineKey.anchorPoint.x b:nextTimelineKey.anchorPoint.x f:interpolationFactor],
- [self interpolate:curTimelineKey.anchorPoint.y b:nextTimelineKey.anchorPoint.y f:interpolationFactor]);
+ [self interpolate:curTimelineKey.anchorPoint.y b:nextTimelineKey.anchorPoint.y f:interpolationFactor]);
+ sprite.scaleX = [self interpolate:curTimelineKey.scaleX b:nextTimelineKey.scaleX f:interpolationFactor];
+ sprite.scaleY = [self interpolate:curTimelineKey.scaleY b:nextTimelineKey.scaleY f:interpolationFactor];
double nextRotation = nextTimelineKey.rotation;
double curRotation = curTimelineKey.rotation;
- if (curTimelineKey.spin == 1 && (nextRotation-curRotation) < 0) {
+ if (fabs(curRotation-nextRotation) <= 0.001) { // There appears to be a spriter bug related to close FP numbers outputting the wrong spin. This solves that.
+ nextRotation = curRotation;
+ } else if (curTimelineKey.spin == 1 && (nextRotation-curRotation) < 0) {
nextRotation += 360;
} else if (curTimelineKey.spin == -1 && (nextRotation-curRotation) > 0) {
nextRotation -= 360;
@@ -298,10 +352,7 @@ -(void) update:(ccTime)dt {
}
-(double) interpolate:(double)a b:(double)b f:(double)f {
- if (f == INFINITY) { f = 0.0; }
- if (f < 0) { f = 0.0; }
- if (f > 1) { f = 1.0; }
- if (f == NAN) { f = 1.0; }
+ if (a == b) { return a; }
return a+(b-a)*f;
}
@@ -315,16 +366,15 @@ -(void)parserDidStartDocument:(NSXMLParser *)parser {
-(void)parserDidEndDocument:(NSXMLParser *)parser {
// load all frames
for (TGSpriterConfigNode * c in [[configRoot_.children objectAtIndex:0] children]) {
- CCLOG(@"%@", c.name);
+ //CCLOG(@"%@", c.name);
if ([[c name] isEqualToString:@"folder"]) {
+ NSMutableArray * folder = [[NSMutableArray alloc] init];
for (TGSpriterConfigNode * file in c.children) {
- CCLOG(@"%@: %d-%d => %@", c.name, [[c.properties objectForKey:@"id"] intValue], [[file.properties objectForKey:@"id"] intValue], [[file.properties objectForKey:@"name"] lastPathComponent]);
-
- NSString * fileKey = [NSString stringWithFormat:@"%d-%d", [[c.properties objectForKey:@"id"] intValue], [[file.properties objectForKey:@"id"] intValue]];
- [files_ setObject:[[file.properties objectForKey:@"name"] lastPathComponent] forKey:fileKey];
-
+ //CCLOG(@"%@: %d-%d => %@", c.name, [[c.properties objectForKey:@"id"] intValue], [[file.properties objectForKey:@"id"] intValue], [[file.properties objectForKey:@"name"] lastPathComponent]);
+ [folder addObject:[[file.properties objectForKey:@"name"] lastPathComponent]];
}
+ [files_ addObject:folder];
} else if ([[c name] isEqualToString:@"entity"]) {
// SpriterNode->[TGSpriterAnimation]->[TGSpriterFrame]->[TGSpriteObjectKey]
for (TGSpriterConfigNode * animation in c.children) {
@@ -334,7 +384,7 @@ -(void)parserDidEndDocument:(NSXMLParser *)parser {
spriterAnimation.name = [animation.properties objectForKey:@"name"];
spriterAnimation.duration = [[animation.properties objectForKey:@"length"] intValue];
- CCLOG(@"Parsing Animation: %@ (%d ms.)", spriterAnimation.name, (int)spriterAnimation.duration);
+ //CCLOG(@"Parsing Animation: %@ (%d ms.)", spriterAnimation.name, (int)spriterAnimation.duration);
for (TGSpriterConfigNode * animConfig in animation.children) {
// mainline
@@ -351,6 +401,7 @@ -(void)parserDidEndDocument:(NSXMLParser *)parser {
[mainlineKey addObjectRef:objectRef];
}
+ mainlineKey.startsAt = [[key.properties objectForKey:@"time"] intValue];
[spriterAnimation addKeyFrame:mainlineKey];
}
} else if ([[animConfig name] isEqualToString:@"timeline"]) {
@@ -364,11 +415,24 @@ -(void)parserDidEndDocument:(NSXMLParser *)parser {
timelineKey.folder = [[object.properties objectForKey:@"folder"] intValue];
timelineKey.file = [[object.properties objectForKey:@"file"] intValue];
- timelineKey.position = ccp([[object.properties objectForKey:@"x"] doubleValue],
- [[object.properties objectForKey:@"y"] doubleValue]);
- timelineKey.anchorPoint = ccp([[object.properties objectForKey:@"pivot_x"] doubleValue],
- [[object.properties objectForKey:@"pivot_y"] doubleValue]);
-
+ timelineKey.position = ccpMult(ccpAdd(ccp([[object.properties objectForKey:@"x"] doubleValue],
+ [[object.properties objectForKey:@"y"] doubleValue]), offset_), sdScale_);
+ if ([object.properties objectForKey:@"pivot_x"]) {
+ timelineKey.anchorPoint = ccp([[object.properties objectForKey:@"pivot_x"] doubleValue],
+ [[object.properties objectForKey:@"pivot_y"] doubleValue]);
+ } else {
+ timelineKey.anchorPoint = ccp(0,1);
+ }
+ if ([object.properties objectForKey:@"scale_x"]) {
+ timelineKey.scaleX = [[object.properties objectForKey:@"scale_x"] doubleValue];
+ } else {
+ timelineKey.scaleX = 1.0;
+ }
+ if ([object.properties objectForKey:@"scale_y"]) {
+ timelineKey.scaleY = [[object.properties objectForKey:@"scale_y"] doubleValue];
+ } else {
+ timelineKey.scaleY = 1.0;
+ }
timelineKey.startsAt = [[key.properties objectForKey:@"time"] intValue];
timelineKey.rotation = [[object.properties objectForKey:@"angle"] doubleValue];
@@ -392,111 +456,6 @@ -(void)parserDidEndDocument:(NSXMLParser *)parser {
continue;
}
-
- /*
- NSString * spriterFrameName = @"";
- TGSpriterFrame * spriterFrame = [TGSpriterFrame spriterFrame];
-
- for (TGSpriterConfigNode * frameNodes in c.children) {
- if ([frameNodes.name isEqualToString:@"name"]) {
- spriterFrameName = frameNodes.value;
- } else if ([frameNodes.name isEqualToString:@"sprite"]) {
- NSString * img;
- double x = 0, y = 0, angle=0, width = 0, height = 0;
- int opacity = 255;
- BOOL flipX = FALSE, flipY = FALSE;
- ccColor3B color = ccc3(255, 255, 255);
- for (TGSpriterConfigNode * spriteProp in frameNodes.children) {
- //CCLOG(@"\t%@: %@", spriteProp.name, spriteProp.value);
- if ([spriteProp.name isEqualToString:@"image"]) {
- img = [[spriteProp.value componentsSeparatedByString:@"\\"] lastObject];
- } else if ([spriteProp.name isEqualToString:@"x"]) {
- x = [spriteProp.value doubleValue];
- } else if ([spriteProp.name isEqualToString:@"y"]) {
- y = -[spriteProp.value doubleValue];
- } else if ([spriteProp.name isEqualToString:@"angle"]) {
- angle = -[spriteProp.value doubleValue];
- } else if ([spriteProp.name isEqualToString:@"opacity"]) {
- opacity = [spriteProp.value doubleValue] / 100.0 * 255;
- } else if ([spriteProp.name isEqualToString:@"flipX"]) {
- flipX = [spriteProp.value boolValue];
- } else if ([spriteProp.name isEqualToString:@"flipY"]) {
- flipY = [spriteProp.value boolValue];
- } else if ([spriteProp.name isEqualToString:@"color"]) {
- int c = [spriteProp.value intValue];
- int red = c / pow(256, 2);
- int green = (c - red * pow(256, 2)) / 256;
- int blue = c - red * pow(256, 2) - blue * 256;
- color = ccc3(red, green, blue);
- } else if ([spriteProp.name isEqualToString:@"width"]) {
- width = [spriteProp.value doubleValue];
- } else if ([spriteProp.name isEqualToString:@"height"]) {
- height = [spriteProp.value doubleValue];
- }
- }
- CCSprite * sprite;
- if (useBatchNode_) {
- sprite = [CCSprite spriteWithSpriteFrameName:img];
- } else {
- sprite = [CCSprite spriteWithFile:img];
- }
- sprite.anchorPoint = ccp(0,1);
- sprite.position = ccp(x,y);
- sprite.rotation = angle;
- sprite.flipX = flipX;
- sprite.flipY = flipY;
- sprite.color = color;
- sprite.scaleX = width / sprite.contentSize.width;
- sprite.scaleY = height / sprite.contentSize.height;
- sprite.visible = FALSE;
-
- if (useBatchNode_) {
- [batchNode_ addChild:sprite];
- } else {
- [self addChild:sprite];
- }
- [spriterFrame addSprite:sprite];
- }
- }
- [frames_ setObject:spriterFrame forKey:spriterFrameName];
- }
- */
-
- /*
- // load all animations
- for (TGSpriterConfigNode * c in [[configRoot_.children objectAtIndex:0] children]) {
- if (![[c name] isEqualToString:@"char"])
- continue;
-
- for (TGSpriterConfigNode * charNodes in c.children) {
- if ([charNodes.name isEqualToString:@"name"]) {
- //CCLOG(@"Character Name: %@", charNodes.value);
- continue;
- } else if ([charNodes.name isEqualToString:@"anim"]) {
- TGSpriterAnimation * animation = [TGSpriterAnimation spriterAnimation];
- NSString * animationName = @"";
- for (TGSpriterConfigNode * frames in charNodes.children) {
- if ([frames.name isEqualToString:@"name"]) { // animation name
- animationName = frames.value;
- } else if ([frames.name isEqualToString:@"frame"]) {
- NSString * frameName = @"";
- double frameDuration = 0;
- for (TGSpriterConfigNode * frameProp in frames.children) {
- if ([frameProp.name isEqualToString:@"name"]) {
- frameName = frameProp.value;
- } else if ([frameProp.name isEqualToString:@"duration"]) {
- // the spec stats milliseconds, but this doesn't match the reference implementation.
- frameDuration = [frameProp.value doubleValue]/100.0;// milliseconds?? should be 1000
- }
- }
- [animation addFrame:[frames_ objectForKey:frameName] duration:frameDuration];
- }
- }
- [animations_ setObject:animation forKey:animationName];
- }
- }
- }
- */
// clean up
if (configRoot_) {
@@ -529,4 +488,7 @@ -(void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
}
}
+-(BOOL) animationEnded { return TRUE;}
+-(void)animationFrameChanged {}
+
@end