Bohm
Bohm

Reputation: 1004

Proper subclassing of SKSpriteNode and instance initialization

I am trying to subclass SKSpriteNode so that I can use it to create different characters with different properties for a game. I know this should be a trivial task, but I am having a hard time understanding how to initialize a variable when instances are created. In the header I have:

#import <SpriteKit/SpriteKit.h>

@interface MyClass : SKSpriteNode 
@property int myVariable;
@end

And in the implementation:

#import "MyClass.h"
@interface MyClass ()
@end

@implementation MyClass
@synthesize myVariable;

- (id)init {
    if (self = [super init]) {
        myVariable = 100;
    }
    return self;
}

When I create the node in the scene:

@implementation GameScene
{
    MyClass *mySprite;
}

- (void)didMoveToView: (SKView *) view
{
    mySprite = [MyClass spriteNodeWithImageNamed:@"image.png"];
}

The value of myVariable is 0, which I assume it means that spriteNodeWithImageNamed does not execute the init method. If I use:

mySprite = [[MyClass alloc] init]; // or mySprite = [MyClass new];
mySprite = [MyClass spriteNodeWithImageNamed:@"image.png"];

The variable name is correctly set to 100, but then reverted to 0 by spriteNodeWithImageNamed.

I have also tried:

mySprite = [[MyClass alloc] init]; // or mySprite = [MyClass new];
[mySprite setTexture:[SKTexture textureWithImageNamed:@"image.png"]];

In this case the value of myVariable is correct, but no image appears when I add the node to the scene. What init method is called when spriteNodeWithImageNamed is used? Am I improperly overriding the SKSpriteNode init method?

Upvotes: 1

Views: 780

Answers (2)

GeneCode
GeneCode

Reputation: 7588

Here is how I do it. Create your own custom init method, and simply call the default spritenode initWithImage.

-(id)initShipWithType:(ShipType)type {
    self = [super initWithImageNamed:[self getShipSprite:type]];
    if (self) {

    }
    return self;
}

Upvotes: 0

MaxKargin
MaxKargin

Reputation: 1545

You have done everything correctly with creating a class, but you need to keep in mind that you are calling the factory method spriteNodeWithImageNamed, which then initializes and allocates by itself. Thus, if you want to use your custom init method you need to override the factory method as well.

Inside of your implementation of MyClass, override the method to call your initializer:

+ (instancetype) spriteNodeWithImageNamed:(NSString *)imageName{
    MyClass *newClass = [[MyClass alloc] init];
    SKTexture *spriteTexture = [SKTexture textureWithImageNamed:imageName];
    newClass.size = spriteTexture.size;
    newClass.texture = spriteTexture;
    return newClass;
}

Hope this helps, let me know if you have questions.

*EDIT: Im actually a little tempted to ditch this, only because SKSpriteNode doesn't have an init method (or at least not that we know of). So unless you want to dive deep into Apple's mysteries then just do it this way:

+ (instancetype) spriteNodeWithImageNamed:(NSString *)imageName{
    MyClass *newClass = [[MyClass alloc] initWithImageNamed:imageName];
    newClass.myVariable = 100;
    return newClass;
}

You could instead override initWithImage to put in myVariable, but the whole point is that I'd avoid trying to use the init initializer with SKSpriteNode.

Upvotes: 3

Related Questions