问题
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 SKSpriteNode
s. 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