SpriteKit - didMovetoView is not called - ios

This is my code for the view controller
import UIKit
import SpriteKit
import GameplayKit
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
// Load the SKScene from 'GameScene.sks'
if let scene = SKScene(fileNamed: "GameScene") {
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill
// Present the scene
view.presentScene(scene)
}
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
}
}
And this is my code for the GameScene
import SpriteKit
import GameplayKit
class GameScene: SKScene {
override func didMove(to view: SKView) {
print("gets called")
}
But for some reasons, in the debug area, it didn't print "gets called", which indicates that didMove didn't even get called. What's happening here? Did I miss anything?

The iOS 9 way
In your GameViewController try to directly present your GameScene instead of a generic SKScene.
if let scene = GameScene(fileNamed: "GameScene") {
...
Remember "fileNamed" is not the name of the .swift file, its the name of the .sks file which is used for the xCode level editor.
The new iOS 10 way
It seems Apple now prefers to pass a generic SKScene like you are trying.
if let scene = SKScene(fileNamed: "GameScene") { ... }
To make it work go to the relevant .sks file and go to the inspector on the right. Click the second last item (custom class) and enter the name of the .swift file into the custom class field.
Hope this helps.

This could happen because you don't have the related SKS (GameScene.sks in your case) file reference to your project, check if you have added it or removed/renamed due to mistake.

I finally sort that out.
My project name contains a period at the end. Like the name "XXXX.". After several experimentations, I discovered that I can simply solve the problem by removing the period.

My suggestion:
use
override func didMoveToView(view: SKView)
instead of
override func didMove(to view: SKView)
Maybe a naming inconsistency in the documentation/API...

I second what Tom Xue said as someone who spent way too long looking for the answer to this. I had a hyphen in my app name and that seems to have been causing the problem. When I renamed my project, the scene was presented as it should have been.

Related

Detect a Tap within the first Scene : SpriteKit Swift iOS, having small problem

so I have a menu screen in my app. Swift, SpriteKit, iOS 7-10,11,12,13..
All I want is a user to tap the button on my screen, and have it move them to another screen. This works in other references in my code. However All I did was change the first loading scene in the GameViewController to my own swift file, and this is how the code looks:
import Foundation
import SpriteKit
import GameplayKit
import UIKit
class FrontMenu : SKScene {
var play = SKSpriteNode(imageNamed: "pbut")
var credit = SKSpriteNode()
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
let node : SKNode = self.atPoint(location)
if node.name == "play" {
print("play tapped.")
// this is where I would have placed the transition, but this did not work.
}
else if node.name == "cred" {
NSLog("credits tapped")
}
if location.x <= -90 && location.y >= -160 {
NSLog("Area hit for play")
// This area is still not detected within the app, and there is no button function.
let gameScene = GameScene(fileNamed: "GameScene")
gameScene?.scaleMode = .aspectFill
self.view?.presentScene(gameScene!, transition: SKTransition.fade(withDuration: 0.86))
Basically that does that. You can see where I implemented the transition. Am I missing an import? Am I missing something to change to the overall Plist file? or Maybe something else within GameViewController.swift, I changed the first loading swift file, so that it does load this code first in the app. However it does not detect the touches.
Thank you for your help!
It looks like you are missing code that would set the name for your node. Make sure that in your didMove function that you are setting the name of the node and adding it to the scene.
//inside scene
override func didMove(to view: SKView) {
play.name = "play"
self.addChild(play)
}
The other thing you have to make sure of is that you created a SpriteKit scene file in your project and set the custom class to be FrontMenu
As for switching the file in your GameViewController, you should just be using the name of the file and not the file extension for fileNamed::
//inside GameViewController
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
// Load the SKScene from 'MneuScene.sks'
if let scene = SKScene(fileNamed: "MenuScene") {
// Set the scale mode to scale to fit the window
scene.scaleMode = .resizeFill
// Present the scene
view.presentScene(scene)
}
}
}

SpriteKit Example without Storyboard

I want to write the iOS Game Example that uses SpritKit in Swift, which is provided with Xcode only in code. That means I don’t want to use the GameScene.sks, actions.sks and the main.storyboard. I know how to write it without storyboard, but I can’t get it working without the .sks files. Can you say what I must change or can you provide me with a full project?
You will first need to have a View Controller. You can adjust the properties how you would like them. Here is mine:
import UIKit
import SpriteKit
class GameViewController: UIViewController {
// MARK: View Controller overrides
override func viewDidLoad() {
super.viewDidLoad()
view = SKView(frame: view.bounds)
if let view = self.view as! SKView? {
// Initialise the scene
let scene = GameScene(size: view.bounds.size) // <-- IMPORTANT: Initialise your first scene (as you have no .sks)
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill
// Present the scene
view.presentScene(scene)
// Scene properties
view.showsPhysics = false
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
}
}
}
Then, you create a class for your first scene. Mine is called GameScene which was initialised in the view controller. Make sure this is a subclass of SKScene. It will look something like this:
import SpriteKit
class GameScene: SKScene {
/* All Scene logic (which you could extend to multiple files) */
}
If you have any questions, let me know :)

Why can't I set SKScene(fileNamed:) in GameViewController?

The relevant code is copied below and I also put a simple test project on Github to demonstrate this situation:
https://github.com/prinomen/viewPresentSceneTest
I have a GameViewController and a GameScene class. I try to set the scene with SKScene(fileNamed: "GameScene") but that call is not working because the scene does not appear and the print statement after that line is not being called.
I know I could use a different way to set the scene, like this:
let scene = GameScene()
But I'm trying to understand SpriteKit and it bothers me that the code below does not work. In another project I was able to successfully set the scene using SKScene(fileNamed: "GameScene") like in the code below.
Does anyone know why it is not working in this project?
GameViewController.swift
import SpriteKit
class GameViewController: UIViewController {
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
if let view = self.view as! SKView? {
// Load the SKScene from 'GameScene.sks'
if let scene = SKScene(fileNamed: "GameScene") {
print("SKScene was set")
// Set the scale mode fit the window:
scene.scaleMode = .aspectFill
// Size our scene to fit the view exactly:
scene.size = view.bounds.size
// Show the new scene:
view.presentScene(scene)
}
}
}
}
GameScene.swift
import SpriteKit
class GameScene: SKScene {
override func didMove(to view: SKView) {
self.anchorPoint = CGPoint(x: 0.5, y: 0.5)
let logoText = SKLabelNode(fontNamed: "AvenirNext-Heavy")
logoText.text = "Game Scene"
logoText.position = CGPoint(x: 0, y: 100)
logoText.fontSize = 60
self.addChild(logoText)
}
}
I believe you need an .sks file to load scenes like that. You probably deleted it from this project, but still kept it around in the other one.
Here's what the documentation says:
The name of the file, without a file extension. The file must be in
the app’s main bundle and have a .sks filename extension.

