Add Skreferencenode/Skscene to Another Skscene in Spritekit

Add SKReferenceNode/SKScene to another SKScene in SpriteKit

I do that, I don't know if is the best way to do this, but works:

I've 2 file Dragon.swift and sks

Sample Image

I've added a "main" node like DragonNode and other node children of this

Sample Image

Now, the DragonNode is a custom class, set it in sks file:

Sample Image

The DragonNode is a normal SKSpriteNode

class DragonNode: SKSpriteNode, Fly, Fire {

var head: SKSpriteNode!
var body: SKSpriteNode!
var shadow: SKSpriteNode!
var dragonVelocity: CGFloat = 250

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

//Example other node from sks file
body = self.childNodeWithName("Body") as! SKSpriteNode
head = body.childNodeWithName("Head") as! SKSpriteNode
shadow = self.childNodeWithName("Shadow") as! SKSpriteNode
shadow.name = "shadow"
}

//Dragon Func
func fireAction () {}
func flyAction () {}
}

Inside the scene, add a SKReferenceNode:

Sample Image

In the SKScene code:

    let dragonReference = self.childNodeWithName("DragonReference") as! SKReferenceNode

let dragonNode = dragonReference.getBasedChildNode() as! DragonNode
print(dragonNode)
//Now you can use the Dragon func
dragonNode.flyAction()

getBasedChildNode() is an extension to find your based node (the first one)

extension SKReferenceNode {
func getBasedChildNode () -> SKNode? {
if let child = self.children.first?.children.first {return child}
else {return nil}
}
}

Add SKReferenceNode programmatically

I've found a workaround, it turns out there are no issues when creating a SKReferenceNode using the URL method.
For example:

let path = NSBundle.mainBundle().pathForResource("SpaceShip", ofType: "sks")
let spaceShip = SKReferenceNode (URL: NSURL (fileURLWithPath: path!))
addChild(spaceShip)

I did a little digging and it appears in 7.3.1 vs 7.2.1 when creating a SKReferenceNode using fileNamed it now returns an optional. When unwrapped you get the SKScene which will of course throw out errors if you try and add it as a child to an existing scene.

Added a quick 7.3 test project https://github.com/cocojoe/SKReferenceNodeIssue/tree/workaround

Notice you referenced my post on the Apple forum. I filled a bug report about a month ago, from past experience these can take a while to be looked at.

Spritekit - Add SKScene content to another SKScene

Ok, I figured out a solution. Maybe I was a bit to fast with going online and asking, but hopefully this will help someone else.

The way I do it is by creating a SKReferenceNode referencing the Scene, which contains the "Level Blocks". The SKReferenceNode can then be used like any other node.

Why can't I add a SKScene to another SKScene?


Can anyone tell me where I've gone wrong, and how I can fix it?

From the Overview section of the SKScene reference page:

A scene is the root node in a tree of Sprite Kit nodes (SKNode).

Since a tree can have only one root, any SKNode graph has just one scene.

To fix the problem, either use an SKNode (that's not a SKScene, obviously) to contain your end of game display. You can then add that node to your existing scene.

Deallocate SKScene after transition to another SKScene in SpriteKit

A similar problem was faced by the person who asked this question.

When asked whether he was able to solve it, they said:

Yes, I did, there wasn't anything I could do about it from the scene
or Sprite Kit for that matter, I simply needed to remove the scene and
the view containing it completely from the parent view, cut all its
bonds to the other parts of the system, in order for the memory to be
deallocated as well.

You should use separate views for each of your scene and transition between these views. You can follow these steps to make it look natural:

1 - At the point you want to transition from one scene to the other, take a snapshot of the scene using the following code:

UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, scale);
[self drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

Then, add this image as a subview of the SKView of the current scene, and remove the scene.

2 - Initialise the new scene on another view, and transition between the two views using UIView animation.

3 - Remove the first view from it's superview.

Import external nodes in SpriteKit using Swift

Can you post the code that you use to create the paddle? Also the code that you use to reference the paddle in your GameScene?

The referenced node (in your case the paddle) is a childnode of the SKReferenceNode. This means that your paddle assignment line should read:

let paddle = paddleRef.childNode(withName: "paddle")

Then you should only need to work with paddle rather than with paddleRef.

Alternatively I would create a dedicated class for the paddle, as a subclass of SKSpriteNode. It would deal with everything related to the paddle - it's position, rotation, size, transparency, image, color tint, etc.

Then it becomes really easy to reuse the paddle in any of your scenes - just create an instance of this class within the scene code, like that:

let paddle = Paddle()

(I assume you would name your paddle class "Paddle"). Then you are dealing with only one object and your paddle properties will work just fine - paddle.position, paddle.zRotation, paddle.size, etc.

If you need any help of how to setup the paddle class, let me know.

Stoyan

How to add an .sks files to existing Swift/Sprite-Kit project?

The reason why you are getting the required is because you have variables that are not optional or not initialized before init takes place.

If you have variables that need to be assigned inside of an init function, then you would do:

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

But then you will ask me: Mr Knight0fDragon, it is telling me to replace fileNamed with coder, and it is not compiling when I switch it.

Well this is because init(fileNamed:) is a convenience init, not a designated init. In order to be able to subclass a class and get all of it's convenience inits, you need to override all of it's designated inits.

Now with SKScene, you have 3, and you already know about 1.

Let's override the other 2:

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

Alright, now this puppy should be ready to compile, we just need to get the variables assigned.

Well what I like to do is create a setup method for any variable that has to be assigned in any version of initialization after the super is called.

Unfortunately we can't do this for constants before super is called, so those we would need to set up in each method. The reason being is that self does not fully exist yet.

This would end up looking like this:

let constant : String
required init?(coder aDecoder: NSCoder)
{
constant = "hi"
super.init(coder: aDecoder)
setup()
}
override init() {
constant = "hi"
super.init()
setup()
}
override init(size: CGSize) {
constant = "hi"
super.init(size: size)
setup()
}


Related Topics



Leave a reply



Submit