0

I create sprite node in my GameScene as the following. I would like to reuse createNodeA1 or nodeA1 in other SKScene. How can I do that?

import SpriteKit

class GameScene: SKScene {

var nodeA1: SKNode!

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

override init(size: CGSize) {
    super.init(size: size)

    // Add sprite node to the scene        
    nodeA1 = createNodeA1()
    addChild(nodeA1)

    }
}

// Create dot 1
func createNodeA1() -> SKNode {
    let spriteNode = SKNode()
    spriteNode.position = CGPointMake(CGRectGetMidX(self.frame)/1.5, CGRectGetMidY(self.frame)/2.0)

    let sprite = SKSpriteNode(imageNamed: "dot_1")
    sprite.zPosition = 3.0
    sprite.name = "A1_Broj"
    spriteNode.addChild(sprite)

    return spriteNode
}

}
saate_group
  • 51
  • 10

2 Answers2

1

There is a few ways to do this.

You could subclass your other scenes to be subclass of the scene with the loadNode function which gives those scenes access to that function.

I asked a question about this last year

Swift multiple level scenes

Another way that might be a bit easier if you are not comfortable with scene subclassing is to just create a subclass of the node itself.

So you create a class

enum EnemyType {
   case Normal
   case Special
} 


class NodeA1: SKSpriteNode {

   init(imageNamed: String, enemyType: EnemyType) {
      let texture = SKTexture(imageNamed: imageNamed)

      if enemyType == .Normal {
           super.init(texture: texture, color: SKColor.clearColor(), size: texture.size())
      else {
         // other init
      }

     self.zPosition = 1
     self.name = ""
     // add physics body, other properties or methods for the node

    }
}

Than in your SKScenes you can add the node in the init method like so

  nodeA1 = NodeA1(imageNamed: "ImageName", enemyType: .Normal)
  nodeA1.position = ....
  addChild(nodeA1)

this way ever scene where you add the node will use the subclass and therefore include all the properties, set up etc for that node. Another benefit with subclassing is that you could loop through all your nodes using

self.enumerateChildNodesWithName...

and than call custom methods on all nodes.

If you want to subclass your scenes than you would create your baseScene

 class BaseScene: SKScene {

     // set up all shared stuff in didMoveToView
     // have your node function here 
     // touches began
     // physics word and contact collision 
     // all other stuff that needs to be shared between all level scenes

   }

Than your subsequent level scenes would look something like this

  class Level1Scene: BaseScene {

     override func didMoveToView(view: SKView) {
           super.didMoveToView(view) // This lines imports all stuff in BaseScene didMoveToView


       // do level 1 specific setUps.
       // you can call any function or property from BaseScene, e.g the loadNode function.
  }

You than load you level scenes as usual, e.g you transition to level 1 scene and it will automatically use/have access to all the superclass methods and sprites (BaseScene). So you never call baseScene directly, its gets called automatically.

This applies for other methods in baseScene too, so say you have a Update method in BaseScene.

 override func update(currentTime: CFTimeInterval) {.... }

This will work across all your level scenes which are subclasses of BaseScene.

But what happens if you need to add some specific stuff to the update method only relevant in 1 level scene and not all level scenes? It would be the same process, you create a new update func in the LevelScene and call super.

