Cocos2d retain() in inherited classes

50 Views Asked by At

So I've had a lot of trouble with Cocos2d's auto-release shenanigans, and (almost) wish that I could just handle all of that myself...

Anyways, the problem I've had is with creating some animations. I've got a class called AnimatedDamageableSprite which inherits from DamageableSprite which inherits from Sprite which inherits from CCSprite etc...

When I create an AnimatedDamageableSprite, I have a successful animation on the screen, which runs as it should.

When I create a Suicider, which (you guessed it) inherits from AnimatedDamageableSprite, the CCArray which contains the frames for animation doesn't survive beyond the first loop, and on the second update attempt, the program gets an AV error.

Here's the code for the two classes:

Sprite.h

// This class works
class AnimatedDamageableSprite :public DamageableSprite {
public:
    AnimatedDamageableSprite(int hp, CCPoint pos, CCTexture2D* tex, int rows, int columns, float scaleX, float scaleY);
    virtual ~AnimatedDamageableSprite();
    virtual void update(float dt);
    virtual bool updateFrame(float dt);
    virtual SpriteType getType() { return ANIMATED_DAMAGEABLE_SPRITE; };
protected:
    float m_frameNum;
    CCArray* m_frames;
    int m_numOfFrames;
};

// This class doesn't
class Suicider :public AnimatedDamageableSprite {
public:
    Suicider(int difficulty);
    virtual ~Suicider();
    virtual void update(float dt);
    virtual SpriteType getType() { return SUICIDER; };
private:
    float m_speed;
};

Sprite.cpp

AnimatedDamageableSprite::AnimatedDamageableSprite(int hp, CCPoint pos, CCTexture2D* tex, int rows, int columns, float scaleX, float scaleY)
    :DamageableSprite(hp, pos, tex, scaleX, scaleY), m_frameNum(0), m_numOfFrames(rows*columns) {
    float texWidth = tex->getContentSize().width / (float)columns;
    float texHeight = tex->getContentSize().height / (float)rows;
    m_frames = CCArray::createWithCapacity(m_numOfFrames);
    m_frames->retain();
    for (unsigned int i = 0; i < columns; i++) {
        for (unsigned int j = 0; j < rows; j++) {
            CCRect r(i*texWidth, j*texHeight, texWidth, texHeight);
            m_frames->addObject(new CCSpriteFrame);
            ((CCSpriteFrame*)m_frames->lastObject())->createWithTexture(tex, r);
            ((CCSpriteFrame*)m_frames->lastObject())->initWithTexture(tex, r);
            m_frames->lastObject()->retain();
        }
    }
    initWithSpriteFrame((CCSpriteFrame*)m_frames->objectAtIndex(m_frameNum));
    setTexture(tex);
    setPosition(pos);
    setScaleX(scaleX);
    setScaleY(scaleY);
    updateTransform();
}

// This function is called every frame. It returns a boolean for unrelated reasons
bool AnimatedDamageableSprite::updateFrame(float dt) {
    bool retVal = false;
    // Assume animations are at 30 FPS for now
    m_frameNum += dt * 0.03f;
    while (m_frameNum >= m_numOfFrames) {
        m_frameNum -= m_numOfFrames;
        retVal = true;
    }
    setDisplayFrame((CCSpriteFrame*)m_frames->objectAtIndex(m_frameNum));
    updateTransform();
    return retVal;
}

// This class calls the constructor of the one that works, and does nothing else relevant to the problem
// It also doesn't override the updateImage() function
Suicider::Suicider(int difficulty)
    : AnimatedDamageableSprite(1, CCPoint(10,10), g_textureManager.getTexture("Suicider Sheet"), 6, 10, SCALE_WIDTH, SCALE_HEIGHT) {
    // ...
}

EDIT:

Seems I forgot to actually point out the problem.

The CCArray* m_frames declared in AnimatedDamageableSprite is fine when used in that instance, but it is deleted at the end of a frame when used in the Suicider class - i.e. it isn't being retained. Hence the AV error when I try to access an item inside it which no-longer exists

I tried retaining it in the Suicider constructor as well, although that didn't change anything.

0

There are 0 best solutions below