Swift: Problems with loading SKScenes - ios

I'm have a game, and I'm trying to load a scene other than GameScene. That scene is called MenuScene. I have both a .sks file and .swift file for MenuScene, both called MenuScene. Running the following code in GameViewController, I can at least load MenuScene.sks
if let view = self.view as! SKView? {
if let scene = SKScene(fileNamed: "MenuScene") {
scene.scaleMode = .aspectFill
view.presentScene(scene)
}
view.ignoresSiblingOrder = true
view.showsFPS = false
view.showsNodeCount = false
}
I don't think that MenuScene.swift is being accessed though. I know that didMove(to view: ) isn't getting called, and I thought that when an .sks file loads, the corresponding swift file gets run too, but that appears to not be the case. I have code in MenuScene.swift that I need to be run, but I can't figure out why it's not being run. Help.

The problem here is that, in Xcode, you have to explicitly connect MenuScene.sks to MenuScene.swift
To do this, open MenuScene and go over to the right to the menu. Click on the Custom Class Inspector tab. Then you'll have to enter MenuScene into the Custom Class form.
That will connect the two files, so that when you present the scene, Xcode knows what to open.

Related

How can you connect a swift file with an SKscene?

I looked through all posts, WWDC talks and youtube videos, but I still can't figure out how to have multiple SKscenes for different levels and connecting them with swift files in a Game using Spritekit. I want to have a main level board and I managed to open a new scene if you press a SKSpriteNode, but how can I implement game logic to this specific SKScene?
Apologies in advance if it is a silly question, I've been spending ages on it.
You can do it like this:
1) Create .swift file and make a subclass of a SKScene
Go to :
File menu -> New File -> Source -> Swift file
and make subclass of a SKScene
class MenuScene:SKScene {}
2) Create .sks file
Then go to
File menu -> New File -> Resource -> SpriteKit Scene
and make a MenuScene.sks (name it MenuScene without the actual extension).
Repeat this steps for each scene you want to have.
Then to load and start your initial scene. Do this inside your GameViewController.swift:
if let scene = GameScene(fileNamed:"GameScene") {
let skView = self.view as! SKView
//setup your scene here
skView.presentScene(scene)
}
To make a transition to other scene (lets assume that you are in the MenuScene currently) you should do something like this:
if let nextScene = GameScene(fileNamed: "GameScene"){
nextScene.scaleMode = self.scaleMode
let transition = SKTransition.fadeWithDuration(1)
view?.presentScene(nextScene, transition: transition)
}

How to create more SKScene in addition to GameScene

I tried to create a new subclass of SKScene "MainScene" like the one apple created the GameScene.
I want to create more scene in addition to my "GameScene" but its not working.
Below is my subclass code.
MainScene :
import SpriteKit
#if !os(iOS)
import AppKit
#endif
class MainScene : SKScene {
override func didMoveToView(view: SKView) {
backgroundColor = UIColor.blueColor()
}
}
MainSceneViewController :
import UIKit
import SpriteKit
class MainViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let scene = MainScene(fileNamed:"MainScene") {
// Configure the view.
let skView = self.view as! SKView
//skView.showsFPS = true
//skView.showsNodeCount = true
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = true
skView.showsPhysics = true
/* Set the scale mode to scale to fit the window */
scene.scaleMode = .AspectFill
skView.presentScene(scene)
}
}
Error : "Could not cast value of type 'UIView' (0x1097f2b20) to 'SKView' (0x108a4cad0)."
When creating a new scene, you need to actually create a new scene file, not just the code behind file.
To create new scene files, go to file, New, File, then in your sections go to iOS, SpriteKit Scene. This will create the sks file you need.
edit:
In the case you are getting the error Could not cast value of type 'UIView' to 'SKView', this is due to the fact that in your story board, your ViewControllers main view does not have a custom class of SKView. In your storyboard file, open up your view controller, click the view for this controller, make sure the right panel is visible, and select the identity inspector tab (It is probably the 3rd from left, looks like a flag or an envelope with a window). Under Custom Class, look for the class text box, and put in SKView
To create more SKScene in addition to GameScene
Go to New File
Select Coca Touch Class
Click on Next
SubClass : Type Manually SkScene
create
import SpriteKit

Adding a screen before GameScene.swift in SpriteKit

I'm making a game in XCode using Swift and I want to add a starting screen before the actual game. I don't want just an image that fades out, I want a screen with "play", "select character", and some buttons. I don't know if i should add a new swift file, add a sks file, edit the GameScene.swift file? I'm just starting to develop in SpriteKit and it would be great if you could explain me how to do this properly. Thanks.
Follow this Step by step and it should work:
Open up your Interface Builder (main.storyboard) and add a UIViewController.
Select the new UIViewController, go to Editor > Embed In > UINavigationController
a. To remove the UINavBar for your game scene you'll be able to do this using the property navigationBarHidden in the Game Scene View Controller
Add the UIButtons and/or other controls of your choice to your new View Controller
Left Click (ctrl) and drag the PLAY UIControl to the View Controller displaying your Game Scene.
Connect the other UIControls after adding other View Controllers that are associated with their UIControl counterpart. (see below)
If you've only ever programmed using the SpriteKit Template file, I would recommend looking over this Apple Documentation
~ MORE Details ~
Having successfully added your Start Screen, or your Root View Controller, add one ViewController for each page, or screen, that you'll need the Start Screen to display, by dragging one at a time into the Storyboard file.
Having all the Screens you'll need represented by the View Controllers within your main.storyboard file, the next step is Control Clicking from each UIButton on your "Start Screen" to the ViewController that will display its target screen.
You can just create new sprite kit scene and new swift file,
then put class of your swift file into Custom Class inspector in the
gamescene.sks so it will work just like default GameScene.
then initialise your menu scene in viewDidLoad instead of original GameScene
if let menu = SKScene(fileNamed: "MainMenu") {
menu.scaleMode = .aspectFill
view.presentScene(menu)
}
You can switch to your original scene like this(for example):
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let posistion = touch.location(in: self)
let node = self.atPoint(posistion)
if node == yourNode {
if let originalScene = SKScene(fileNamed: "GameScene") {
originalScene.scaleMode = .aspectFill
view?.presentScene(originalScene)
}
}
}
}