 override func update(currentTime: CFTimeInterval) {
     super.update(currentTime) // this calls the baseScene Update method

    /// specific stuff for that level only
  }

Super simply means the super class of the currentScene, which is BaseScene if the scene is a subclass of it.

Is this helping?

Community
  • 1
  • 1
crashoverride777
  • 10,581
  • 2
  • 32
  • 56
  • Yes, great answer. Thank you. I would ask one more thing. If I create subclass of this nodeA1 using init() method, can I also have in this same subclass more then one init() method, for example if I wanted to create more nodes (nodeA1, nodeA2, nodeA3, etc.) to be used throughout the app? Thanks. – saate_group Mar 09 '16 at 03:14
  • Yes you can. You could create an enum above the class method with your enemy types, and than you pass it into the init method like the imageString. Than you load the correct init() depending on the enemyType using if statements. Keep in mind that you can resume this class as many times as you want, so you can add 20 enemies to the screen all with the same subclass. It depends what your enemies are, if they are all more or less the same just have one subclass. – crashoverride777 Mar 09 '16 at 03:21
  • If they are all different, with different actions etc than its properly nicer to just crate more subclasses instead of having different init methods. Please mark my answer as correct if you dont mind. Thanks – crashoverride777 Mar 09 '16 at 03:21
  • Can you please update this answer to explain how to use enum above the class as you suggest. – saate_group Mar 09 '16 at 03:31
  • One additional question! Is subclassing other scenes to be subclass of the scene with the loadNode function the best way to handle this or use of init() methods is more preferred way in terms of efficiency? I will have to subclass first scene's functionality with the other 30 scenes that will be using the same nodes. Thanks. – saate_group Mar 09 '16 at 05:34
  • I updated the answer, let me know how it goes. If you are unsure simply open a new PlayGround file and play around with subclassing. Its not that hard once you know what you have to do. – crashoverride777 Mar 09 '16 at 14:05
  • If you have over 30 scenes than you most certainly want to have a BaseScene and subclass the other 30 scenes. – crashoverride777 Mar 09 '16 at 15:34
  • Super explanation. Thank you so much. I will try this when I get chance. – saate_group Mar 09 '16 at 22:33
  • I have posted another question "Draw line with finger within specific pattern on scene in sprite kit using Swift". Please see if you can help with this one or provide any resources to learn such drawing. Thanks. – saate_group Mar 11 '16 at 03:11
  • I will have a look at it later. – crashoverride777 Mar 11 '16 at 13:31
  • Sorry my friend, I just had a look at your new question and its beyond my knowledge. I am not very confident yet with CGPaths, so its properly best for someone else to hopefully answer that particular question. – crashoverride777 Mar 11 '16 at 17:55
  • Hey, it's all good. Thanks for helping on other stuff. I'll figure something out. – saate_group Mar 11 '16 at 18:55
  • Let's say I create node1 in baseScene. When in Level1Scene, the only thing I need to do is change position for node1. Can I just do the following in the didMoveToView function? 'node1.position = CGPointMake(CGRectGetMidX(self.frame)/1.3, CGRectGetMidY(self.frame)/2.0)' – saate_group Mar 13 '16 at 21:01
  • Yes of course, just try it. You can change color, position, etc – crashoverride777 Mar 13 '16 at 21:23
  • I tried and it works perfect. I just wanted to check if this is the right approach. Let's say I have node1 thru node6 in baseScene, but in Level1Scene I need two more nodes node7 and node8. Would I crate node7 and nod8 still in baseScene but add them to the scene in Level1Scene? – saate_group Mar 13 '16 at 21:30
  • It depends. Think of baseScene as the scene where you put stuff that you want shared across all scenes. So if node7 and node8 is only in Level1Scene than I would all the code there. There is no doing wrong there tho. Just think about your structures, code maintenance etc. You dont want BaseScene to have basically everything and than the Level scenes have next to nothing. – crashoverride777 Mar 13 '16 at 22:12
  • Thanks for your support on all this friend. I have another topic. Let's move to it "Adding multiple sprite nodes to the scene using single function/method in swift". I'm sure you can help there too. Thanks! – saate_group Mar 15 '16 at 04:46
  • I'll check it out later, let's not write more comments here as its too many, – crashoverride777 Mar 15 '16 at 12:39
  • I have to ask the following my friend. I I have sublcassed all 30 scenes from the baseScene. However, I start with Leve1Scene and I as transition from Level1Scene to Level2Scene memory use increases. As I keep going to Level3Scene all the way to the last Level30Scene, memory use just keeps increasing on each LevelXScene transition. Would you happen to know why? Am I suppose to use removeFromParent or some other method during scene transitions? Thanks much again! – saate_group Mar 21 '16 at 07:07
  • You probably have a memory leak somewhere. Check you properties from strong ones or read about ARC in swift. Try removing all nodes and their actions from the scene before transitioning, that sometimes works. I had a similar problem recently. Have a look here http://stackoverflow.com/questions/35798496/swift-spritekit-arc-for-dummies – crashoverride777 Mar 21 '16 at 12:30
  • Here what I did and it seems to work, and could help you if you face similar issue ever. I was adding child node in the touchesBegan method 'If node1.name = "String_Name" ' – saate_group Mar 21 '16 at 15:08
  • That line does not create a strong reference. – crashoverride777 Mar 21 '16 at 15:14
  • Here is what I did and it seems to work, and could help you if you face similar issue ever. I was adding child node in the touchesBegan method 'If node1.name = "String_Name then"', 'runAction.SKAction.withDuration' block, in where I did 'self.node1 = createNode1()' 'self.addChild(node1)', I runAction on this block as 'runAction(myCoolAction, withKey: "CoolAction")'. Where transition happens from Level1Scene to Level2Scene, which is in touchesBegan method, added 'self.removeActionForKey("CoolAction")'. Removing action for key, scenes now do deinitialize and memory usage is 25-30MB. – saate_group Mar 21 '16 at 15:23
  • This is what I told you if you would have read the link I posted. I created a method that loops through all nodes in a scene and removes their actions and children. Your way you would have to do for each node so you better not forget a node. I think this is actually a SpriteKit bug. – crashoverride777 Mar 21 '16 at 15:26
  • I read the link you posted. If I have two scenes Level1Scene and Level2Scene, where would you call cleanScene function? Since I'm subclassing 30 scenes, I would have to call this function each time I load next scene? Thanks. Hopefully this is my last question on this topic here! – saate_group Mar 21 '16 at 15:38
  • Please invite me to chat room again. I need to ask quick question in terms of protocol extensions. Thanks. – saate_group Mar 23 '16 at 02:49
  • Can you please ask another question. You are adding to many comment per question. – crashoverride777 Mar 23 '16 at 02:56
  • I'm sorry buddy. I know. I'm new to this site, yes I have been member for a while but have not used it until recently. I am blocked to ask questions at this time because as new member on this site I have asked questions which resulted in blocking me for now. We'll see when block will be released. – saate_group Mar 23 '16 at 03:04
  • We chat tomorrow, its late where I am – crashoverride777 Mar 23 '16 at 03:08
0

This is additional answer information in terms of subclass of the baseScene. We can create node1thru node10 all in baseScene. Then in Leve1Scene which is subclass of the baseScene, all we have to do is in didMoveToView function state node1.position = CGPointMake(....) for each node that we need in Level1Scene where we would specify node's position. If we do not need to load all of the 10 nodes in Level1Scene, for example, let's say we don't need to load to the scene node10 we can simply in didMoveToView function just state node10.removeFromParent() and this node will not be loaded to Level1Scene but rest of 9 nodes will. Note that this example uses only 10 nodes, but you can go with any number of nodes in your baseScene. This way of subclassing will save you a lot repeatable code in subclasses.

saate_group
  • 51
  • 10