Create a subclass of a SKSpriteNode subclass

吃可爱长大的小学妹 提交于 2019-12-24 01:14:53

问题


Let's say I want to create a bunch of different types of Spaceships. I want to setup a base spaceship class that I can use to create other spaceships with minor differences.

My base class looks like this.

// BaseSpaceship.h
@interface SpaceshipNode : SKSpriteNode
@property NSColor color;
@property CGFloat engineThrust;
+ (id)baseSpaceshipWithImageNamed:(NSString *)name;
@end

// BaseSpaceship.m
@implementation BaseSpaceship
+ (id)baseSpaceshipWithImageNamed:(NSString *)name {
    BaseSpaceship *ship = [BaseSpaceship spriteNodeWithImageNamed:name];

    ship.color = [NSColor redColor];
    ship.engineThrust = 2.0;

    return ship;
}
@end

I can create a ship in MyScene.m like this just fine.

BaseSpaceship *baseClass = [BaseSpaceship baseSpaceshipWithImageNamed:@"BaseShip"];

However, I'm not sure how to create a subclass of BaseSpaceship, for example, DestroyerSpaceship. I'm not sure if I should be using static methods or not. The examples I've seen online use static methods to instantiate SKSpriteNodes. This is what I came up with, but it's wrong.

// DestroyerSpaceship.h
@interface DestroyerSpaceship : BaseSpaceship
@property CGFloat missileThrust;
- (id)makeDestroyerSpaceship;
@end

// DestroyerSpaceship.m
@implementation DestroyerSpaceship
- (id)makeDestroyerSpaceship{
    DestroyerSpaceship *ship = [DestroyerSpaceship baseSpaceshipWithImageNamed:@"DestroyerShip"];
    ship.engineThrust = 2.0;
    // ship doesn't have missileThrust, program crashes
    ship.missileThrust = 3.0; 

    return ship;
}
@end

Ultimately, I want to be able to do something like this.

DestroyerSpaceship* a = [DestroyerSpaceship makeDestroyerSpaceship];
EvilSpaceship* b = [EvilSpaceship makeEvilSpaceship];
NiceSpaceship* c = [NiceSpaceship makeNiceSpaceship];

And have them all inherit basic properties and methods from BaseSpaceship.


回答1:


The answer is less complex than you think. Well, the code might be a bit more complex, but once you have the structure it is most flexible. Creating the different types of spaceships will also be a lot more readable.

You can override the initializer method in the subclass. As a sidenote, use (instancetype) instead of (id) (source: instancetype @ NSHipster).

As you are adding custom body sprites to the object, I would opt to subclass SKNode instead of SKSpriteNode (so @interface SpaceshipNode : SKNode instead of @interface SpaceshipNode : SKSpriteNode).

@interface SpaceshipNode : SKNode
  @property SKColor * color; // Use SKColor instead of NSColor
  @property CGFloat engineThrust;
@end

// ... 

@implementation SpaceshipNode

- (instancetype) init {
  if (self == [super init]) {
    NSLog(@"A new SpaceshipNode was just init'ed.");
    // set some default initial values here that all brand-new SpaceshipNodes will inherit

    // perhaps create and add a basic body sprite
    // SKSpriteNode * body = ...;
    // [self addChild:body];

    // set thrust
    self.engineThrust = 2.0;
  }
  return self;
}

Then you can subclass and create a new type of spaceship. Awesome!

@interface DestroyerSpaceship : SpaceshipNode
  @property CGFloat missileThrust;
@end

@implementation DestroyerSpaceship

- (instancetype) init {
  // note that [super init] will call the SpaceshipNode's init method
  if (self = [super init]) {
    NSLog(@"A new DestroyerSpaceship was just init'ed.");

    // add a body sprite
    // SKSpriteNode * body = ...;
    // [self addChild:body];

    // a Destroyer is much faster than your average spaceship
    self.engineThrust = 10.0;

    // set class specific variables
    self.missileThrust = 5.f;
  }
  return self;
}

Now, you can just call:

SpaceshipNode * newSpaceShip = [SpaceshipNode new]; // short for [[SpaceshipNode alloc] init];
DestroyerSpaceship * newDestroyer = [DestroyerSpaceship new];

These two lines will log the following. The last two lines are caused by the Destroyer, which first calls the SpaceshipNode init, and then the Destroyer-specific init method.

A new SpaceshipNode was just init'ed.

A new SpaceshipNode was just init'ed.

A new DestroyerSpaceship was just init'ed.

And you can even use it like this:

SpaceshipNode * newUnidentifiedVessel = [DestroyerSpaceship new];

if ([newUnidentifiedVessel isKindOfClass:[DestroyerSpaceship class]]) {
  NSLog(@"We are under attack! Route power to shields!");
}



回答2:


- (instancetype)makeDestroyerSpaceship{
    if (self = [super baseSpaceshipWithImageNamed:@"DestroyerShip"]) {
        self.engineThrust = 2.0;
        self.missileThrust = 3.0; 
    }
    return self;
}


来源:https://stackoverflow.com/questions/23946005/create-a-subclass-of-a-skspritenode-subclass

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!