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

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.

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)
}
}
}

Multiple Views In Xcode Swift Playground

I am creating a swift playground I want to create multiple views, first an introduction screen then a SpriteKit game then a conclusion screen.
How can I change between views in Xcode playground.
Here is a picture that show first and 2 and 3 view in sources that I want to display by order
How can I change views between these 3 files and there is no storyboard. What code should I put in MyPlayground.
In your playground file, you create your scene view like this:
let sceneView = SKView(frame: CGRect(x:0 , y:0, width: 640, height: 480))
let myScene = FirstView(fileNamed: "MyPlayground")
if let scene = myScene {
scene.scaleMode = .aspectFill
sceneView.presentScene(scene)
}
PlaygroundSupport.PlaygroundPage.current.liveView = sceneView
And in your First View file, create your FirstView class. Do not forget to put it as public:
import Foundation
import SpriteKit
public class FirstView: SKScene {
private var label : SKLabelNode!
open override func didMove(to view: SKView) {
// Get label node from scene and store it for use later
label = SKLabelNode(text: "first view")
label.position = view.center
addChild(label)
}
}

SpriteKit - didMovetoView is not called

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.

Adding a spark particle sprite inside a view controller

I created an .sks particle emitter based on the spark template.
My app is a normal app (not a game). When a user clicks a button, I have a new View controller that shows modally over fullscreen so that I can blur the background.
In this modal, I created a view and gave it a class of SCNView see image below:
How can I load the particle .sks file to do the animation on that viewController on the Particles view?
Update
How to load a SceneKit particle systems in view controller?
As mentioned by #mnuages, you can use .scnp file instead of .sks, which is a SceneKit Particle System.
So the steps are:
Create a SceneKit Particle System, I called it ConfettiSceneKitParticleSystem.scnp
Then in your art-board, select the view and select the class SCNView for it like in the printscreen of the question
In your UIViewController:
class SomeVC: UIViewController {
#IBOutlet weak var particles: SCNView!
override func viewDidLoad() {
super.viewDidLoad()
let scene = SCNScene()
let particlesNode = SCNNode()
let particleSystem = SCNParticleSystem(named: "ConfettiSceneKitParticleSystem", inDirectory: "")
particlesNode.addParticleSystem(particleSystem!)
scene.rootNode.addChildNode(particlesNode)
particles.scene = scene
}
}
Et Voila...you have you animation :)
.sks files are SpriteKit particle systems. You can also create SceneKit particle systems in Xcode, they are .scnp files.
A .scnp file is basically an archived SCNParticleSystem that you can load with NSKeyedUnarchiver and add to your scene using -addParticleSystem:withTransform:.
It might be easier to create a SpriteKit Particle File (which is what you did). You can add it to your main view in your UIViewController.
Add this somewhere:
extension SKView {
convenience init(withEmitter name: String) {
self.init()
self.frame = UIScreen.main.bounds
backgroundColor = .clear
let scene = SKScene(size: self.frame.size)
scene.backgroundColor = .clear
guard let emitter = SKEmitterNode(fileNamed: name + ".sks") else { return }
emitter.name = name
emitter.position = CGPoint(x: self.frame.size.width / 2, y: self.frame.size.height / 2)
scene.addChild(emitter)
presentScene(scene)
}
}
To use:
override func viewWillAppear(_ animated: Bool) {
view.addSubview(SKView(withEmitter: "ParticleFileName"))
}

Gaming SKScene transitions Swift

I'm new to Swift and have no Objective-c experience. I already have a working Swift game that I programed using SpriteKit and a not functional Menu also in SpriteKit. Im trying to figure out how to integrate this two but I can't find information on how to handle SKScene (I asume).
Currently if I Run the file it goes straight to the game and I want to first launch the menu and when a button is pressed to jump to the game. How or where can I learn to do this?
My two file clases are as follows:
class GameScene: SKScene, SKPhysicsContactDelegate {
// handles the game
}
class Menu: SKScene {
//handles the menu
}
thank you
You should have ViewController.swift after you make standart SpriteKit application. Your game scene is created and displayed in this file. To first show the menu, it is necessary to replace the game scene creating to menu scene creating. And your game scene must be created on menu scene object. It may look something like this:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let scene = Menu(size: CGSize(width: 1024, height: 768))
let skView = self.view as SKView
skView.ignoresSiblingOrder = true
scene.scaleMode = .AspectFill
skView.presentScene(scene)
}
....
}
class Menu: SKScene {
...
func startPlayButtonPressEvent() {
let skView = self.view as SKView
skView.ignoresSiblingOrder = true
let scene = GameScene(size: skView.bounds.size)
scene.scaleMode = .AspectFill
skView.presentScene(scene)
}
...
}

Resources