Animation with large number of sprites in Cocos2d iOS? - ios

I have to animate(dancing) a character(guy) for about 6-7 seconds i.e 500-600 frames. I have done animation before by creating spritesheets using zwoptex and then loading it with CCSpriteFrameCache && CCSpriteBatchNode with the help of The Great Ray Wenderlich. But in this case frames are heavy in number i am not sure if iOS device will be able to sustain it. What is the best process to animate all these frames with as little overhead as possible. Can i change the fps while animating? any idea anyone??

Here I put code That use for add Animated Image Without use TexturePacker:
CCSprite *dog = [CCSprite spriteWithFile:#"dog1.gif"];
dog.position = ccp(winSize.width/2, winSize.height/2);
[self addChild:dog z:2];
NSMutableArray *animFrames = [NSMutableArray array];
for( int i=1;i<=5;i++)
{
NSString* file = [NSString stringWithFormat:#"dog%d.gif", i];
CCTexture2D* texture = [[CCTextureCache sharedTextureCache] addImage:file];
CGSize texSize = texture.contentSize;
CGRect texRect = CGRectMake(0, 0, texSize.width, texSize.height);
CCSpriteFrame* frame = [CCSpriteFrame frameWithTexture:texture rect:texRect];
[animFrames addObject:frame];
}
CCAnimation * animation = [CCAnimation animationWithSpriteFrames:animFrames];
animation.delayPerUnit = 0.07f;
animation.restoreOriginalFrame = YES;
CCAnimate *animAction = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:animation]];
[dog runAction:animAction];
Try with This code, I'm not sure might be helpful in your case:

Related

How to make Ray Animation like Candy Crush Saga application using Cocos2d V3 in iOS

