Keeps Crashing when CCSprite * on Update

Hi kind sirs. I’m currently working on the Space Shooter tutorial on http://www.raywenderlich.com/11338/cocos2d-x-for-ios-and-android-space-game
It seems that some of the code on the tutorial is not supported in the latest releases. I tried to search for alternatives and new methods to make it work. But I’m currently in a dilema and it keeps my game crashing.

I’m on the part of the tutorial where I have to add in some asteroids into the game. I pasted my HelloWorldScene.h and .cpp code. It seems that the game crashes when I use this line 184:
CCSprite asteroid = );
I’m not sure why. I appreciate any help. Thanks in advance and thank you for the developers working on cocos2d-x. I’m enjoying the learning so far.
HelloWorldScene.h
<pre>

#ifndef HELLOWORLD_SCENE_H
#define HELLOWORLD_SCENE_H
#include “cocos2d.h”
#include “CCParallaxNodeExtras.h”
USING_NS_CC;
class HelloWorld : public cocos2d::CCLayer
{
private:
CCSpriteBatchNode
*batchNode;
CCSprite**ship;

// Parallax
CCParallaxNodeExtras* *backgroundNode;
CCSprite**spacedust1;
CCSprite* *spacedust2;
CCSprite**planetsunrise;
CCSprite* *galaxy;
CCSprite**spacialanomaly;
CCSprite* spacialanomaly2;
// Accelerometer
float
shipPointsPerSecY;

public:

// Asteroids
CCArray* asteroids;
CCSprite* asteroid;
int
nextAsteroid;
float *nextAsteroidSpawn;
void update;
// Asteroids
float randomValueBetween;
void setInvisible;
float getTimeTick;
// Accelerometer
virtual void didAccelerate;
// Here’s a difference. Method ‘init’ in cocos2d-x returns bool, instead of returning ‘id’ in cocos2d-iphone
virtual bool init;
// there’s no ‘id’ in cpp, so we recommand to return the exactly class pointer
static cocos2d::CCScene* scene;
// a selector callback
void menuCloseCallback;
// implement the “static node()” method manually
CREATE_FUNC;
};
#endif //*HELLOWORLD_SCENE_H_

On line 184. When I add that line, it keeps crashing the game. If I comment it out up to line 200. The game works. But the asteroids are not showing up. HelloWorldScene.cpp
#include "HelloWorldScene.h"
#include "SimpleAudioEngine.h"

using namespace cocos2d;
using namespace CocosDenshion;

CCScene* HelloWorld::scene()
{
    // 'scene' is an autorelease object
    CCScene *scene = CCScene::create();

    // 'layer' is an autorelease object
    HelloWorld *layer = HelloWorld::create();

    // add layer as a child to scene
    scene->addChild(layer);

    // return the scene
    return scene;
}

