Is there any way to reduce the game framerate from 30 to 25 fps on the iPhone? I'm porting a Flash game created at 25 fps and exporting the sprites with this frame rate but animations are not shown as correctly as they should.
Any idea?
Try this instead, straight out of the box :
animation = [CCAnimation animationWithSpriteFrames:frames delay:.04];
with 40 ms delay, that should come real close to 25 fps (rendered animation) while the rest of the game is clocking full bore at 60 fps (if you don't have lag issues elsewhere)
I think that you can change your animation interval in your App Delegate with the following snippet in your didFinishLaunching method :
CCDirector *director = [CCDirector sharedDirector];
[director setAnimationInterval:1.0/25];
Hope this helps!
EDIT :
Could this link provide you more information about how to deal with that ?
http://www.cocos2d-iphone.org/wiki/doku.php/prog_guide:best_practices
Well, at last the solution is by another way.
Kept the framerate to 1.0/60.0
What you need to do for animating the spritesheet slowest is to add the frame more than once to the animation array.
NSMutableArray *walkAnimFrames = [NSMutableArray array];
for(int i = _spriteMetadata.spriteInitFrame; i <= _spriteMetadata.spriteEndFrame; ++i)
{
NSString *spriteFrameName = [NSString stringWithFormat:#"%#%#", _spriteMetadata.spriteBaseName, index];
for (int i=0; i<2; i++)
{
[walkAnimFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:spriteFrameName]];
}
}
It's not very orthodox but it works! :)
Thanks for your help Andy!
Related
Sprite animation issues.
Using this example which seems to work for others:
How to create animation in cocos2d 3.0?
So I do this:
NSMutableArray *ballAnimFrames = [NSMutableArray array];
for(int i = 1; i <= 11; ++i)
{
[ballAnimFrames addObject:[[CCSpriteFrameCache sharedSpriteFrameCache]
spriteFrameByName: [NSString stringWithFormat:#"discoball1200x2008c16-%d.png", i]]];
}
CCAnimation *ballAnim = [CCAnimation
animationWithSpriteFrames:ballAnimFrames delay:0.1f];
discoBallSprite = [CCSprite spriteWithImageNamed:#"discoball1200x2008c16-1.png"];
discoBallSprite.position = ccp(upper1Body.position.x,upper1Body.position.y-200);
CCActionAnimate *animationAction = [CCActionAnimate actionWithAnimation:ballAnim];
CCActionRepeatForever *repeatingAnimation = [CCActionRepeatForever actionWithAction:animationAction];
discoBallSprite.scaleX = 0.25;
discoBallSprite.scaleY = 0.25;
[discoBallSprite runAction:repeatingAnimation];
[self addChild:discoBallSprite z:10];
I get the following error:
'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
Obviously the error message is saying my image file is nil but it seems perfectly fine.
I tried renaming files to remove the extra "-" character but no change (I also renamed files outside of Xcode and re-imported with new name).
All my images are in Resources folder.
I tried moving images out of Resources folder to next level up but still the error.
The naming of them seems fine.
Any ideas what else to check?
Make a sprite sheet, add it to your int
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"YourAnim.plist"];
Now in the animation code
[ballAnimFrames addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName: [YourAnim.png", i]]];
When you make a sprite sheet it makes two things, 1) a png with the sprites and 2) a plist with the coordinates
if you so decide to use the program I told you about make sure you set it to cocos2d
See The code Link
Now Change for Cocos2dV3 is below.
In the link code there is CCAnimation that is replace by CCActionAnimate in V3 and also CCRepeatForever is replace by CCActionRepeatForever in V3.
Also check your .plist images may be 10 althougt in for condition it get 11th image in it. so may be that is your problem to insert image in array,
replace and try.
for(int i = 1; i < 11; ++i)
{
// Code
}
Change it work fine.
Using iPad 2 simulator , after i have created a sprite sheet, its size was ±8000 pixels, i got warning that is bigger than the supported 4096 x 4096 .
The Animation is made of images in the size of half iPad screen, and each animation has 10 frames .
So , how can i create a sprite sheet to run the animation ? do i need 2 sprite sheets? and if yes , is there a way to run them in sequence ?
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:plist];
hotGirl= [CCSprite spriteWithSpriteFrameName:pngFirst];
hotGirl.position=ccp(winSize.width/2,winSize.height/1.335);
[self addChild:hotGirl];
NSMutableArray *animFrames = [NSMutableArray array];
for(int i = 1; i < num+1; i++)
{
CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:#"%#%i.png",file,i]];
[animFrames addObject:frame];
}
CCAnimation* Animation = [CCAnimation animationWithSpriteFrames:animFrames delay:0.1f];
CCAnimate * pAction = [CCAnimate actionWithAnimation:Animation];
id call=[CCCallFunc actionWithTarget:self selector:#selector(done:)];
id seq=[CCSequence actions:pAction,call, nil];
[hotGirl runAction:seq];
Thanks .
Its openGLES Texture memory limitation.
int maxTexSize;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize);
printf("Max = %d\n",maxTexSize);
You can't load image that is larger than GL_MAX_TEXTURE_SIZE. It depends on device.
Let's say I have an animation consisting of five frames.
How would I set frames 1-4 to play for 0.5 seconds each, then the 5th frame for 0.1 seconds?
I have not tried this yet, (new in cocos 2.x), but :
CCAnimation *anim = [CCAnimation animation];
NSMutableArray *frames = [NSMutableArray array];
CCSpriteFrame *sfr1 = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:#"name1"];
CCAnimationFrame *af1 = [[[CCAnimationFrame alloc] initWithSpriteFrame:sfr1 delayUnits:5 userInfo:nil] autorelease];
[frames addObject:af1];
// tru sfr4 and finally
CCSpriteFrame *sfr5 = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:#"name5"];
CCAnimationFrame *af5 = [[[CCAnimationFrame alloc] initWithSpriteFrame:sfr5 delayUnits:1 userInfo:nil] autorelease];
[frames addObject:af5];
anim = [CCAnimation animationWithAnimationFrames:frames delayPerUnit:.1 loops:1];
This should give you the effect you are looking for.
ps : userInfo is an NSDictionary. When the animation is played you can register for a notification named CCAnimationFrameDisplayedNotification, and receive the userInfo, frame by frame.
// not tested , yet //
By playing the animation manually. Schedule a selector, use its delta time to see if you need to switch to the next frame. Use setDisplayFrame: to change the sprite's frame.
Use two separate animation, one with 0.5 second and one with 0.2second.
I created a CCAnimation as seen below. I tried lowering the delay to something below .05f and the animation now fails to complete! Its only 8 frames. I don't know if I am doing something wrong. At first I thought it was a memory leak and I was losing the action, so I assigned it to a strong property to test that, and still did it. I'm not sure how the delay could cause my animation to fail to finish. I am running in the simulator at 60 frames per sec.
Using Kobold 2.0.4
Can anyone help?
else if([model currentState] == PROCESSING_FIRST_ACTION)
{
CCDirector* director = [CCDirector sharedDirector]; // process model
//Get the top left corner of the screen
int screen_height = director.screenSizeAsPoint.y;
int screen_width = director.screenSizeAsPoint.x;
id attacker = [model attacker];
id attackChoice = [attacker getRegisteredAttack];
CCAction* attack = [model.resourceManager animation: #"simple-attack-frame"];
CCSprite * attackSprite = [model.resourceManager sprite: #"simple-attack-frame-01"];
attackSprite.position = ccp(screen_width - rxa(80), screen_height - rya(80));
attackSprite.tag = 5;
self.action = attack;
CCNode * check = [self getChildByTag:5];
if(check == nil)
{
[self addChild: attackSprite];
[attackSprite runAction:attack];
}
}
resource manager:
-(id)animation: (NSString*)_resource
{
NSMutableArray *frames = [NSMutableArray array];
for(int i = 1; i <= 8; ++i)
{
[frames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"%#-0%d", _resource, i]]];
}
CCAnimation *animation = [CCAnimation animationWithSpriteFrames: frames delay:1/60];
CCAction * action = [CCAnimate actionWithAnimation: animation];
return action;
}
In your line
CCAnimation *animation = [CCAnimation animationWithSpriteFrames: frames delay:1/60];
you're setting the delay to 1/60, but as 1 and 60 are both integers, 1/60 is 0. Try using 1.0f/60.0f and you'll get a floating point divide.
After digging around on the web I found a solution. I'm not the one who submitted this solution but I can attest that it fixed my problems:
https://github.com/cocos2d/cocos2d-iphone/commit/60f9cc98783b9a6a5635db4f468f83e0511c74c8
I am trying to preload an animation in the init method of my layer. I then call the animation if the screen is touched. The app crashes with no error message as soon as I touch the screen and seems it is to do with calling the preloaded animation. I would like to do it this way as it seems expensive to create the animation every time the screen is touched - which does seems to work though. Any tips greatly appreciated.
Sample Code:
In my header:
#interface Test : CCLayer {
NSMutableArray *wake;
CCSprite* ani;
CCAnimate *animate;
}
#end
In my implementation:
-(id) init {
if( (self=[super init])) {
// enable touches
self.isTouchEnabled = YES;
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"ani.plist" texture:[[CCTexture2D alloc] initWithImage:[UIImage imageNamed:#"ani.png"]]];
ani = [CCSprite spriteWithSpriteFrameName:#"ani1.png"]; //comes from .plist file
ani.anchorPoint=ccp(0,0);
ani.position = ccp(700,65);
[self addChild:ani z:30];
wake = [NSMutableArray array];
for(int i = 1; i <= 4; i++) {
[wake addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:#"ani%d.png",i]]];
}
animate = [CCAnimate actionWithAnimation:[CCAnimation animationWithFrames:wake delay:1.0f] restoreOriginalFrame:FALSE];
}
return self;
}
Handling the touch:
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
// run the animation
[ani runAction:animate];
}
Animations in Cocos2d are not designed to be reused. You need to create a new one every time.
Problem solved by creating properties for the array and animation on the class using nonatomic,retain.
You only need to retain the animation but the array can be local.
self.myAnimation = [[CCAnimation animationWithFrames:myAniFramesArray delay:0.1f] retain];
Remember to make the property nonatomic, retain as stated by Chev and to release any objects you retain in the appropriate dealloc method.