How to create starting screen in SpriteKit with swift - ios

In my game right now I've got a GameScene.swift and a GameOverScene.swift. When the game loads, GameScene.swift shows up and the game plays great. However, now that I'm done with the gameplay, how can I add a start screen that displays when the app opens?

To create the scene that runs when your app first opens, you will have to make some adjustments to the game's view controller. First change
let scene = archiver.decodeObjectForKey(NSKeyedArchiveRootObjectKey) as! GameScene
to
let scene = archiver.decodeObjectForKey(NSKeyedArchiveRootObjectKey) as! sceneName
and this line in didMoveToView
if let scene = GameScene.unarchiveFromFile("GameScene") as? GameScene {
to
if let scene = GameScene.unarchiveFromFile("GameScene") as? sceneName {
This will change the opening scene from GameScene to sceneName, or whatever you called your scene. Also, you must declare you scene like this: class sceneName:SKScene {...}. You can create a new .swift file (cmd + n) to score this class in for easy file management or you can put it in the GameScene file. Happy coding.

Related

Scene transition troubleshoot in spritekit in swift

I'm Trying to make a Start Scene Where you press a "Start" Button, and it goes to the main game scene. Here's the code:
if startBTN.containsPoint(location) {
let gameSceneTemp = GameScene(fileNamed: "GameScene")
self.scene?.view?.presentScene(gameSceneTemp, transition: SKTransition.fadeWithDuration(0.01))
}
But for some reason, whenever the scene loads up, it displays a squished-like scene in the GameScene. Can anyone help solve this problem by displaying a normal size (portarit) scene? Here's the Screen shots between the expected and actual scene:
The Expected Scene
The Actual Scene (The Problem)
It turns out, I didn't set the scene mode. I looked this problem up and I finally found the solution. Here's the code:
if startBTN.containsPoint(location) {
var gameScene = GameScene(size: self.size)
var transition = SKTransition.fadeWithDuration(0.8)
gameScene.scaleMode = SKSceneScaleMode.AspectFill
self.scene!.view?.presentScene(gameScene, transition: transition)
}
I had put the gamescene file and transition, but didn't add the scalemode to it.

SceneKit load node with animation from separate scn file

I have a view that creates SCNView dynamically. It's scene is empty, but when I press a button I would like to add a node from separate scn file. This file contains animation, and I would like it to animate in main scene. The problem is that after adding object to the scene it's not animating. When I use this file as SCNView scene it works. isPlaying and loops are enabled. What else do I need to do to import such node with animation? Sample code below:
override func viewDidLoad() {
super.viewDidLoad()
let scene = SCNScene()
let sceneView = SCNView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
sceneView.scene = scene
sceneView.loops = true
sceneView.isPlaying = true
sceneView.autoenablesDefaultLighting = true
view.addSubview(sceneView)
let subNodeScene = SCNScene(named: "Serah_Animated.scn")!
let serah = subNodeScene.rootNode.childNode(withName: "main", recursively: false)!
scene.rootNode.addChildNode(serah)
}
You need to fetch the animation from your scene Serah_Animated.scn, which will be a CAAnimation object. You then add that animation object to the rootNode of your main scene.
let animScene = SCNSceneSource(url:<<URL to your scene file", options:<<Scene Loading Options>>)
let animation:CAAnimation = animScene.entryWithIdentifier(<<animID>>, withClass:CAAnimation.self)
You can find the animID from the .scn file using scene editor in Xcode, as shown below.
Now you can add the animation object to your root node.
scene.rootNode.addAnimation(animation, forKey:<<animID>>)
Note that we are reusing animID, that will allow you to also remove the animation from the node.
scene.rootNode.removeAnimation(forKey:<<animId>>)
My solution above assumes your animation is a single animation. If you see a bunch of animations, you need to add all the animation nodes. In my workflow, I have files in Blender which I export to Collada format and then use the Automated Collada Converter to ensure I have single animation nodes.
Related SO answer
You can also fetch the animID programmatically using entriesWithIdentifiersOfClass(CAAnimation.self), useful when you have a bunch of animations instead of a single animation as above or if you just want to add the animation without bothering about the animID before hand.
Apple Sample Code for scene kit animations, note the sample code is in ObjC but translation to Swift should be straight forward.
All you need is retrieving animations:
[childNode enumerateChildNodesUsingBlock:^(SCNNode *child, BOOL *stop) {
for(NSString *key in child.animationKeys) { // for every animation key
CAAnimation *animation = [child animationForKey:key]; // get the animation
animation.usesSceneTimeBase = NO; // make it system time based
animation.repeatCount = FLT_MAX; // make it repeat forever
[child addAnimation:animation forKey:key]; // animations are copied upon addition, so we have to replace the previous animation
}
}];

Swift SpriteKit Delegate Pattern

I have been trying to learn how to use delegates recently and actually seem to understand it for the most part. However I have one problem.
I have 1 GameViewController, 1 StartScene and 1 MenuScene
In my GameViewController I have 2 methods that I would like to get called from MenuScene. So far I have been using NSNotification, which works fine but I am trying to use delegates.
So I have set up a protocol in MenuScene
protocol MenuSceneDelegate {
func gameOver()
func showGameCenter()
}
I than referenced it like so
var menuSceneDelegate: MenuSceneDelegate?
In GameViewController I added the MenuSceneDelegate at the top. All is very standard so far. However the main problem I have is that when I set the delegate in GameViewController like so
let skView = view as! SKView!
var scene = StartScene(size: skView.bounds.size)
skView.ignoresSiblingOrder = true
scene.scaleMode = .ResizeFill
skView.presentScene(scene)
scene.menuSceneDelegate = self //Sets delegate to StartScene not MenuScene
it only applies to the StartScene. How can I set the GameViewController delegate from StartScene to MenuScene. Everything works fine if I would first present the MenuScene. However I present StartScene first and therefore I am trying to understand how I set the delegate to MenuScene.
I tried something like this below but it doesnt work and just doesnt seem right
var menuScene = MenuScene(size: skView.bounds.size)
menuScene.menuSceneDelegate = self
I would appreciate any help or support. Thank you very much
Basically the solution is to set the delegate when I change from start scene to game scene, not in the beginning.

Sprites disappears sometimes [Sprite Kit]

Main menu looks like this.
When i press start code below changes the scene.
let newScene = LevelScene(size: self.scene!.size)
let transition = SKTransition.revealWithDirection(SKTransitionDirection.Up, duration: 1)
newScene.scaleMode = SKSceneScaleMode.AspectFill
self.scene!.view!.presentScene(newScene, transition: nil)
And after I return to the main menu it looks like this
or this
So, as you can see, sprites just disappears. I can't come up with a reason for this to happen.
Are you doing,
self.addChild(...)
self.addChild(...)
in your didMoveToView method?
Another possible problem might be that you are setting the zPosition of the node to less than your background, and / or other nodes.
I had the same problem with sprites disappearing and after changing the zPositions of all my sprites and background I still wasn't able to solve it.
I ended up just redeclaring the scene inside my restartButton:
var scene = SKScene(fileNamed: "GameScene")
scene?.scaleMode = .aspectFill
view!.presentScene(scene)
And that worked for me.

More Sprite Kit Game modes

I have a small game and I wish to present, in the menu, 2 game modes:
I have the first up and running from my original sprite kit scene and, in order to build my second one, I added another view to the storyboard, created another scene, linked them up just like the originals:
// Configure the view.
SKView * skView = (SKView *)self.view;
skView.showsFPS = NO;
skView.showsNodeCount = NO;
skView.multipleTouchEnabled = YES;
// Create and configure the scene.
SKScene * scene = [MyScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
and linked it to another button in my menu. The problem was, whenever i would press the button to go to the second game mode I would get a SIGABRT Thread 1 error. I made sure everything I linked was declared and valid and still got the error. I then removed the second SKScene (MyScene) and the view was loaded with no problem... just no content.
Is there a specific way I must proceed in order to have another View linked to a SpriteKit game?

Resources