// on "init" you need to initialize your instance
bool HelloWorld::init()
{
    //////////////////////////////
    // 1. super init first
    if ( !CCLayer::init() )
    {
        return false;
    }

    // CLOSE
    CCMenuItemImage *pCloseItem = CCMenuItemImage::create(
                                            "CloseNormal.png",
                                            "CloseSelected.png",
                                            this,
                                            menu_selector(HelloWorld::menuCloseCallback) );
        pCloseItem->setPosition( ccp(CCDirector::sharedDirector()->getWinSize().width - 20, 20) );

        // create menu, it's an autorelease object
        CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);
        pMenu->setPosition( CCPointZero );
        this->addChild(pMenu, 1);
    // End Close

    // Load the spritesheet pvr.ccz in just 1 batch call
    _batchNode = CCSpriteBatchNode::create("Sprites.pvr.ccz");
    this->addChild(_batchNode);
    CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("Sprites.plist");

    // Ship Sprite
    _ship = CCSprite::createWithSpriteFrameName("SpaceFlier_sm_1.png");
    CCSize winSize = CCDirector::sharedDirector()->getWinSize();
    _ship->setPosition( ccp(winSize.width * 0.1, winSize.height * 0.5) );
    _batchNode->addChild(_ship, 1);

    // 1. Create the CCParallaxNode
    _backgroundNode = CCParallaxNodeExtras::node();
    this->addChild(_backgroundNode, -1);

    // 2. Create the Sprite we'll add to the CCParallaxNode
    _spacedust1 = CCSprite::create("bg_front_spacedust.png");
    _spacedust2 = CCSprite::create("bg_front_spacedust.png");
    _planetsunrise = CCSprite::create("bg_planetsunrise.png");
    _galaxy = CCSprite::create("bg_galaxy.png");
    _spacialanomaly = CCSprite::create("bg_spacialanomaly.png");
    _spacialanomaly2 = CCSprite::create("bg_spacialanomaly2.png");

    // 3. Determine the relative movement speeds for space dust and background
    CCPoint dustSpeed = ccp(0.1, 0.1);
    CCPoint bgSpeed = ccp(0.05, 0.05);

    // 4. Add Children to CCParallaxNode
    _backgroundNode->addChild( _spacedust1, 0, dustSpeed, ccp(0, winSize.height / 2) );
    _backgroundNode->addChild( _spacedust2, 0, dustSpeed, ccp(_spacedust1->getContentSize().width, winSize.height/2) );
    _backgroundNode->addChild(_galaxy, -1, bgSpeed, ccp(0, winSize.height * 0.7));
    _backgroundNode->addChild(_planetsunrise, -1, bgSpeed, ccp(600, winSize.height * 0));
    _backgroundNode->addChild(_spacialanomaly, -1, bgSpeed, ccp(900, winSize.height * 0.3));
    _backgroundNode->addChild(_spacialanomaly2, -1, bgSpeed, ccp(1500, winSize.height * 0.9));

    //  Star Particles
    // Initialize Particles
    CCParticleSystemQuad* star1 = CCParticleSystemQuad::create("Stars1.plist");
    CCParticleSystemQuad* star2 = CCParticleSystemQuad::create("Stars2.plist");
    CCParticleSystemQuad* star3 = CCParticleSystemQuad::create("Stars3.plist");

    // Set the position of start particles
    star1->setPosition(ccp(winSize.width, winSize.height/2));
    star2->setPosition(ccp(winSize.width, winSize.height/2));
    star3->setPosition(ccp(winSize.width, winSize.height/2));

    // Let there be light!
    this->addChild(star1);
    this->addChild(star2);
    this->addChild(star3);
    //HelloWorld::addChild(CCParticleSystemQuad::create("Stars1.plist")) ;
    //HelloWorld::addChild(CCParticleSystemQuad::create("Stars2.plist")) ;
    //HelloWorld::addChild(CCParticleSystemQuad::create("Stars3.plist")) ;

    // Accelerometer


    // Asteroids
    #define KNUMASTEROIDS 15
    CCArray *_asteroids = CCArray::createWithCapacity(15);
    for(int i = 0; i < KNUMASTEROIDS; i++)
    {
        asteroid = CCSprite::createWithSpriteFrameName("asteroid.png");
        asteroid->setVisible(false);
        _batchNode->addChild(asteroid);
        _asteroids->addObject(asteroid);
    }

    _nextAsteroid = 0;

    this->scheduleUpdate();
    this->setAccelerometerEnabled(true);
    return true;
}