I have created an application similar to Candy Crush Saga application using Cocos2d V3 in iPhone and iPad. I want the ray animation on candy. The ray should passed in different directions and at different distance. I have attached the Image for the reference.
I have also the sequence of animation Images of ray like,
Could any one can assist me how this can be done ?
To find the angle of rotation:
CGPoint difference = ccpSub(targetCloud.position, sourceCloud.position);
CGFloat rotationRadians = ccpToAngle(difference);
CGFloat rotationDegrees = -CC_RADIANS_TO_DEGREES(rotationRadians);
rotationDegrees -= 90.0f;
CGFloat rotateByDegrees = rotationDegrees - targetCloud.rotation;
To find the scale :
float dist = ccpDistance(targetCloud.position,sourceCloud.position);
CCSprite *line = [CCSprite spriteWithImageNamed:#"0_light.png"];
float scale = dist / line.boundingBox.size.width;
To create the animation :
-(CCActionSequence *)createRayAnimationFrom:(CGPoint)startPosition atAngle:(float)angle toScale:(float)scale
{
//Using Texture packer
CCSpriteBatchNode *batchNode = [CCSpriteBatchNode batchNodeWithFile:#"light.pvr.ccz"];
[self addChild:batchNode];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"light.plist"];
CCSprite *raySprite = [CCSprite spriteWithSpriteFrameName:#"0_light.png"];
raySprite.position = startPosition;
raySprite.anchorPoint = ccp(0.5, 0.0);
[batchNode addChild:raySprite];
NSMutableArray *animFrames = [NSMutableArray array];
for( int i=1;i<=12;i++)
{
CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:#"%d_light.png",i]];
[animFrames addObject:frame];
}
CCAnimation *animation = [CCAnimation animationWithSpriteFrames:animFrames];
animation.delayPerUnit = 0.1f;
animation.restoreOriginalFrame = YES;
CCActionAnimate *animAction = [CCActionAnimate actionWithAnimation:animation];
CCActionSequence *animSequence = [CCActionSequence actions:[CCActionRotateBy actionWithDuration:0.1 angle:angle],[CCActionScaleBy actionWithDuration:0.1 scaleX:1.0f scaleY:scale],animAction,[CCActionCallBlock actionWithBlock:^{
[CCActionRemove action];
}], nil];
[raySprite runAction:animSequence];
}
You have to call this function for each target cloud:
[self createRayAnimationFrom:sourceCloud atAngle:rotateByDegrees toScale:scale];

Sprite Frame Animation Cocos2d 3.0

I've been trying to make an animated sprite, they're are a lot of tutorials but they're all for Cocos2d 2.x. My sprite sheet is named flappbird.png and the .plist is named flappbird.plist
I have this code but every time i start the scene it just crashes, this is in my init method
// -----------------------------------------------------------------------
_player = [CCSprite spriteWithImageNamed:#"monster1.png"]; // comes from your .plist file
_player.position = ccp(self.contentSize.width/28,self.contentSize.height/2);
_player.physicsBody = [CCPhysicsBody bodyWithRect:(CGRect){CGPointZero, _player.contentSize} cornerRadius:0]; // 1
_player.physicsBody.collisionGroup = #"playerGroup";
_player.physicsBody.type = CCPhysicsBodyTypeStatic;
CCSpriteBatchNode *batchNode = [CCSpriteBatchNode batchNodeWithFile:#"monster1.png"];
[batchNode addChild:_player];
[self addChild:batchNode];
NSMutableArray *animFrames = [NSMutableArray array];
for(int i = 1; i < 5; i++)
{
CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:#"flapbird%d.png",i]];
[animFrames addObject:frame];
}
CCAnimation *animation = [CCAnimation animationWithSpriteFrames:animFrames delay:0.2f];
[_player runAction:[CCActionRepeatForever actionWithAction:[CCActionAnimate actionWithAnimation:animation]]];
[_physicsWorld addChild:_player];
// -----------------------------------------------------------------------
Animate sprite with spritesheet in Cocos2d 3.0
Make sure to add #import "CCAnimation.h" at the beginning of your code
Also add the sprite sheet after the self.userInteractionEnabled = YES; in the init
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"your.plist"];
No add all this where the sprite will be
//The sprite animation
NSMutableArray *walkAnimFrames = [NSMutableArray array];
for(int i = 1; i <= 7; ++i)
{
[walkAnimFrames addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName: [NSString stringWithFormat:#"monster%d.png", i]]];
}
CCAnimation *walkAnim = [CCAnimation
animationWithSpriteFrames:walkAnimFrames delay:0.1f]; //Speed in which the frames will go at
//Adding png to sprite
monstertest = [CCSprite spriteWithImageNamed:#"monster1.png"];
//Positioning the sprite
monstertest.position = ccp(self.contentSize.width/2,self.contentSize.height/2);
//Repeating the sprite animation
CCActionAnimate *animationAction = [CCActionAnimate actionWithAnimation:walkAnim];
CCActionRepeatForever *repeatingAnimation = [CCActionRepeatForever actionWithAction:animationAction];
//Animation continuously repeating
[monstertest runAction:repeatingAnimation];
//Adding the Sprite to the Scene
[self addChild:monstertest];
Hope this helps somebody :D Cheers

Endless Scrolling Background in SpriteKit

I am attempting to make a side scrolling game using Apple's SpriteKit. When wanting to make a endless scrolling background I came across this answer.
After implementing the solution it does appear to work although it drops my FPS significantly. This is probably due to the fact that the images positions are being recalculated on every frame.
I feel like it would be much better if I could use one or more SKAction calls to take care of this animation for me but I'm not certain how to implement it.
Thoughts?
The code I have so far in my scene class (this only animates the background across the screen once though)
- (void)addBackgroundTileAtPoint:(CGPoint)point {
SKSpriteNode *bg = [SKSpriteNode spriteNodeWithImageNamed:#"background"];
bg.anchorPoint = CGPointZero;
bg.position = point;
bg.name = #"background";
bg.zPosition = -99;
[self addChild:bg];
SKAction *sequence = [SKAction sequence:#[
[SKAction moveByX:-(bg.size.width * 2) y:0 duration:10],
[SKAction removeFromParent]
]];
[bg runAction: sequence];
}
I did a small component called SKScrollingNode for that particular need in my last open source project : SprityBird.
FPS was not an issue even with 3 or 4 layers (for parallax), but you may need to try it yourself.
To use it you just have to add it like any other node and giving it a scrollingSpeed likeso :
back = [SKScrollingNode scrollingNodeWithImageNamed:#"back" inContainerWidth:WIDTH(self)];
[back setScrollingSpeed:BACK_SCROLLING_SPEED];
[self addChild:back];
SKScrollingNode.h
#interface SKScrollingNode : SKSpriteNode
#property (nonatomic) CGFloat scrollingSpeed;
+ (id) scrollingNodeWithImageNamed:(NSString *)name inContainerWidth:(float) width;
- (void) update:(NSTimeInterval)currentTime;
#end
SKScrollingNode.m
#implementation SKScrollingNode
+ (id) scrollingNodeWithImageNamed:(NSString *)name inContainerWidth:(float) width
{
UIImage * image = [UIImage imageNamed:name];
SKScrollingNode * realNode = [SKScrollingNode spriteNodeWithColor:[UIColor clearColor] size:CGSizeMake(width, image.size.height)];
realNode.scrollingSpeed = 1;
float total = 0;
while(total<(width + image.size.width)){
SKSpriteNode * child = [SKSpriteNode spriteNodeWithImageNamed:name ];
[child setAnchorPoint:CGPointZero];
[child setPosition:CGPointMake(total, 0)];
[realNode addChild:child];
total+=child.size.width;
}
return realNode;
}
- (void) update:(NSTimeInterval)currentTime
{
[self.children enumerateObjectsUsingBlock:^(SKSpriteNode * child, NSUInteger idx, BOOL *stop) {
child.position = CGPointMake(child.position.x-self.scrollingSpeed, child.position.y);
if (child.position.x <= -child.size.width){
float delta = child.position.x+child.size.width;
child.position = CGPointMake(child.size.width*(self.children.count-1)+delta, child.position.y);
}
}];
}
#end
I've been working on a library for an infinite tile scroller, you can easily use it to create a scrolling background. Take a look at it:
RPTileScroller
I made an effort to make it the most efficient possible, but I am not a game developer. I tried it with my iPhone 5 with random colors tiles of 10x10 pixels, and is running on a solid 60 fps.

CCAnimate inside of CCSequence creates not CCFiniteTimeAction error

this is probably a very quick and easy answer for someone, but I'm having a hard time figuring it out as a noob. I'm trying to run my CCAnimation and then run a second action that removes the animation from the screen upon completion. Before I can get to that point I'm getting a "Incompatible pointer types sending 'CCAction *' to parameter of type 'CCFiniteTimeAction *'" error. I suspect I need to use something besides CCRepeat to run my animation, but I'm not sure what to replace it with. Thank you!!
NSMutableArray *crabAnimFrames = [NSMutableArray array];
for (int i=1; i<=10; i++) {
[crabAnimFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"bashCrab%d.png",i]]];
}
CCAnimation *crabAnim = [CCAnimation animationWithSpriteFrames:crabAnimFrames delay:0.1f];
CGSize winSize = [CCDirector sharedDirector].winSize;
float randomOffset = CCRANDOM_X_Y(-winSize.height * 0.25, winSize.height * 0.25);
render.node = [CCSprite spriteWithSpriteFrameName:#"bashCrab1.png"];
render.node.position = ccp(winSize.width * 0.25, winSize.height * 0.5 + randomOffset);
render.crabWalk = [CCRepeat actionWithAction:[CCAnimate actionWithAnimation:crabAnim] times:1];
[_batchNode addChild:render.node];
[render.node runAction:[CCSequence actions:render.crabWalk, nil]];
How is crabWalk defined? If it is CCAction* change it to CCFiniteTimeAction*.

game crashes 3-5 big sprites for background (1920*640 ~100kb each) ~ 400-500kb in each level

I've got a problem in my cocos2d game: In the Game's level layer I've 3-5 big sprites for background (1920*640 ~100kb each) ~ 400-500kb in each level. When I switch between menu and various game's level 4-5 times the game crashes to main IPhone menu
[[CCDirector sharedDirector] replaceScene:transition];
without this big sprites all work perfect!
-(id) init
{
....
if( (self=[super init])) {
_spriteBGLevel1 = [CCSprite spriteWithFile: [NSString stringWithFormat:#"level_fon_%i_1.png", _currentLevel]];
_spriteBGLevel1.anchorPoint = ccp(0, 0);
_spriteBGLevel1.position = CGPointMake(0.0, 0.0);
[self addChild:_spriteBGLevel1 z:-5];
_spriteBGLevel2 = [CCSprite spriteWithFile: [NSString stringWithFormat:#"level_fon_%i_2.png", _currentLevel]];
_spriteBGLevel2.anchorPoint = ccp(0, 0);
_spriteBGLevel2.position = CGPointMake(0.0, 0.0);
[self addChild:_spriteBGLevel2 z:-5];
_spriteBGLevel3 = [CCSprite spriteWithFile: [NSString stringWithFormat:#"level_fon_%i_3.png", _currentLevel]];
_spriteBGLevel3.anchorPoint = ccp(0, 0);
_spriteBGLevel3.position = CGPointMake(0.0, 0.0);
[self addChild:_spriteBGLevel3 z:-5];
....
- (void) dealloc
{
....
_spriteBGLevel1=nil;
_spriteBGLevel2=nil;
_spriteBGLevel3=nil;
[super dealloc];
}
Background.m
#import "Background.h"
#import "GameConfig.h"
#import "XMLReader.h"
#import "CCParallaxNode-Extras.h"
#import "SettingsManager.h"
#implementation Background
#synthesize backgrounds=_backgrounds;
#synthesize backgroundNode=_backgroundNode;
+(id) scene
{
CCScene *scene = [CCScene node];
Background *layer = [Background node];
[scene addChild: layer];
return scene;
}
-(id) init
{
if ((self = [super init]))
{
CGSize screenSize = [[CCDirector sharedDirector] winSize];
int currentLevel = [[SettingsManager sharedSettingsManager] getCurrentLevel];
_backgroundNode = [CCParallaxNode node];
_backgroundNode.anchorPoint = CGPointMake(0, 0);
_backgroundNode.position = CGPointMake(0, 0);
[self addChild:_backgroundNode z:-1];
NSData *xmlData = [NSData dataWithContentsOfFile:[[NSBundle bundleForClass:[self class]] pathForResource:#"gameScene" ofType:#"xml"]];
NSError *error = nil;
NSDictionary *dictionary = [XMLReader dictionaryForXMLData:xmlData error:&error];
NSDictionary *levelsDict = [dictionary valueForKeyPath:#"levels.level"];
NSDictionary *levelDict;
_backgrounds = [[[NSMutableArray alloc] init] retain];
// [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile: [NSString stringWithFormat:#"level_fon_%i.plist", currentLevel]];
for (levelDict in levelsDict)
{
int idLevel = [[levelDict valueForKeyPath:#"id"] intValue];
if(idLevel==currentLevel)
{
NSDictionary *fonsDict = [levelDict valueForKeyPath:#"background.fon"];
NSDictionary *fonDict;
for (fonDict in fonsDict){
NSString *name=[fonDict valueForKeyPath:#"name"];
int zIndex=[[fonDict valueForKeyPath:#"z"] intValue];
float ratio=[[fonDict valueForKeyPath:#"ratio"] floatValue];
float offsetx=[[fonDict valueForKeyPath:#"offsetx"] floatValue];
float offsety=[[fonDict valueForKeyPath:#"offsety"] floatValue];
if(zIndex<0)
{
//CCTexture2D* tex = [[CCTextureCache sharedTextureCache] addImage:[NSString stringWithFormat:#"%#", name]];
//CCSprite *fon_level_1 = [CCSprite spriteWithSpriteFrameName: [NSString stringWithFormat:#"%#", name]];
//CCSprite *fon_level_2 = [CCSprite spriteWithSpriteFrameName: [NSString stringWithFormat:#"%#", name]];
//CCSprite *fon_level_1 = [CCSprite spriteWithTexture:tex];
//CCSprite *fon_level_2 = [CCSprite spriteWithTexture:tex];
fon_level_1 = [CCSprite spriteWithFile:[NSString stringWithFormat:#"%#", name]];
fon_level_2 = [CCSprite spriteWithFile:[NSString stringWithFormat:#"%#", name]];
fon_level_1.anchorPoint = CGPointMake(0, 0);
fon_level_1.position = CGPointMake(0, 0);
fon_level_2.anchorPoint = CGPointMake(0, 0);
fon_level_2.position = CGPointMake(0, 0);
//[_backgroundNode addChild:fon_level_1 z:zIndex parallaxRatio:ccp(ratio, ratio) positionOffset:ccp(offsetx, offsety*screenSize.height)];
//[_backgroundNode addChild:fon_level_2 z:zIndex parallaxRatio:ccp(ratio, ratio) positionOffset:ccp(fon_level_1.contentSize.width, offsety*screenSize.height)];
[_backgrounds addObject:fon_level_1];
[_backgrounds addObject:fon_level_2];
fon_level_1=nil;
fon_level_2=nil;
}
}
break;
}
}
NSLog(#"count: %d",_backgrounds.count);
[self scheduleUpdate];
}
return self;
}
- (void)scheduleUpdate
{
[self schedule:#selector(updateBackgroud:)];
}
-(void) updateBackgroud:(ccTime)delta
{
CGPoint backgroundScrollVel = ccp(-1000, 0);
_backgroundNode.position = ccpAdd(_backgroundNode.position, ccpMult(backgroundScrollVel, delta));
for (CCSprite *background in _backgrounds) {
if (([_backgroundNode convertToWorldSpace:background.position].x+background.contentSize.width/10) < -(background.contentSize.width)) {
[_backgroundNode incrementOffset:ccp(background.contentSize.width*2,0) forChild:background];
}
}
}
- (void) dealloc
{
_backgroundNode = nil;
// _backgrounds = nil;
[_backgrounds removeAllChildren];
[_backgrounds release];
[super dealloc];
}
#end
Well, here's how I have gone about it:
Get as close as possible to a POT texture size. 1920x640 costs you as much memory as a 2048x2048. Maybe you could get your artists to combine the three-five sprites on a single 2048x2848 png, crop with an plist (like for animation).
Whenever possible, load textures 'just in time', ie before they are required to be visible. If load time became an issue (perceivable lag at an inappropriate game circumstance), convert the texture to .pvr format (faster load), later to .pvr.gz (still faster load time, smaller app download size). PVR will cause some artefacts, so check with graphic people on your project before comiting.
Coming out of any level transition (either to some kind of menu or to some cut-scene), cleanup memory used by textures. This means that if the game logic requires returning to the main scene, reload textures just-in-time, during the transition.
Last ditch, change the depth setting before loading these large textures (code snippet below). Setting to RGBA444 will save 75% of the memory requirement, BUT, you take a hit on some graphic quality, especially for high saturation images. Once again, if you need to go there, get your graphics people to optimize the images to this depth, so they are satisfied with the result on device.
cleanup:
NSLog(#"GESprite<removeUnusedSprites> : before purging all caches");
[[CCTextureCache sharedTextureCache] dumpCachedTextureInfo];
[[CCSpriteFrameCache sharedSpriteFrameCache] removeUnusedSpriteFrames];
[[CCDirector sharedDirector] purgeCachedData];
NSLog(#"GESprite<removeUnusedSprites> : after purging all caches");
[[CCTextureCache sharedTextureCache] dumpCachedTextureInfo];
depth (in a CCSprite derivative class, some utility methods), you can do this anywhere anytime:
+(void) mediumPixelFormat{
[CCTexture2D setDefaultAlphaPixelFormat:kTexture2DPixelFormat_RGBA4444];
}
+(void) highPixelFormat{
[CCTexture2D setDefaultAlphaPixelFormat:kTexture2DPixelFormat_RGBA8888];
}

Resources