Multiple Sprite Actions - objective-c

I am using Cocos2d engine and I've faced a strange problem.
I have a sprite. Also, I have 2 animations for that sprite. And I want to play one animation when app loads and second, after ccTouchevent is called.
walkAnim = [CCAnimation animation];
dropAnim = [CCAnimation animation];
for( int q=1;q<12;q++){
[walkAnim addFrameWithFilename: [NSString stringWithFormat:#"walkforward_%.2d.png", q]];
[dropAnim addFrameWithFilename: [NSString stringWithFormat:#"drop_%.2d.png", q]];
}
action = [CCAnimate actionWithAnimation:walkAnim];
action.duration = 2;
id act = [CCRepeatForever actionWithAction:action];
[sprite runAction:act];
So, here we see an animating sprite.
[sprite stopAllActions]; //and here my torture begins
I have tried many ways of creating an action:
I've tried to add another AnimateAction, tried to replace the current animation, but everything results in a crash.
[action setAnimation:dropAnim];
and
CCAnimate* animat = [[CCAnimate alloc]initWithDuration:30 animation:dropAnim restoreOriginalFrame:YES];
and
id action = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:dropAnim]];
[player1 runAction:action];
The crash is in [CCAnimate actionWithAnimation:]
+(id) actionWithAnimation: (CCAnimation*)anim
{
return [[[self alloc] initWithAnimation:anim restoreOriginalFrame:YES] autorelease];
}
Thanks!
To launch an action from another method, you have to retain the action Eg: [action retain];

To launch an action from another method, you have to retain the action
Eg: [action retain]; and then do not forget to release it
-(void)create{
for( int q=1;q<12;q++){
[playerWalkAnim addFrameWithFilename: [NSString stringWithFormat:#"walkforward_%.2d.png", q]];
}
playerAction = [CCAnimate actionWithAnimation:playerWalkAnim];
playerAction.duration = 2;
[playerAction retain];
}
-(void)launch{
[player1 runAction:playerAction];
}

Related

Sprite kit node not being removed form memory

My sprite kit game has been having a memory problem and i have tried everything i know of to fix it but still nothing. A little background on the issue; the first time you play the game, memory is fine, it stays completely stable. But when you die and hit play again, that's when the memory starts creeping up. It seems that the more you play again, the faster the memory creeps up. You can be on any scene and the memory being used will still climb. Here's a picture showing instruments, http://postimg.org/image/5olu8h7tp/.
Here's the code i have:
creates the object:
-(void)createObstacle0 {
int yMin = (CGRectGetMidY(self.frame)+190);
int yMax = (CGRectGetMidY(self.frame)+270);
CGPoint startPoint = CGPointMake(-20, yMin + arc4random_uniform(yMax - yMin));
SKSpriteNode *obstacle = [SKSpriteNode spriteNodeWithImagedNamed:#"obstacle"];
obstacle.position = CGPointMake(startPoint.x, startPoint.y);
obstacle.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:21];
obstacle.physicsBody.categoryBitMask = enemyCategory;
obstacle.physicsBody.contactTestBitMask = playerCategory;
obstacle.physicsBody.dynamic = NO;
obstacle.name = #"obstacle";
[self addChild:obstacle];
SKAction *move = [SKAction moveTo:CGPointMake(340, startPoint.y) duration:minTime +arc4random_uniform(maxTime - minTime)];
SKAction* removeObstacle = [SKAction removeFromParent];
[obstacle runAction:[SKAction sequence:#[move, removeObstacle]] completion:^{
score++;
scorelabel.text = [NSString stringWithFormat:#"%lu",(unsigned long)score];
}];
float randomNum = arc4random_uniform(3.0) + 0.2;
[self performSelector:#selector(createObstacle0) withObject:nil afterDelay:randomNum];
}
Collision detector and scene transition:
-(void)didBeginContact:(SKPhysicsContact *)contact
{
uint32_t collision = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask);
if (collision == (playerCategory | enemyCategory)) {
playerAlive = NO;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setInteger:score forKey:#"playerScore"];
[defaults synchronize];
int highScore = [[[NSUserDefaults standardUserDefaults] objectForKey:#"High Score"] integerValue];
if (highScore){
if (highScore < score){
[[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithInt:score] forKey:#"High Score"];
}
}
else{
[[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithInt:score] forKey:#"High Score"];
}
[[NSUserDefaults standardUserDefaults] synchronize];
SKTransition *reveal = [SKTransition fadeWithDuration:0.75];
MGLCreateGameOverScene *scene = [MGLCreateGameOverScene sceneWithSize:self.view.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
[self.view presentScene:scene transition:reveal];
}
}
To remove remaining nodes:
-(void)update:(CFTimeInterval)currentTime {
if (playerAlive == NO) {
[self enumerateChildNodesWithName:#"obstacle" usingBlock:^(SKNode *node, BOOL *stop) {
[node removeFromParent];
}];
}
}
As i said before, the first time you play, memory stays completely stable. It's only after the first time that memory starts to rise. It appears that the more you revisit the main game scene, the faster the memory climbs. I really need help solving this, my game has been down for two weeks now and i really want it back up. I appreciate all help.
Your problem is with the line:
[self performSelector:#selector(createObstacle0) withObject:nil afterDelay:randomNum];
This method actually retains self (by creating a timer) until after the selector is performed. What you need to do is add to the method didBeginContact: the following line before changing scenes:
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(createObstacle0) object:nil];
This will destroy the timer that is retaining self and calling that method unendingly.
You can check that this works by adding a call to NSLog(#"%s", __PRETTY_FUNCTION__); in the dealloc method of your scene.

Disable CCMenuItem until animation finished

I have an CCMenuItem and I want to disable it until an animation is finished, but I don't want to disable all touches with:
[CCDirector sharedDirector].touchDispatcher.dispatchEvents = NO;
Any easy solution?
Use CCSequence to first use the animation action and when that is done you create an action that calls a function with the CCMenuItem as parameter and in that function make it enabled.
Code example: (PS: It was a long time since I used cocos2d.)
{
...
CCMenuItem *menuItem = [CCMenuItem itemWith...];
menuItem.isEnable = NO;
CCMenu *menu = [CCMenu menuWithItems:menuItem, nil];
[self addChild:menu];
[menuItem runAction:[CCSequence actions:[CCAction actionWith...], [CCCallFunc actionWithTarget:self selector:#selector(enable:)], nil]];
...
}
-(void)enable:(CCMenuItem *)item {
item.isEnable = YES;
}
You can disable the CCMenuItem with
CCMenuItem *item = [[CCMenuItem alloc] initWith...];
item.isEnabled = YES;
and enable it afterwards.

How to Change NSTableColumn width with Animation

I have a NSScrollView and a NSTableView with some NSTableColumn in it.
When I push a button,I change the NSScrollView'width with Animation.
Here is my code:
NSDictionary *myScrollViewDictionary = [[NSDictionary alloc] initWithObjectsAndKeys:
myScrollView,NSViewAnimationTargetKey,
[NSValue valueWithRect:myScrollViewStartFrame],NSViewAnimationStartFrameKey,
[NSValue valueWithRect:myScrollViewEndFrame],NSViewAnimationEndFrameKey, nil];
NSViewAnimation *animation = [[NSViewAnimation alloc] initWithViewAnimations:#[myScrollViewDictionary]];
animation.delegate = self;
animation.duration = 0.2;
[animation setAnimationBlockingMode:NSAnimationBlocking];
[animation startAnimation];
This works fine.
But I want to change each Column'width in the meanwhile with the same Animation,the problem is NSTableColumn is not a NSView, so I can not change its frame.Now I only can change Column'width without any Animation.
somebody have ideas?
I'm afraid you would probably have to create your own custom animation that does everything manually. To animate the column, here is a general idea:
- (IBAction)animateColumn:(id)sender
{
NSTableColumn *tableColumn; // = set your table column
CGFloat initialWidth = [tableColumn width];
CGFloat finalWidth; // = whatever
dispatch_async(dispatch_get_global_queue(0,0), {
double animationTime = 2; //seconds
double timeElapsed = 0; //approximate measure; probably good enough
while (timeElapsed<animationTime)
{
double t = timeElapsed/animationTime;
CGFloat width = t*finalWidth + (1-t)*initialWidth;
dispatch_async(dispatch_get_main_queue(), ^{
[tableColumn setWidth:width];
});
NSDate *future = [NSDate dateWithTimeIntervalSinceNow:0.02];
[NSThread sleepUntilDate:future];
timeElapsed += 0.02;
}
dispatch_async(dispatch_get_main_queue(), ^{
[tableColumn setWidth:finalWidth];
});
});
}
I guess you can adapt this to do what you want. Perhaps you can start this animation at the same time you start the other animation (using the same time for both, changing 2 to 0.2 in my example).

Sprite animation cocos2d

How can I animate this sprite?
if ((self = [super initWithSpriteFrameName:#"Boss_ship_5.png" world:world shapeName:#"Boss_ship" maxHp:50 healthBarType:HealthBarTypeRed])) {
I'm trying with this, but with _layer doesn't work...
CCSpriteFrameCache * cache =
[CCSpriteFrameCache sharedSpriteFrameCache];
CCAnimation *animation = [CCAnimation animation];
[animation addSpriteFrame:
[cache spriteFrameByName:#"Boss_ship_5.png"]];
[animation addSpriteFrame:
[cache spriteFrameByName:#"Boss_ship_4.png"]];
animation.delayPerUnit = 0.05;
[_layer runAction:
[CCRepeatForever actionWithAction:
[CCAnimate actionWithAnimation:animation]]];
Before adding sprites to animation object, you'll need to load the textures into the CCSpriteFrameCache. Please, take a look at
http://www.cocos2d-iphone.org/archives/633
Also, CCAnimation actions are supposed to be used with CCSprites. Which class is _layer object?

CCSprite runAction: crash.

I am trying to animate static, like on a tv. I have 5 frames, and I am trying to switch them out very quickly. Every time I run it, I get an unrecognized selector error and a crash. It crashes on [staticSprite runAction:repeat];. I am new at cocos2d.
CCLayer *staticlayer = [[CCLayer alloc]init];
staticlayer.contentSize = CGSizeMake(640, 960);
staticlayer.position = CGPointMake(winSize.width/2, winSize.height/2);
staticlayer.isRelativeAnchorPoint = YES;
NSArray *staticFrames = [[NSArray alloc]initWithObjects:#"static_0.jpg",
#"static_1.jpg",#"static_2.jpg",#"static_3.jpg",#"static_4.jpg",nil];
CCSprite *staticSprite = [CCSprite spriteWithFile:#"static_0.jpg"];
staticSprite.position = ccp(winSize.width/2, winSize.height);
CCAnimation *staticAnimation = [CCAnimation animationWithFrames:staticFrames delay:0.1f];
CCAnimate *staticAnimate = [CCAnimate actionWithAnimation:staticAnimation];
CCRepeatForever *repeat = [CCRepeatForever actionWithAction:staticAnimate];
[staticlayer addChild:staticSprite];
[self addChild:staticlayer z:0];
[staticSprite runAction:repeat];
Your Array of frames should be CCSpriteFrame objects (as you have them they are NSString, and does not have the methods provided by a CCSpriteFrame, thus the unrecognized selector). Look up here for a good introductory turorial on sprite animations.