void HelloWorld::update(float dt)
{
    CCPoint backgroundScrollVert = ccp(-1000, 0);
    _backgroundNode->setPosition(ccpAdd(_backgroundNode->getPosition(),ccpMult(backgroundScrollVert,dt)));

    // Space Dust Parallax
    CCArray *spaceDusts = CCArray::createWithCapacity(2) ;
    spaceDusts->addObject(_spacedust1) ;
    spaceDusts->addObject(_spacedust2) ;


    for ( int ii = 0  ; ii < spaceDusts->count() ; ii++ ) {
        CCSprite * spaceDust = (CCSprite *)(spaceDusts->objectAtIndex(ii)) ;

        float xPosition = _backgroundNode->convertToWorldSpace(spaceDust->getPosition()).x  ;
        float size = spaceDust->getContentSize().width ;

        if ( xPosition < -size + 300 ) {
            _backgroundNode->incrementOffset(ccp(spaceDust->getContentSize().width*2,0), spaceDust) ;

        }
    }

    // Background Parallax
    CCArray *backGrounds = CCArray::createWithCapacity(4) ;
    backGrounds->addObject(_galaxy) ;
    backGrounds->addObject(_planetsunrise) ;
    backGrounds->addObject(_spacialanomaly) ;
    backGrounds->addObject(_spacialanomaly2) ;

    for ( int jj = 0 ; jj < backGrounds->count() ; jj++ ) {
        CCSprite * background = (CCSprite *)(backGrounds->objectAtIndex(jj)) ;
        float xPosition = _backgroundNode->convertToWorldSpace(background->getPosition()).x ;
        float size = background->getContentSize().width ;

        if ( xPosition < -size ) {
            _backgroundNode->incrementOffset(ccp(2000,0),background) ;
        }
    }

    // Accelerometer
    CCSize winSize = CCDirector::sharedDirector()->getWinSize();
    float maxY = winSize.height - _ship->getContentSize().height/2;
    float minY = _ship->getContentSize().height/2;

    float diff = (_shipPointsPerSecY * dt) ;
    float newY = _ship->getPosition().y + diff;
    newY = MIN(MAX(newY, minY), maxY);

    _ship->setPosition(ccp(_ship->getPosition().x, newY));


    // Asteroids
    float curTimeMillis = getTimeTick();

    if(curTimeMillis > _nextAsteroidSpawn)
    {
        float randMillisecs = randomValueBetween(0.20,1.0) * 1000;
        _nextAsteroidSpawn = randMillisecs + curTimeMillis;

        float randY = randomValueBetween(0.0, winSize.height);
        float randDuration = randomValueBetween(2.0,10.0);

        CCSprite *asteroid = (CCSprite *)(_asteroids->objectAtIndex(_nextAsteroid)); // <--- this makes it crash
        _nextAsteroid++;

        if(_nextAsteroid >= _asteroids->count())
        {
            _nextAsteroid = 0;
        }


        asteroid->stopAllActions();
        asteroid->setPosition( ccp(winSize.width+asteroid->getContentSize().width/2, randY));
        asteroid->setVisible(true);
        asteroid->runAction(CCSequence::create (
                CCMoveBy::create(randDuration,ccp(-winSize.width-asteroid->getContentSize().width,0)) ,
                CCCallFuncN::create(this,callfuncN_selector(HelloWorld::setInvisible)) ,
                NULL // DO NOT FORGET TO TERMINATE WITH NULL (unexpected in C++)
                ));
    }

}

void HelloWorld::didAccelerate(CCAcceleration* pAccelerationValue)
{
#define KFILTERINGFACTOR 0.1
#define KRESTACCELX -0.6
#define KSHIPMAXPOINTSPERSEC (winSize.height * 0.5)
#define KMAXDIFFX 0.2

    float rollingX;
    // Cocos2DX inverts X and Y accelerometer depending on device orientation
    // in landscape mode right x=-y and y=x !!! (Strange and confusing choice)

    pAccelerationValue->x = pAccelerationValue->y;
    rollingX = (pAccelerationValue->x * KFILTERINGFACTOR) + (rollingX * (1.0 - KFILTERINGFACTOR));

    // float accelX = pAccelerationValue->x - rollingX;
    float accelX = pAccelerationValue->x;

    CCSize winSize = CCDirector::sharedDirector()->getWinSize();

    float accelDiff = accelX - KRESTACCELX;
    float accelFraction = accelDiff / KMAXDIFFX;
    _shipPointsPerSecY = KSHIPMAXPOINTSPERSEC * accelFraction;
}

// Asteroids
float HelloWorld::randomValueBetween(float low, float high)
{
    return (((float) arc4random() / 0xFFFFFFFFu) * (high - low)) + low;
}

void HelloWorld::setInvisible(CCNode * node)
{
    node->setVisible(false);
}

float HelloWorld::getTimeTick()
{
    timeval time;
    gettimeofday(&time, NULL);
    unsigned long millisecs = (time.tv_sec * 1000) + (time.tv_usec / 1000);
    return (float) millisecs;
}

void HelloWorld::menuCloseCallback(CCObject* pSender)
{
    CCDirector::sharedDirector()->end();

#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
    exit(0);
#endif
}

If you look inside the CCArray::createWithCapacity() function, you’ll see that it returns an autoreleased object. What that means is that it’ll get cleaned up by the system at some undetermined point in the future. I think what’s happening here is that you’re making the CCArray (using createWithCapacity()) and then some crazy system process is cleaning it up for you in the background. Your pointer is still pointing to the bit of memory where the CCArray used to live… but it’s not there any more, hence the crash.

The solution is to add @ _asteroids->retain()@ just after the createWithCapacity() call. That’ll keep it around until you choose to get rid of it by calling _asteroids->release(). Of course you’ll need to add that somewhere too, perhaps in the menuCloseCallback function?

Ben

That worked perfectly! Thank you, Ben Ward!