CCAnimate error after declaring NSMutable array and animation in init - cocos2d-iphone

I'm having an error that i don't know how to solve, I've declared an NSMutablearray in my init, filled it with two sprites to animate, and declare the CCAnimation;
animParpadeoNina = [[NSMutableArray alloc]init];
[animParpadeoNina addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:#"ninaCamina002b.png"]];
[animParpadeoNina addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:#"ninaCamina002.png"]];
for (id obj in animParpadeoNina) {
NSLog(#"%#",obj);
}
paralanina = [CCAnimation animationWithSpriteFrames:animParpadeoNina delay:.2];
Now, if i call the action just after declare it all, the animation works, but if i try to run the CCAnimation in any other function, I get " EXC_BAD_ACCESS (code = 1, address = 0xb0ab1de8)
If i fill the array AND declare the CCAnimation inside the function, then it works. The thing is that i want to run this action several times, and it doesn't feels the right way to fill and declare once and once again the same code...
What am i doing wrong? Any suggestion to solve this?
Thanks in advance.

animParpadeoNina = [NSMutableArray alloc];
This should be:
animParpadeoNina = [[NSMutableArray alloc] init];

Related

Removing random object from parent CCSprite

probably this is a simple problem to solve, since I'm quite new.
I have a scene with a waiter holding a tray of food
(the food is a random CCSprite choosen from an array)
each time he comes onscreen he holds a new piece of food
(the user touches the food and the waiter walks off to return
again with a new piece of food
however I cant seem to delete the old peice of food from the screen
as it says the child is already added...
any help would be great
-(id) init
{
///other code then...
waiterOnSCreen
= [CCSprite spriteWithSpriteFrameName:#"CatUP.png"];
waiterOnSCreen.position = ccp(CatOffSCreenPosX, catXpos);
[self addChild:waiterOnSCreen z:0];
//moving the waiter
// the random food sprite is added later to the waiter
// [waiterOnSCreen addChild:myRandomSprite];
}
-(void)LoadRandomFood
{
///I make my array here then and add CCSprites
RandomFood = [[NSMutableArray alloc]initWithObjects:
//cake,
RandomMuffin,
RandomMeat,
RandomCake,//
nil];//
int i = 0;
int count= [RandomFood count];
if (i < count)
{
int i = arc4random() % [RandomFood count];
myRandomSprite = (CCSprite *)[RandomFood objectAtIndex:i];
//waiterOnSCreen is a CCSprite added on the init
[waiterOnSCreen addChild:myRandomSprite];
myRandomSprite.position=ccp(290,220);
myRandomSprite.tag = RandomFoodTag;
}
}
later
in if(CGRectContainsPoint(waiterOnSCreen.boundingBox, location))
{
//trying to remove the food here
//Ive already tried to remove the sprite using
[self removeChildByTag:RandomeObjectTag];
//and also
CCSprite *wantedSprite = (CCSprite *)[self getChildByTag:RandomFoodTag];
[wantedSprite removeFromParentAndCleanup:YES];
}
}
Im guessing its also crashing 'child already added. It can't be added again'
as its trying to add RandomMuffin,RandomMeat,RandomCake, again
im not too sure how to fix that.
You shouldn't need to create another array just to delete a sprite. If you can provide a more complete picture of your project I would be happy to review it. Can you post the entire code file where you are doing your work? Or multiple files? On inspecting some of your samples further a few concerns in LoadRandomFood you are allocating an NSMutableArray without checking if RandomFood already has a value.
Something like this would be safer though note I am just doing a sanity check here. It would be more efficient to just fill in RandomFood once on init or elsewhere that is not going to be executed constantly.
-(void)LoadRandomFood
{
if (RandomFood)
{
[RandomFood release];
}
///I make my array here then and add CCSprites
RandomFood = [[NSMutableArray alloc]initWithObjects:
//cake,
RandomMuffin,
RandomMeat,
RandomCake,//
nil];//
int i = 0;
int count= [RandomFood count];
if (i < count)
{
int i = arc4random() % [RandomFood count];
myRandomSprite = (CCSprite *)[RandomFood objectAtIndex:i];
//waiterOnSCreen is a CCSprite added on the init
[waiterOnSCreen addChild:myRandomSprite];
myRandomSprite.position=ccp(290,220);
myRandomSprite.tag = RandomFoodTag;
}
}
In the case of the crash when adding a sprite are you sure the removeChildByTag call is being executed? Is it possible you are re-assigning the tag to a new sprite before deleting the old one? Have you stepped through the logic in the debugger? Again it would help to see a more complete code file here.
I had to make another array to access the sprite and delete it
NSMutableArray *_buffer = [NSMutableArray new];
[_buffer insertObject:myRandomSprite atIndex:0];
CCSprite *sprite = (CCSprite *)[_buffer objectAtIndex:0];
[sprite removeFromParentAndCleanup:YES];

Reading sprites from a NSMutableArray to detect collision

I am adding sprites to a NSMutableArray like this:
NSMutableArray * movableSprites;
NSString *image = [images objectAtIndex:3];
CCSprite *sprite = [CCSprite spriteWithFile:image];
sprite.position = ccp(AREA_A2_X2 - (i * 56), AREA_A3A5A4_Y);
[self addChild:sprite];
[movableSprites addObject:sprite];
So far so good.
Now I am trying to detect collisions among them. The user is able to move the sprites around, but I want the sprites to be blocked by one another.
So, when I am working on the translation of them I want it to happen there. By the way, is it the best place to go for a collision detection?
- (void)panForTranslation:(CGPoint)translation {
if (selSprite) {
I intent to do the following in a loop:
CGRect rect1 = [SpriteUtilities positionRect:selSprite];
CGRect rect2 = [SpriteUtilities positionRect:EVERY_OTHER_SPRITE];
if (!CGRectIsNull(CGRectIntersection(rect1, rect2))) {
//handle collision
}
The thing is... I didn't find a NSMutableArray method to retrieve the sprite object.
Thank you for your help.
Ok... after a few more reading I got into this:
CCSprite *toCollide;
for (int i = 0; i < [movableSprites count]; i++){
toCollide = [movableSprites objectAtIndex:i];
...
Thanks anyway!! Hope it helps somebody else!

CCAnimation, how to set frame rate for individual frames

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.

Cocos2D - NSMutableArray not accessible in ccTouchBegan?

First, let's be clear on two things. My English is terrible and I'm pretty new in cocos2d. So sorry and sorry again. :D Now for my question.
I have declared these in a .m (Its a CCscene):
//A mutable array global to my class
NSMutableArray *arrayBoutons;
//I use this array like this :
LettreBleue *lettre1 = nil;
lettre1 = [LettreBleue construireObjLettre];
lettre1.position = ccp(80,370);
[self addChild:lettre1];
[arrayBoutons addObject:lettre1];
//The method to register the touch
-(void) registerWithTouchDispatcher
{
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:kCCMenuTouchPriority swallowsTouches:NO];
}
// The classic TouchBegan in which Im trying to access the value Valeur
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
// test!
NSLog(#"Debut test ccTouchBegan4");
int cptLettres = 0;
do {
LettreBleue *unBoutontest=[arrayBoutons objectAtIndex: cptLettres];
NSLog(unBoutontest.Valeur);
cptLettres = cptLettres+1;
} while (cptLettres < 16);
The problem is my arrayBoutons doesn't seem to keep my data in my NsMutableArray.
Have you initialized the NSMutableArray, perhaps in an init method? You need to call something like:
arrayBoutons = [[NSMutableArray alloc] init];
Then, you need to release it in your dealloc method:
[arrayBoutons release];

Cocos2d: Preloading animation causes a crash

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.