Sprite-Kit Error

Im following a tutorial right now and Im getting an error that I do not know how to fix.
import UIKit
import SpriteKit
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let scene = StartGameScene(size: view.bounds.size)
let skView = view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
skView.ignoresSiblingOrder = true
scene.scaleMode = .ResizeFill
skView.presentScene(scene)
}
override func prefersStatusBarHidden() -> Bool {
return true
}
}
On line 8 the let scene = StartGameScene(size: view.bounds.size)
is giving me an error:
use of Unresolved Identifier ' StartGameScene'.
I have created a CocoaTouch class and named StartGameScene. I dont know what the issue is. How do I fix it?
StartGameScene would need to be a class declared like this:
class StartGameScene: SKScene {...}
Either StartGameScene is not declared as an SKScene or the class itself is not declared.
The cocoa touch class that you have created has to inherit from SKScene. SKScene is the class in which you define your game's scene. Hence your code should look like:
class StartGameScene: SKScene {
}
If you have already done this, then please make sure there isn't any typographic error.
just change StartGameScene to GameScene

SpriteKit Scenes

I'm trying to figure out how to add more scenes in SpriteKit. If I use the line generated from SpriteKit in the GameViewController
if let scene = GameScene.unarchiveFromFile("GameScene") as? GameScene
This works fine, however if I create a class that's also a of type SKScene and add it the the SKView.
let newscene = GameMenu()
skView.presentScene(newscene)
This will not work. It just displays a washed out gray color with only a fraction of the nodes but nothing actually presented. Is there something going wrong with the way SpriteKit uses unarchiveFromFile to create the scene. I'm also not even using the Storyboard or GameScene.sks. The entire game has been created programatically. One more Issue if I try to create another ViewController for a menu and use presentViewController. When it tries to run I also get an error that says "Could not cast value of type 'UIView' to 'SKView.'" I'm casting it with the same line similar to GameViewController.
let skView = self.view as! SKView
This is the line that it keeps breaking on. If anyone has any insight on how to fix this problem that would be greatly appreciated.
Here is how I normally make a scene:
Go to File -> New -> File...
Click Cocoa Class, click next
Name it whatever you want, make it a subclass of SKScene, choose swift
In the new class, make it look like this:
import SpriteKit
class GameScene: SKScene {
override init(size: CGSize) {
super.init(size: size)
//Other init code
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
//Other functions like override func touchesBegan, update, etc. Whatever you want
}
If you want to display the scene first, GameViewController, in viewDidLoad you would type:
let scene = GameScene(size: skView.bounds.size)
skView.presentScene(scene)
(skView should be made for you already, but if its not , its: let skView = self.view as! SKView, and put that before all the let scene = GameScene... etc and stuff in viewDidLoad.
Then if you wanted to present the scene from a different SKScene, and not from the view controller, then do:
let scene = GameScene(size: self.frame.size)
self.view?.presentScene(scene)
If you're constructing a scene programmatically, don't try to unit hive it from a file (that probably stores a different scene). Use its initializer instead: e.g. GameMenu() or GameMenu(size: whateverSize) or a custom initializer you've defined.

Resources