Make Skspritenode Subclass Using Swift

Make SKSpriteNode subclass using Swift

You have to call the designated initializer for SKSpriteNode. I'm actually surprised you didn't get another error about not full implementing SKSpriteNode, are you using an older Xcode6 beta maybe?

Since you have to use the designated initializer, you need to call super.init(texture: '', color: '', size: '').

It would be something like this:

class Ball: SKSpriteNode {
init() {
let texture = SKTexture(imageNamed: "ball")
super.init(texture: texture, color: nil, size: texture.size())
}

required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

Note: I also added the init for NSCoder which Xcode will require.

How to create subclass of SKSpriteNode in Swift 3

Turns out my code is fine, the bugs were due to something else. If anyone sees this - it is now that easy to add new attributes to a subclass - you don't have to faff around with super inits etc.

print(Ci.pitch) 

will now give "middle C".

Am unable to subclass SKSpriteNode using an image name

Just use the full initializer on the super, like so...

class MyBall : SKSpriteNode{

init(iNamed: String) {
let texture = SKTexture(imageNamed: iNamed)
super.init(texture: texture, color: .clear, size: texture.size())
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

Creating an SKSpriteNode class with Swift 4

you are declaring your init to have two parameters (texture: SKTexture, size: CGSize) but you are not passing the parameters in your initialization call

let player = Vaisseau()

you either need to change the initialization to...

let texture = SKTexture(imageNamed: "player")
let player = Vaisseau(texture: texture, size: texture.size())

and change the init to

init(texture: SKTexture, size: CGSize) {
super.init(texture: texture, color: UIColor.clear, size: size)
}

OR change the init in the class to...

init() {
let texture = SKTexture(imageNamed: "player")
super.init(texture: texture, color: UIColor.clear, size: texture.size())
}

and leave your initialization call as...

let player = Vaisseau()
player.position = CGPoint(x: 500, y: 500)
addChild(player)

EDIT added the above 2 lines to show you that those need to be in the scene
but other items such as alpha, zPosition, actions, zRotation etc. can be inside of the class

What you need to ask yourself to figure out which one to use is "will the texture for the player ever be different?" if so you may want to consider the first option where you pass in the texture.

Changing texture for subclass of SKSpriteNode?

Your code works well. In fact this SO answer is correct.

About SKSpriteNode subclass, the update method is a new custom function added by you, because the instance method update(_:) is valid only for SKScene class, this just to say that this function is not performed if it is not called explicitly.

To make a test about your class you can change your code as below( I've changed only textureForLevel method only to make this example):

class CharacterNode: SKSpriteNode {
let spriteSize = CGSize(width: 70, height: 100)
var level = 0
init(level: Int) {
self.level = level
super.init(texture: nil, color: UIColor.clear, size: spriteSize)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func update(level: Int) {
self.level = level
self.texture = textureForLevel(level: level)
}
func textureForLevel(level: Int) -> SKTexture {
if level == 3 {
return SKTexture(imageNamed: "TestTexture3.jpg")
}
return SKTexture(imageNamed: "TestTexture.jpg")
}
}

class GameScene: SKScene {
override func didMove(to view: SKView) {
let characterNode = CharacterNode(level:2)
characterNode.update(level:2)
addChild(characterNode)
characterNode.position = CGPoint(x:self.frame.midX,y:self.frame.midY)
characterNode.run(SKAction.wait(forDuration: 2.0), completion: {
characterNode.update(level:3)
})
}
}

As you can see when you launch GameScene a characterNode sprite will be shown in the center of the screen. After 2 seconds, the texture will change.

Why am I unable to subclass the SKSpriteNode

In Swift, you need to call an initializer that is implemented directly from your super class, in this case, SKSpriteNode. super.init() is implemented by another class that is in SKSpriteNode's inheritance tree, like SKNode or NSObject. You can always check the documentation for which constructors can you call for each class. It's very important to pay understand that you need to call designated initializers in your subclass

For example, you can do

class GuessSlot : SKSpriteNode{
init(color: SKColor, size: CGSize) {
super.init(texture: nil, color: color, size: size)
}

required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}

How to inherit the SKspritenode and create by self.childNode

leftCar is of type Car so compiler is complaining to cast childNode as Car instead of SKSpriteNode shown below.

func setUp() {
if let car = self.childNode(withName: "leftCar") as? Car {
leftCar = car
}
}

BTW, you already initialized leftCar in the same GameScene so you can simply use that instead of assigning it again.


Set custom class Car in GameScene.sks for leftCar node as shown in below image,

Sample Image

Creating Initializers for SKSpriteNode Subclass

The compiler is right: your override would be fine except that you haven't initialized your properties. If you need to have parameters to do that, then you'll need to create a new designated initializer instead: your init(texture: SKTexture, color: UIColor, size: CGSize, rangeOfMovement: CGFloat, originalPosition: CGFloat, platformNumber: Int) will do; simply remove convenience from it, as it is a new designated initializer, not a convenience initializer. (Convenience initializers, as the compiler points out, must delegate across to self.something, not up as you wish to do.)

As for init?(coder:), you're fine to use the fatalError version as long as you are never going to encode or decode instances of your subclass. If you do need to make use of NSCoding, then you'll need to provide a working implementation of init?(coder:) and override encodeWithCoder(_:), too.

How to add a sprite from another class on the gameScene

You don't generally subclass the scene for instances such as this. More likely you are meaning to make boss a subclass of SKSpriteNode and adding it to your scene. While there is probably dozens of ways that you could subclass this, this is just 1 way.

Also worth noting that it is not generally acceptable practice to make your variable names capitalized, classes yes, variables no.

class Boss: SKSpriteNode {

init() {

let texture = SKTetxure(imageNamed: "boss1")
super.init(texture: texture , color: .clear, size: texture.size())

zPosition = 2
//any other setup such as zRotation coloring, additional layers, health etc.
}
}

...meanwhile back in GameScene

class GameScene: SKScene {

let boss1: Boss!

override func didMove(to view: SKView) {

boss1 = Boss()
boss1.position = CGPoint(x: size.width * 0.1, y: size.height * 0.5)
self.gameScene.addChild(boss1)
}
}

in GameScene you create an instance of the new class and position it and add it in the GameScene.

edit

the init function has a short cut in swift.

Boss()

is the same as

Boss.init()

you can also add custom parameters to your init in order to further clarify or add more features to your class. for example...

class Boss: SKSpriteNode {

private var health: Int = 0

init(type: Int, health: Int, scale: CGFloat) {

let texture: SKTetxure!

if type == 1 {
texture = SKTetxure(imageNamed: "boss1")
}
else {
texture = SKTetxure(imageNamed: "boss2")
}
super.init(texture: texture , color: .clear, size: texture.size())

self.health = health
self.setScale(scale)
zPosition = 2
//any other setup such as zRotation coloring, additional layers, health etc.
}
}

Using properties of SKSpriteNode for subclass

Not sure if this is what you're asking, but, generally, if you create a subclass of an object, you don't need to do anything special to access the superclass's properties. They'll be initialized in the usual fashion.

However, you DO have to ensure that the superclass's initializers get called in a proper manner if you have your own initializers for your subclass.

In the case of a subclass of SKSpriteNode, if you define your own initializer for the subclass, that initializer will need to call the designated superclass initializer, which passes in the texture, color, and size to use for the sprite:

init(enemyType:String) {
let texture = SKTexture(imageNamed: "enemy_\(enemyType)")
let color = UIColor.black
let size = texture.size()
super.init(texture: texture, color: color, size: size)
}


Related Topics



Leave a reply



Submit