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
I've added a "main" node like DragonNode and other node children of this
Now, the DragonNode is a custom class, set it in sks file:
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:
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
Swift - Get File Path of Currently Opened Document in Another Application
Why Can't I Mutate a Variable Initially Set to a Certain Parameter When the Func Was Called
Scngeometryelement Setup in Swift 3
For Loop for Dictionary Don't Follow It's Order in Swift
Physics Detecting Collision Multiple Times
New Firebase Retrieve Data and Put on the Tableview (Swift)
Arkit -Drop a Shadow of 3D Object on the Plane Surface
\N in the End of Line with Using Print
Change Time Interval in Skaction.Waitforduration() as Game Goes On
Is There a Preferred Technique to Prohibit Pasting into a Uitextfield
Google API - Invalid Credentials
How to Get Coreml in Pure Playground Files
How to Cast an Any Value with Nil in It to a Any
What's the Best Way to Iterate Over Results from an API, and Know When It's Finished
What Are the Advantages Swift Deprecates C-Style for Statement
Many Ways of Defining a Swift Dictionary
Label Disappear When Changing Font Size to 25 in Swift
What's the Best Way to Cut Swift String into 2-Letter-Strings