Search code examples
iosobjective-cmemory-leakssprite-kitsknode

__stack_chk_fail in SKNode subclass


I have attempted to create an SKNode subclass for a node that will be called repeatedly, each time with a user interaction, then an breaking/explosion effect. However, whenever I try to run the code, I receive a SIGABRT error. Something to do with ___stack_chk_fail in the debug terminal.

Additionally, in the inspector, when the code breaks for the SIGABRT, all of these properties are displayed as nil.

This is the .m of my SKNode subclass:

#import "CandyNode.h"

static const int MAX_VELOCITY = 20;
static const int MIN_VELOCITY = 2;

@implementation CandyNode

- (instancetype)init {
    self = [super init];
    if (self == [super init])
    {
        _spriteType = arc4random()%4+1;
        NSString* imageRand = [NSString stringWithFormat:@"Sprite %i", _spriteType];

        _background = [SKSpriteNode spriteNodeWithImageNamed:imageRand];
        _background.name = @"Main";
        _background.zPosition = 3;
        [self addChild:_background];

        _burst1 = [SKSpriteNode spriteNodeWithImageNamed:[NSString stringWithFormat:@"S%dB%d",_spriteType,1]];
        _burst2 = [SKSpriteNode spriteNodeWithImageNamed:[NSString stringWithFormat:@"S%dB%d",_spriteType,2]];
        _burst3 = [SKSpriteNode spriteNodeWithImageNamed:[NSString stringWithFormat:@"S%dB%d",_spriteType,3]];

        _burst1.name = @"Burst #1";
        _burst2.name = @"Burst #2";
        _burst3.name = @"Burst #3";

        [_background setHidden:NO];

        [_burst1 setHidden:YES];
        [_burst2 setHidden:YES];
        [_burst3 setHidden:YES];

        [self addChild:_burst1];
        [self addChild:_burst2];
        [self addChild:_burst3];

        double burstAngle[3];
        int offsetAngle = 240;
        double burstDisplacement[3];
        CGVector burstVector[3];

        CGFloat x, y;
        for (int i = 0; i<=3; i++){
            burstAngle[i] = (arc4random()%60+120*i+offsetAngle)*3.1415/180;
            burstDisplacement[i] = arc4random()%(MAX_VELOCITY-MIN_VELOCITY)+ MIN_VELOCITY;
            x = burstDisplacement[i]*cos(burstAngle[i]);
            y = burstDisplacement[i]*sin(burstAngle[i]);
            burstVector[i] = CGVectorMake(x, y);
        }

        _explode1 = [SKAction sequence:@[[SKAction fadeInWithDuration:0],
                                         [SKAction moveBy:burstVector[0] duration:.5],
                                         [SKAction fadeOutWithDuration:.2]]];
        _explode2 = [SKAction sequence:@[[SKAction fadeInWithDuration:0],
                                         [SKAction moveBy:burstVector[1] duration:.5],
                                         [SKAction fadeOutWithDuration:.2]]];
        _explode3 = [SKAction sequence:@[[SKAction fadeInWithDuration:0],
                                         [SKAction moveBy:burstVector[2] duration:.5],
                                         [SKAction fadeOutWithDuration:.2]]];

    }
    return self;

}

.h:

#import <SpriteKit/SpriteKit.h>
@interface CandyNode : SKNode

//-(id)initWithImageNumber:(int)spriteType;
//-(void)explodeCandy;

@property (nonatomic) SKSpriteNode *background;
@property (nonatomic) SKSpriteNode *burst1;
@property (nonatomic) SKSpriteNode *burst2;
@property (nonatomic) SKSpriteNode *burst3;

@property (nonatomic) SKAction *explode1;
@property (nonatomic) SKAction *explode2;
@property (nonatomic) SKAction *explode3;

@property (nonatomic) int spriteType;


@end

And it is all called in a main SKScene with: _NodeA = [CandyNode new];, _NodeA being defined in that class's header as @property (nonatomic) CandyNode *NodeA;

My question is obviously how can I get this to work, or if I have a horrible misunderstanding of how to use subclasses and SpriteKit, how can I do this differently?


Solution

  • You are calling init twice:

    self = [super init];
    if (self == [super init])
    

    The first correctly assigns to self, the second creates an instance, compares it with self, then throws the new instance away.

    To fix this:

    self = [super init];
    if (self)
    

    UPDATE:

    You declare an array with 3 elements:

    double burstAngle[3];
    

    Then you enumerate over the array with a range of 0 to 3 (for loop runs four times):

    for (int i = 0; i<=3; i++){
    

    When i is 3 you have an index out of bounds situation, array indexes are zero-based.

    Fix it like so:

    for (int i = 0; i < 3; i++){