cocos2d sprite animation "SIGABRT" - objective-c

i have followed many videos on how tho animate sprites in cocos2d. But i seem to always com across this when the code is run.
CCSpriteBatchNode *spriteSheet = [CCSpriteBatchNode SpriteSheetWithFile:#"animbear.png"];
it says (Thread 1: Program received signal "SIGBRT")
im not sure what do do I've tried everything i can please help?
heres the code within the init method
heres the part of the code!
// Import the interfaces
#import "HelloWorldLayer.h"
// HelloWorldLayer implementation
#implementation HelloWorldLayer
// At the top, under #implementation
#synthesize bear = _bear;
#synthesize moveAction = _moveAction;
#synthesize walkAction = _walkAction;
-(id) init {
if((self = [super init])) {
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:
#"bear.plist"];
CCSpriteBatchNode *spriteSheet = [CCSpriteBatchNode
batchNodeWithFile:#"bear.jpg"];
[self addChild:spriteSheet];
NSMutableArray *walkAnimFrames = [NSMutableArray array];
for(int i = 1; i <= 8; ++i) {
[walkAnimFrames addObject: *****THIS IS WERE (PROGRAM RECEIVED SIGNAL:"SIGABRT***
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"bear%d.png", i]]];
}
CCAnimation *walkAnim = [CCAnimation
animationWithFrames:walkAnimFrames delay:0.1f];
CGSize winSize = [CCDirector sharedDirector].winSize;
self.bear = [CCSprite spriteWithSpriteFrameName:#"bear.jpg"];
_bear.position = ccp(winSize.width/2, winSize.height/2);
self.walkAction = [CCRepeatForever actionWithAction:
[CCAnimate actionWithAnimation:walkAnim restoreOriginalFrame:NO]];
[_bear runAction:_walkAction];
[spriteSheet addChild:_bear];
}
return self;
}

Have you added animbear.png to your project?

Make Sure you SAVE the sheet before publishing the PNG and PLIST file using Zwoptex

Related

Animation must be non-nil in Cocos2d

I am trying to create a CCSprite subclass called Enemy
#import "Enemy.h"
#implementation Enemy
{
CCSprite* ant;
CCAnimation *walkAnim ;
}
-(id)init
{
self = [super init];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"char.plist"];
CCSpriteBatchNode *spriteSheet = [CCSpriteBatchNode batchNodeWithFile:#"char.png"];
[self addChild:spriteSheet];
NSMutableArray *walkAnimFrames = [NSMutableArray array];
for (int i=1; i<=3; i++) {
[walkAnimFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"antNormal_%d.png",i]]];
}
walkAnim = [CCAnimation animationWithSpriteFrames:walkAnimFrames delay:0.1f];
self = [CCSprite spriteWithSpriteFrameName:#"antNormal_1.png"];
CCAction* walkAction = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:walkAnim]];
[self runAction:walkAction];
return self;
}
#end
and then in my gamelayer I have the enemies added like this
enemies=[[CCArray alloc] initWithCapacity:100];
for (int i=0; i<10; i++) {
Enemy* ant=[[Enemy alloc] init];
[ant setPosition:ccp(100*i,100)];
[enemies addObject:ant];
}
But this is causing the program to crash on start with the error
'NSInternalInconsistencyException', reason: 'Animate: argument Animation must be non-nil'
If I comment out the CCAction though, the enemies display correctly, just without animation(obviously). Not sure how to solve this at the moment.
While I can't speak to Cocos2d specifically, there's several things wrong in your init method from an ObjC standpoint that probably contribute to the problem.
self is set self twice. The second one creates a new instance of the class and clobbers the old one. You should only set self to the result of an init method, not a class factory method
self is not checked for nil. You should always check self for nil before setting any ivars. If the init method you call fails, if will be nil and your app will crash.
walkAnim is not retained, it will be released at a later time and your app will crash when you try to use it. It must be retained.
Do not call methods on self in your custom init methods. By definition, your object is not in a fully initialized state inside init methods. Strange things can occur if you call methods on self. Other init methods are an exception.
While I cannot guarantee this is free of bugs, as I am not personally familiar with Cocoas2d, this should get you closer to what you want:
-(id)init
{
self = [CCSprite initWithSpriteFrameName:#"antNormal_1.png"];
if (self)
{
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"char.plist"];
CCSpriteBatchNode *spriteSheet = [CCSpriteBatchNode batchNodeWithFile:#"char.png"];
[self addChild:spriteSheet];
NSMutableArray *walkAnimFrames = [NSMutableArray array];
for (int i=1; i<=3; i++) {
[walkAnimFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"antNormal_%d.png",i]]];
}
walkAnim = [[CCAnimation animationWithSpriteFrames:walkAnimFrames delay:0.1f] retain];
}
return self;
}
-(void)startWalkAction
{
CCAction* walkAction = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:walkAnim]];
[self runAction:walkAction];
}
And then add enemies like this:
enemies=[[CCArray alloc] initWithCapacity:100];
for (int i=0; i<10; i++) {
Enemy* ant=[[Enemy alloc] init];
[ant setPosition:ccp(100*i,100)];
[ant startWalkAction];
[enemies addObject:ant];
}

