could someone help on animating two sets of image depending on true/false condition? I am getting error message with "Interface type cannot be statically allocated" when using "CCAnimation". Here is my code:
//---frameSetOne
for (int i=1; i<=4; i++) {
[framesOne addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:#"bird%d.png",i]]];
}
//---frameSetTwo
for (int i=5; i<=8; i++) {
[framesTwo addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:#"bird%d.png",i]]];
}
if ( Answer == 1 ) {
CCAnimation _flyAnimation = [CCAnimation animationWithSpriteFrames:framesOne delay:0.07f];
}
else
{
CCAnimation _flyAnimation = [CCAnimation animationWithSpriteFrames:framesTwo delay:0.07f];
}
Could someone help correct the issue or suggest a different way of animating multiple sets of frames/images using true or false condition?
ThanksInAdvance!
Try:
CCAnimation* _flyAnimation = [CCAnimation animationWithSpriteFrames:framesOne delay:0.07f];
The call to the class method animationWithSpriteFrames: method returns a CCAnimation*, not a CCAnimation.
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.
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
Is it possible in Cocos2d to create a move animation that would go on a specific path?
For example, how should I do if I need an object to move on an arc or full circle?
Regards!
Sure you can do this using :
ccBezierConfig bezier;
bezier.controlPoint_1 = ccp(320,0); // control point 1
bezier.controlPoint_2 =ccp(0,0); // control point 2
bezier.endPosition = ccp(endPoint.x,endPoint.y) ;
id bezierForward = [CCBezierTo actionWithDuration:3 bezier:bezier];
[ball runAction:bezierForward];
you can use ccBezier to move any node in curves :
Now Animation Part :
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"eggAnimation.plist"];
spriteSheet = [CCSpriteBatchNode batchNodeWithFile:#"eggAnimation.png"];
[gameBackgroundLayer addChild:spriteSheet];
eggAnimFrames = [NSMutableArray array];
for ( int i = 1; i <= 10; i++ )
{
[eggAnimFrames addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:#"%d.png", i]]];
}
rotateAnim = [CCAnimation animationWithFrames:eggAnimFrames delay:0.05f];
ball = [CCSprite spriteWithSpriteFrameName:#"1.png"];
ball.position=ccp(160,80);
rotateAction =[CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:rotateAnim restoreOriginalFrame:YES]];
[spriteSheet addChild:ball];
Reference Links : http://www.raywenderlich.com/1271/how-to-use-animations-and-sprite-sheets-in-cocos2d
http://www.math.ubc.ca/~cass/gfx/bezier.html
My problem is that animation are not working properly during movements of sprite.
Below is the code which i'm using
- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
[selSprite resumeSchedulerAndActions];
CGPoint touchLocation = [self convertTouchToNodeSpace:touch];
[self selectSpriteForTouch:touchLocation];
return TRUE;
}
- (void)selectSpriteForTouch:(CGPoint)touchLocation
{
CCSprite * newSprite = nil;
for (CCSprite *sprite in movableSprite) {
if (CGRectContainsPoint(sprite.boundingBox, touchLocation)) {
newSprite = sprite;
break;
}
}
if (newSprite != selSprite) {
[selSprite stopAllActions];
selSprite = newSprite;
_MoveableSpritetouch = TRUE;
}
if(_MoveableSpritetouch==TRUE)
{
movement=0;
CGRect selRect=CGRectMake((SpriteX)-20.0,(SpriteY)-20.0,40.0,40.0);
if(CGRectContainsPoint(selRect, touchLocation))
{
[selSprite stopAllActions];
}
if((selSprite==MarshallCar)&& (!(CGRectContainsPoint(selRect, touchLocation))))
{
movement=1;
[self reorderChild:selSprite z:5];
NSMutableArray *MarshallCarWalkAnimFrames = [NSMutableArray array];
for(int i = MarshallCarTouchStartFrameIndex; i <= MarshallCarTouchEndFrameIndex; ++i) {
[MarshallCarWalkAnimFrames addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:#"mcar_move_%d.png", i]]];
}
MarshallCarWalkAnim = [CCAnimation animationWithFrames:MarshallCarWalkAnimFrames delay:MarshallCarTouchFrameDelay];
walkMarshallCar = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:MarshallCarWalkAnim restoreOriginalFrame:NO]];
[selSprite runAction:walkMarshallCar];
}
}
}
- (void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event {
if(gameState == TRUE){
CGPoint point = [touch locationInView:[touch view]];
point = [[CCDirector sharedDirector] convertToGL:point];
if (moveDifference.x>0)
{
selSprite.flipX = YES;
}
else {
selSprite.flipX = NO;
}
[selSprite setPosition:point];
}
}
-(void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event
{
movement=0;
if(selSprite==MarshallCar)
{
[selSprite setDisplayFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:#"mcar_idle.png"]];
}
[selSprite pauseSchedulerAndActions];
}
The animation frames for movement are not playing every time during movements sometimes it plays or sometimes not. It plays properly when you touch and move your sprite for the first time but if touch another sprite and then again move the previous sprite the animations for movement won't play.
Is anyone having any idea why this is happening?
Please tell me the proper code for removing this bug.
Thanks!!!
I believe your problem is the if/else if construct:
if (_MoveableSpritetouch==TRUE)
{
CGRect selRect = CGRectMake(SpriteX - 20, SpriteY - 20, 40, 40);
if(CGRectContainsPoint(selRect, touchLocation))
{
[selSprite stopAllActions];
}
else if(...)
{
...
[selSprite runAction:walkMarshallCar];
}
}
If you don't see it right away: if the touch location is inside the selRect, you call stopAllActions on the selected (new) sprite and do nothing else. Only if the touch location is not within that rectangle you'll run the animation action.
I think the "in rectangle" check is superfluous since you've already called stopAllActions anyway a few lines above.
Allow me a few general remarks about your code:
The method "selectSpriteForTouch" tells me that you're selecting a new sprite. The function does that. But it does not advertise playing an animation. You might want to refactor this out to a seperate "playAnimationOnSelectedSprite" method.
You wrote 20.0 and 40.0 several times. This means you're actually passing a double (8 bytes floating point data type) to a CGPoint which takes floats (4 bytes floating point). Strictly speaking use either 20.0f with the suffixed "f" to denote it as a floating point data type, or use integers since you don't use the floating point part.
Why you put (SpriteX) in brackets is not clear to me, if you want to enhance readability you'll achieve more by adding spaces after commas and operands.
In Objective-C, use YES and NO macros instead of TRUE and FALSE.
The bool variable _MoveableSpritetouch seems superfluous, unless needed someplace else. In any case you should move the following if(_MoveableSpritetouch==TRUE) block to where you set the _MoveableSpritetouch variable to TRUE because it just makes your code harder to read by setting a variable, leaving the code block you were in ( if(selSprite != newSprite) ) just to jump into another block of code ( if(_MoveableSpritetouch==TRUE) ) that you already know you're going to run anyway.
if((selSprite==MarshallCar)&& (!(CGRectContainsPoint(selRect, touchLocation))))
{
movement=1;
[self reorderChild:selSprite z:5];
NSMutableArray *MarshallCarWalkAnimFrames = [NSMutableArray array];
for(int i = MarshallCarTouchStartFrameIndex; i <= MarshallCarTouchEndFrameIndex; ++i) {
[MarshallCarWalkAnimFrames addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:#"mcar_move_%d.png", i]]];
}
MarshallCarWalkAnim = [CCAnimation animationWithFrames:MarshallCarWalkAnimFrames delay:MarshallCarTouchFrameDelay];
walkMarshallCar = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:MarshallCarWalkAnim restoreOriginalFrame:NO]];
[selSprite runAction:walkMarshallCar];
}
I have added [selSprite stopAllActions];
and it started working correctly because in the touch ended method i was pausing the actions
but not resuming them so when i touch the sprite for the second time it was not playing animation because the action was paused.
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.