How do you call a function defined in another class?

I've created a SpriteKit project and defined a function in the GameScene.swift file. Said function creates a SKSpriteNode and has no problem running when called within it's class.
func generateShip() {
self.removeAllChildren()
let SKSprite1 = SKSpriteNode(imageNamed: "Spaceship")
SKSprite1.size = CGSize(width: CGFloat(arc4random_uniform(UInt32(200))), height: CGFloat(arc4random_uniform(UInt32(200))))
SKSprite1.position = CGPoint(x: self.size.width / 2, y: self.size.height / 2)
self.addChild(SKSprite1)
}
//if I called it here with touchesBegan, it worked.
Now, in my ViewController, I created a simple button and connected it to its swift file. I did a few things before the following code, but this is the part I'm having trouble with.
let gameScene = GameScene()
#IBAction func newShip(sender: AnyObject) {
gameScene.generateShip() // am I doing this wrong?
}
When I run the app, and click the button, nothing happens. What do I need to change/ do to make function.... well ... function?
Links: Full Code , Iphone
The problem is in this code:
let gameScene = GameScene()
override func viewDidLoad() {
super.viewDidLoad()
let skView = self.view as! SKView
skView.presentScene(GameScene(fileNamed: "GameScene"))
}
Your gameScene property isn't the same as the scene you presented. Those are two separate objects. You need to do two things.
Change your gameScene declaration to be like the new one you created in your presenting code. Like so:
let gameScene = GameScene(fileNamed: "GameScene")
In viewDidLoad, present that GameScene object instead of making a new one, like this:
skView.presentScene(gameScene)
This way you create one GameScene object, present it, and call generateShip() on the same object.
In theory Swift should be able to link all the files automatically that are inside of your project, so your code should be able to work on its own. However, the only issue that might arise is because you are now relying on the StoryBoard as well, so you have to make sure thats linked correctly.
Make sure that its linked correctly.
Check out this question for more information on linking with Swift.
EDIT: Also, look at your code. You are calling the function for the space ship on the class itself and not on an instance of it, so thats why its probably not working. You need to first initialize a gameScene and then use that scene to call a method. I think it might be a lot more work so my advice would be to keep everything inside of your gameScene class and create a spriteNode button inside of there.
Your code seems fine to me.
If there was any 'access' problem with code from an unknown class / module etc. you'd get a compiler warning about it. This seems not to be the case.
My guess: your button is not wired up correctly!
Doublecheck that the #IBAction func newShip(sender: AnyObject) really gets called when you press the button: set a breakpoint inside of the newShip function.
Edit: And if it does stop there: step into the function using the debugger.
You are incorrectly using two different instances of GameScene in your view controller! One is added to the view hierarchy, and the OTHER instance is called when the button is tapped.
This can not be seen from the code in the original question, but from the code you provided in a comment: screenshot of full code
In your view controller your are first creating a GameScene with:
let gameScene = GameScene()
but then you are creating and adding a second instance of GameScene to the view hierarchy with:
skView.presentScene(GameScene(fileNamed:"GameScene"))
and your button action calls the generateShip() method on the first object stored in gameScene, that has not been presented by the SKView.
So the solution is to change the above code to:
let gameScene = GameScene(fileNamed:"GameScene"))
and later:
skView.presentScene(gameScene)

How to add a sprite from another .swift file?

I have a project I've been working on for some time. I am using Sprite-Kit but now want to be able to add a child node from a swift file that is different from the GameScene.swift file.
Some of main code from the view controller that loads the GameScene is shown here:
let skView:SKView = SKView()
let theScene:SKScene = SKScene()
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let theScene = GameScene.unarchiveFromFile("GameScene") as? GameScene {
// Configure the view.
let skView = self.view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = true
/* Set the scale mode to scale to fit the window */
theScene.scaleMode = .ResizeFill //.AspectFill
var customSceneSize = CGSizeMake(2560, 1600)
theScene.size = customSceneSize
skView.presentScene(theScene)
makeFakeStuff() // prepares some sample data
}
}
Usually I add sprites in the GameScene.swift file using "self.addChild". That won't work from another .swift file, so I have tried:
theScene.addChild(flyingCell)
and I tried:
skView.scene?.addChild(flyingCell)
These execute without error, but nothing shows on the screen. When I try to otherwise use the identical sprite code and put it in the GameScene.swift file and use "self.addChild" it draws it, so the sprite code (not shown) seems fine (position, zPosition, etc). I also made "flyingCell" a global variable to see if that would help ... nope. Any ideas?
I had 2 things wrong in my code.
The first is visible in my question: I should have declared "theScene" using "var" and not "let"
The second problem was in my gamescene, I needed to put "theScene = self"
Apple DTS helped me solve this problem.

Resources