What is the proper way to implement animation in a CCSprite subclass?

in my game I made a subclass of CCSprite (cocos2d) for my enemies.
Because I want control over animation, from within every instance of this subclass, I had to translate my animation code in my main class, which loads
the enemies, to this subclass.
I found this rather hard but.... after some time it magically started to work.
Unfortunately after creating and setting properties in this subclass I started to have weird crashes. Because they are in cocosDenshion and other places which have nothing to do with my
enemy class and after a research in depth in my code and on the net, I'm convinced its some kind of data corruption and I'm almost completely certain its because I did my enemie class with his animation code completely the wrong way.
To be honest, I cannot even wrap my mind around what is going on here anymore and how this actually works :S...I'm completely stuck. any help is much appreciated!
So my main questions would be: What is the proper way to implement animation in a CCSprite subclass ? / what am I doing wrong here?
simplified my code here: (it triggers the animation every 2 seconds to show how I want
to use it)
#import "cocos2d.h"
#interface Npc : CCSprite
{
CCAction *_runAnimation;
NSString* name;
int strength;
}
#property (nonatomic, retain) CCAction *runAnimation;
#property int strength;
#property (nonatomic, retain) NSString* name;
- (Npc*)loadAnimation;
- (void)animate;
#end
#import "Npc.h"
#implementation Npc
#synthesize runAnimation = _runAnimation;
#synthesize name;
#synthesize strength;
-(id) initWithTexture:(CCTexture2D*)texture rect:(CGRect)rect
{
if( (self=[super initWithTexture:texture rect:rect]))
{
}
return self;
}
- (Npc*)loadAnimation
{
int lastFrame = 11;
NSString *creatureFile = #"vis 1";
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:
[NSString stringWithFormat:#"%#.plist", creatureFile]];
CCSpriteBatchNode* sheet = [CCSpriteBatchNode batchNodeWithFile:
[NSString stringWithFormat:#"%#.png", creatureFile]];
self = [Npc spriteWithTexture:sheet.texture];
NSMutableArray* animFrames = [[NSMutableArray alloc] init];
for (int x = 0; x < lastFrame; x++)
{
[animFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"%# %d.png", creatureFile, x]]];
}
CCAnimation* anim = [CCAnimation animationWithFrames: animFrames delay: 0.1];
self.runAnimation = [CCAnimate actionWithAnimation:anim restoreOriginalFrame:NO];
[self runAction:_runAnimation];
return self;
}
- (void)animate
{
[self runAction:self.runAnimation];
}
- (void)dealloc
{
[super dealloc];
[name release];
}
#end
#import "HelloWorldLayer.h"
#import "Npc.h"
#implementation HelloWorldLayer
+(CCScene *) scene
{
CCScene *scene = [CCScene node];
HelloWorldLayer *layer = [HelloWorldLayer node];
[scene addChild: layer];
return scene;
}
-(id) init
{
if( (self=[super init]))
{
timer = 0;
creatureTemp = [Npc spriteWithFile:#"Icon.png"];
creature = [creatureTemp loadAnimation];
creature.position = ccp(100,100);
[self addChild:creature];
[self schedule:#selector(nextFrame:)];
}
return self;
}
- (void)nextFrame:(ccTime)dt
{
timer += dt;
if (timer > 2.)
{
[creature animate];
timer = 0.;
}
}
- (void) dealloc
{
[super dealloc];
}
#end
-------------------EDIT--------------------
I changed my code with help of a tutorial by Ray Wenderlich: http://www.raywenderlich.com/3888/how-to-create-a-game-like-tiny-wings-part-1
this is I think much closer to what it should be. Unfortunately it still crashes on my iphone (not the simulator) on SimpleAudioEngine (which I implement right) so I still do something wrong.
on top of the Npc class:
#synthesize batchNode = _batchNode;
the init of the Npc class:
-(id) initNpc
{
if( (self=[super initWithSpriteFrameName:#"vis 1 0.png"]))
{
_normalAnim = [[CCAnimation alloc] init];
NSMutableArray* animFrames = [[NSMutableArray alloc] init];
int lastFrame = 11;
for (int x = 0; x < lastFrame; x++)
{
[animFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"vis 1 %d.png", x]]];
}
_normalAnim = [CCAnimation animationWithFrames: animFrames delay: 0.1];
self.runAnimation = [CCAnimate actionWithAnimation:_normalAnim restoreOriginalFrame:NO];
}
return self;
}
and the init of the HelloWorldLayer
-(id) init
{
if( (self=[super init]))
{
timer = 0;
_batchNode = [CCSpriteBatchNode batchNodeWithFile:#"vis 1.png"];
[self addChild:_batchNode];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"vis 1.plist"];
creature = [[[Npc alloc] initNpc] autorelease];
creature.position = ccp(200,200);
[_batchNode addChild:creature];
[self schedule:#selector(nextFrame:)];
[[SimpleAudioEngine sharedEngine] preloadEffect:#"super1.mp3"];
}
return self;
}
You're reassigning self in loadAnimation:
self = [Npc spriteWithTexture:sheet.texture];
At that point I stopped reading the code. Since self already is an instance of the Npc class you have to ask yourself why you're doing this in an Npc instance method like loadAnimation.
So, I got it....here is the code:
Npc.h:
#import "cocos2d.h"
#interface Npc : CCSprite
{
CCAction *_runAnimation;
CCAnimation *_normalAnim;
CCAnimate *_normalAnimate;
}
#property (nonatomic, retain) CCAction *runAnimation;
- (void)animate;
- (id)initNpc;
#end
Npc.m
#synthesize runAnimation = _runAnimation;
#synthesize batchNode = _batchNode;
-(id) initNpc
{
if( (self=[super initWithSpriteFrameName:#"vis 1 0.png"]))
{
_normalAnim = [[CCAnimation alloc] init];
NSMutableArray* animFrames = [[NSMutableArray alloc] init];
int lastFrame = 7;
for (int x = 0; x < lastFrame; x++)
{
[animFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"vis 1 %d.png", x]]];
}
_normalAnim = [CCAnimation animationWithFrames: animFrames delay: 0.1];
self.runAnimation = [CCAnimate actionWithAnimation:_normalAnim restoreOriginalFrame:NO];
}
return self;
}
- (void)animate
{
[self runAction:_runAnimation];
}
in the HelloWorldLayer.m
-(id) init
{
if( (self=[super init]))
{
_batchNode = [CCSpriteBatchNode batchNodeWithFile:#"vis 1.png"];
[self addChild:_batchNode];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"vis 1.plist"];
timer = 0;
creature = [[[Npc alloc] initNpc] autorelease];
creature.position = ccp(200,200);
[_batchNode addChild:creature];
[self schedule:#selector(nextFrame:)];
}
return self;
}
- (void)nextFrame:(ccTime)dt
{
timer += dt;
if (timer > 2.)
{
[creature animate];
timer = 0.;
}
}
And about the weird crashes in cocosDenshion. That is also solved...it turned out to be a known bug in SimpleAudioEngine where it threw exceptions only when I had an exception breakpoint active. Workaround: made a class for my sound and if I need a exception breakpoint, I comment out the sound...
-- have to say, I do would prefer the:
_batchNode = [CCSpriteBatchNode batchNodeWithFile:#"vis 1.png"];
[self addChild:_batchNode];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"vis 1.plist"];
inside the Npc class, but that is too advanced oop for me. If anybody knows that, let me know...would be great to know actually, to understand oop better.
But it is not strictly necessary...

Strange Crash, No Debugger Clues

I am currently running this Block of code in my Level1.m file, this is the scene for the first level of my game.
#import "BankerL1.h"
#import "GameOverScene.h"
#import "BankerGameWin1.h"
// HelloWorldLayer implementation
#implementation BankerL1Layer
#synthesize label = _label;
#synthesize Banker = _Banker;
#synthesize WalkAction = _WalkAction;
#synthesize MoveAction = _MoveAction;
+(CCScene *) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
BankerL1Layer *layer = [BankerL1Layer node];
// add layer as a child to scene
[scene addChild: layer];
// return the scene
return scene;
}
// on "init" you need to initialize your instance
-(id) init
{
// always call "super" init
// Apple recommends to re-assign "self" with the "super" return value
if( (self=[super init])) {
CGSize winSize = [[CCDirector sharedDirector] winSize];
CCSprite *background = [CCSprite spriteWithFile:#"Ninja Menu Background.png"];
background.position = ccp(winSize.width/2, winSize.height/2);
[self addChild:background z:-1];
CCLabelTTF *Levelcounter = [CCLabelTTF labelWithString:#"Level 1" fontName:#"Marker Felt" fontSize:40];
Levelcounter.position = ccp(winSize.width * 0.80,winSize.height * 0.92);
[self addChild: Levelcounter];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile: #"GreenorcSpriteSheet_default.plist"];
CCSpriteBatchNode *spriteSheet = [CCSpriteBatchNode batchNodeWithFile:#"GreenorcSpriteSheet_default.png"];
[self addChild:spriteSheet];
NSMutableArray *walkAnimFrames = [NSMutableArray array];
for(int i = 1; i <=6; ++i) {
[walkAnimFrames addObject: [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName: [NSString stringWithFormat:#"Greenorc%d.png", i]]];
}
CCAnimation *walkAnim = [CCAnimation animationWithFrames:walkAnimFrames delay:0.1f];
self.Banker = [CCSprite spriteWithSpriteFrameName:#"Greenorc1.png"];
_Banker.position = ccp(winSize.width/2, (winSize.height/2)-190);
self.WalkAction = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:walkAnim restoreOriginalFrame:NO]];
//[_Banker runAction:_WalkAction];
[spriteSheet addChild:_Banker];
self.isTouchEnabled = YES;
_targets = [[NSMutableArray alloc] init];
}
return self;
}
- (void) onEnter
{
// First, call super if you override this. ALWAYS.
[super onEnter];
[self schedule:#selector(gameLogic:) interval:1.5];
[self scheduleUpdate]; // use this instead of schedule: if it's for an update method.
}
//Implements the Callback function above
-(void)gameLogic:(ccTime)dt {
[self addTarget];
}
-(void)spriteMoveFinished:(id)sender {
CCSprite *sprite = (CCSprite *)sender;
[self removeChild:sprite cleanup:YES];
if (sprite.tag == 1) { // target
[_targets removeObject:sprite];
GameOverScene *gameOverScene = [GameOverScene node];
[gameOverScene.layer.label setString:#"You Lose :["];
[[CCDirector sharedDirector] replaceScene:gameOverScene];
} else if (sprite.tag == 2) { // projectile
[_targets removeObject:sprite];
}
}
//Adds the "targets" or in this case enemies, to the scene and spawns/moves them
-(void)addTarget {
CCSprite *target = [CCSprite spriteWithFile:#"seeker.png"
rect:CGRectMake(0, 0, 40, 40)];
target.tag = 1;
[_targets addObject:target];
// Determine where to spawn the target along the X axis
CGSize winSize = [[CCDirector sharedDirector] winSize];
int minX = target.contentSize.height/2;
int maxX = winSize.height - target.contentSize.height/2;
int rangeX = maxX - minX;
int actualX = (arc4random() % rangeX) + minX;//Randomizes the place it will spawn on X- Axis
// Create the target slightly off-screen along the top edge,
// and along a random position along the Y axis as calculated above
target.position = ccp(actualX, winSize.height + (target.contentSize.height/2));
[self addChild:target];
// Determine speed of the target
int minDuration = 2.0;
int maxDuration = 5.0;
int rangeDuration = maxDuration - minDuration;
int actualDuration = (arc4random() % rangeDuration) + minDuration;//Speed is randomized between 2 and 5
// Create the actions
id actionMove = [CCMoveTo actionWithDuration:actualDuration
position:ccp(actualX, -target.contentSize.height/2)];
id actionMoveDone = [CCCallFuncN actionWithTarget:self
selector:#selector(spriteMoveFinished:)];
[target runAction:[CCSequence actions:actionMove, actionMoveDone, nil]];
}
//WHEN THE THINGS COLLIDE, THEY DISSAPEAR
- (void)update:(ccTime)dt {
CGSize winSize = [[CCDirector sharedDirector] winSize];
NSMutableArray *targetsToDelete = [[NSMutableArray alloc] init];
for (CCSprite *target in _targets) {
CGRect targetRect = CGRectMake(
target.position.x - (target.contentSize.width/2),
target.position.y - (target.contentSize.height/2),
target.contentSize.width,
target.contentSize.height);
BOOL playerHit = FALSE;
for (CCSprite *player in _targets) {
CGRect playerRect = CGRectMake(
player.position.x - (player.contentSize.width/2),
player.position.y - (player.contentSize.height/2),
player.contentSize.width,
player.contentSize.height);
if (CGRectIntersectsRect(playerRect, targetRect)) {
//[targetsToDelete addObject:target];
playerHit = TRUE;
[targetsToDelete addObject:target];
break;
}
}
for (CCSprite *target in targetsToDelete) {
[_targets removeObject:target];
[self removeChild:target cleanup:YES];
_targetsDestroyed++;
[_label setString:[NSString stringWithFormat:#""]];
if (_targetsDestroyed > 30) {
GameWinScene *gameWinScene = [GameWinScene node];
_targetsDestroyed = 0;
[[CCDirector sharedDirector] replaceScene:gameWinScene];
} else{
NSString *killcounttext = [NSString stringWithFormat:#"Catches: %i", _targetsDestroyed];
self.label = [CCLabelTTF labelWithString:killcounttext fontName:#"Zapfino" fontSize:20];
_label.color = ccc3(225,225,225);
_label.position = ccp(winSize.width * 0.20,winSize.height * 0.92);
[self addChild:_label];
}
}
if (targetsToDelete.count > 0) {
[targetsToDelete addObject:target];
}
[targetsToDelete release];
}
for (CCSprite *target in targetsToDelete) {
[_targets removeObject:target];
[self removeChild:target cleanup:YES];
//[[SimpleAudioEngine sharedEngine] playEffect:#"ProjectileHit.wav"];
}
[targetsToDelete release];
}
-(void) registerWithTouchDispatcher
{
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0
swallowsTouches:YES];
}
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
return YES;
}
-(void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint touchLocation = [touch locationInView: [touch view]];
touchLocation = [[CCDirector sharedDirector] convertToGL: touchLocation];
touchLocation = [self convertToNodeSpace:touchLocation];
float bankerVelocity = 320.0/2.0;
CGPoint moveDifference = ccpSub(touchLocation, _Banker.position);
float distanceToMove = ccpLength(moveDifference);
float moveDuration = distanceToMove / bankerVelocity;
if (moveDifference.x < 0) {
_Banker.flipX = NO;
} else {
_Banker.flipX = YES;
}
[_Banker stopAction:_MoveAction];
if (!_Moving) {
[_Banker runAction:_WalkAction];
}
self.MoveAction = [CCSequence actions:
[CCMoveTo actionWithDuration:moveDuration position:touchLocation],
[CCCallFunc actionWithTarget:self selector:#selector(bearMoveEnded)],
nil];
[_Banker runAction:_MoveAction];
_Moving = TRUE;
}
-(void)bearMoveEnded {
[_Banker stopAction:_WalkAction];
_Moving = FALSE;
}
// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
// in case you have something to dealloc, do it in this method
// in this particular example nothing needs to be released.
// cocos2d will automatically release all the children (Label)
self.Banker = nil;
self.WalkAction = nil;
// don't forget to call "super dealloc"
[super dealloc];
}
#end
The scene starts and everything works fine except as soon as a target is added (this is what I think is happeneing) the game freezes and crashes.
I don't know if the target being added is what is causing the crash, but it seems that whenever it is time for the target to come on, it crashes.
There is nothing in the debugger that says the game crashed, Xcode things the game is still running even though it is frozen. Please help :/ thanks
retain the _targets array in the init method like this: _targets = [[[NSMutableArray alloc] init] retain];

How to get CCScrollLayer to scroll?

I am trying to get CCScrollLayer to work in my cocos2d app, but it won't scroll.
Here is what I did:
Using the cocos2d template, created a iOS cocos2d project. Added the CCScrollLayer files, and imported into my HelloWorldLayer class. Added a method "layerWithLevelName" to create the layers.
In init, I created a few layers for testing. Below is the code for my HelloWorldLayer implementation. It is very basic, as I am just trying to get some layers to scroll.
#
// HelloWorldLayer implementation
#import "HelloWorldLayer.h"
#import "CCScrollLayer.h"
#implementation HelloWorldLayer
+(CCScene *) scene
{
CCScene *scene = [CCScene node];
HelloWorldLayer *layer = [HelloWorldLayer node];
[scene addChild: layer];
// return the scene
return scene;
}
-(CCLayer*) layerWithLevelName:(NSString*)name number:(int)number screenSize:(CGSize)screenSize
{
CCLayer *layer = [[[CCLayer alloc] init]autorelease];
int largeFont = [CCDirector sharedDirector].winSize.height / 9;
CCLabelTTF *layerLabel = [CCLabelTTF labelWithString:name fontName:#"Marker Felt" fontSize:largeFont];
layerLabel.position = ccp( screenSize.width / 2 , screenSize.height / 2 + 10 );
layerLabel.rotation = -6.0f;
layerLabel.color = ccc3(95,58,0);
[layer addChild:layerLabel];
return layer;
}
// on "init" you need to initialize your instance
-(id) init
{
// always call "super" init
// Apple recommends to re-assign "self" with the "super" return value
if( (self=[super init]))
{
// ask director the the window size
NSMutableArray* _layers = [[NSMutableArray alloc]init];
CGSize screenSize = [CCDirector sharedDirector].winSize;
for (int i=0; i<3; i++)
{
int number = i;
NSString* name = [[NSString alloc]initWithFormat:#"level%d",i];
CCLayer* layer = [self layerWithLevelName:name number:number screenSize:screenSize];
[_layers addObject:layer];
[name release];
}
// Set up the swipe-able layers
CCScrollLayer *scroller = [[CCScrollLayer alloc] initWithLayers:_layers
widthOffset:230];
[self addChild:scroller];
// [scroller selectPage:0];
[scroller release];
[_layers release];
}
return self;
}
- (void) dealloc
{
[super dealloc];
}
#end
If you run the code, you will find that you can see the levels / scroll layer --> It seems to have loaded properly. But you can't scroll. What have I forgotten to do? What am I doing wrong?
EDIT: I am using cocos2d-iphone 1.1beta2
It seems that this is an issue with 1.1beta2.
A temporary workaround is to set scroller.stealTouches = NO;
I don't know what other side effects this has though.
EDIT:
Fix: Use updated CCTouchDispatcher files:
https://github.com/cocos2d/cocos2d-iphone/blob/develop/cocos2d/Platforms/iOS/CCTouchDispatcher.m
and corresponding .h file
https://github.com/cocos2d/cocos2d-iphone/blob/develop/cocos2d/Platforms/iOS/CCTouchDispatcher.h

How to unload images in Cocos2d

I am working with cocos2d. At the first Default.png load as first splash, then splash1.png load as second splash. I see in Instruments, that memory don't free when I replace scene. How can I unload images from memory? Thanks!
#import "cocos2d.h"
#import "MainMenu.h"
#interface Splash : CCLayer {
NSMutableArray *m_pSplashes;
int m_nCurrentSplash;
CGSize m_szWinSize;
CCSequence *m_pSequence, *m_pSequenceDefault;
CCCallFunc *m_pCall;
CCSprite *m_pSplashDefault, *splash;
id m_pFadein, m_pDelay, m_pFadeout;
}
#property(nonatomic, retain) CCSequence *m_pSequence;
+(id) scene;
-(void) showNext: (id) sender;
#end
Implementation file
#import "Splash.h"
#implementation Splash
#synthesize m_pSequence;
+(id) scene {
CCScene *scene = [CCScene node];
Splash *layer = [Splash node];
[scene addChild: layer];
return scene;
}
-(id) init {
if( (self=[super init]) ) {
m_szWinSize = [[CCDirector sharedDirector] winSize];
m_pFadein = [CCFadeIn actionWithDuration:2];
m_pDelay = [CCDelayTime actionWithDuration:2];
m_pFadeout = [CCFadeOut actionWithDuration:2];
m_pCall = [CCCallFunc actionWithTarget:self selector:#selector(showNext:)];
m_nCurrentSplash = 0;
m_pSplashes = [[NSMutableArray alloc] init];
m_pSequenceDefault = [CCSequence actions:m_pFadeout, m_pCall, nil];
[m_pSplashes addObject:#"splash1.png"];
m_pSplashDefault = [[[CCSprite alloc] initWithFile:#"Default.png"] autorelease];
[m_pSplashDefault setRotation:-90];
[m_pSplashDefault setPosition:ccp(m_szWinSize.width/2, m_szWinSize.height/2)];
[self addChild:m_pSplashDefault];
[m_pSplashDefault runAction:m_pSequenceDefault];
[m_pFadein retain];
[m_pDelay retain];
[m_pFadeout retain];
[m_pCall retain];
}
return self;
}
-(void) showNext: (id) sender {
if ( m_nCurrentSplash >= [m_pSplashes count] )
{
CCScene *scene = [CCScene node];
id child = [MainMenu node];
[scene addChild:child];
[[CCDirector sharedDirector] replaceScene: [CCFadeTransition transitionWithDuration:1 scene:scene]];
[m_pCall release];
}
else
{
splash = [[[CCSprite alloc] initWithFile:[m_pSplashes objectAtIndex:m_nCurrentSplash]] autorelease];
[splash setPosition:ccp(m_szWinSize.width/2, m_szWinSize.height/2)];
splash.tag = 1;
[self addChild:splash];
m_nCurrentSplash ++;
m_pSequence = [CCSequence actions:m_pFadein, m_pDelay, m_pFadeout, m_pCall, nil];
[splash runAction:m_pSequence];
}
}
-(void) dealloc {
NSLog ( #"dealloc" );
[m_pSplashes release];
[m_pFadein release];
[m_pDelay release];
[m_pFadeout release];
[self removeAllChildrenWithCleanup:YES];
[super dealloc];
}
#end
Either you manually handle by using
[[CCTextureCache sharedTextureCache]removeTexture:(CCTexture2D *)tex]
or:
[[CCTextureCache sharedTextureCache] removeUnusedTextures];
if you are sure the texture is no longer being use.