Swift spritekit multiple scenes - ios

I am a beginner in swift, I have made a simple game and I wanted to add a menu scene.
This is what I have so far.
In menueScene.swift
import Foundation
import spritekit
class MenuScene: SKScene {
override func didMoveToView(view: SKView) {
/* Setup your scene here */
let Label = SKLabelNode(fontNamed:"Chalkduster")
Label.text = "Choose the Device";
Label.fontSize = 25;
Label.position = CGPoint(x:CGRectGetMidX(self.frame), y:665.523254394531);
self.addChild(Label)
let Label1 = SKLabelNode(fontNamed: "Chalkduster")
Label1.text = "light's";
Label1.fontSize = 20;
Label1.position = CGPointMake(401.463256835938,545.199401855469)
self.addChild(Label1)
}
}
and in GameViewController.swift
import UIKit
import SpriteKit
extension SKNode {
class func unarchiveFromFile(file : NSString) -> SKNode? {
if let path = NSBundle.mainBundle().pathForResource(file, ofType: "sks") {
var sceneData = NSData(contentsOfFile: path, options: .DataReadingMappedIfSafe, error: nil)!
var archiver = NSKeyedUnarchiver(forReadingWithData: sceneData)
archiver.setClass(self.classForKeyedUnarchiver(), forClassName: "SKScene")
let scene = archiver.decodeObjectForKey(NSKeyedArchiveRootObjectKey) as MenuScene
archiver.finishDecoding()
return scene
} else {
return nil
}
}
}
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let scene = MenuScene.unarchiveFromFile("MenuScene") as? MenuScene {
//if scene = MenuScene.unarchiveFromFile("MenuScene") as? MenuScene {
// 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 */
scene.scaleMode = .AspectFill
scene.size = skView.bounds.size
skView.presentScene(scene)
}
}
And this displays nothing in the iOS simulator and no errors. What am I doing wrong.

I think it will be much easier for you to use visual tools.
You can create new scene using File -> New file -> SprikeKitScene.
In this case you will have "MenuScene.sks" file.
You can drag and drop elements to this scene (labels, sprites etc).
All your logic you will put into "ManuScene.swift".
Code in your main ViewController to show your menu on a startup:
class YourViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let scene = MainMenuScene(fileNamed:"MenuScene") {
let skView = self.view as! SKView
skView.ignoresSiblingOrder = true
scene.scaleMode = .AspectFit
skView.presentScene(scene)
}
}
...
}
Later if you need to open your menu again from another scene, simply call this code:
let nextScene = GameScene(fileNamed: "ManuScene")!
nextScene.scaleMode = .AspectFit
scene?.view?.presentScene(nextScene)

Seems like the CGPoints you want for the Label.position are placed out of the view. This is because the x and y values are to big. I don't know why your values are this big, I assume you where working with an iPad as simulator device. Try replacing it with this:
override func didMoveToView(view: SKView) {
let Label = SKLabelNode(fontNamed:"Chalkduster")
Label.text = "Choose the Device";
Label.fontSize = 25;
Label.position = CGPoint(x:CGRectGetMidX(self.frame), y:20.0);
self.addChild(Label)
let Label1 = SKLabelNode(fontNamed: "Chalkduster")
Label1.text = "light's";
Label1.fontSize = 20;
Label1.position = CGPointMake(CGRectGetMidX(self.frame) ,300.0)
self.addChild(Label1)
}

Related

Swift: Load the SKScene from GameMenu.sks doesn't work

i have the problem, that the GameViewController doesn't load my GameMenu. If i simulate my app it only shows a grey screen with node:0 and the fps count.
Here the Code from GameViewController.swift:
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 = GameMenu(fileNamed: "GameMenu") {
// 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
}
}
I tried also the line:
if let scene = SKScene(fileNamed: "GameMenu")
but it changed nothing.
I also added the Custom Class "GameMenu" to the GameMenu.sks
I think the problem is this if let scene = SKScene(fileNamed: "GameMenu") line.
I have read a lot about this problem but i my case nothing was successful.
I also tried this:
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
// Load the SKScene from 'GameScene.sks'
if let gkScene = GKScene(fileNamed: "GameMenu.sks") {
if let skScene = gkScene.rootNode as? SKScene {
// Set the scale mode to scale to fit the window
skScene.scaleMode = .aspectFill
// Present the scene
view.presentScene(skScene)
}
}
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
}
}
but nothing happend.
You have to load it as GKScene from .sks file and get SKScene from its rootNode attribute.
if let gkScene = GKScene(fileNamed: "GameMenu") {
if let skScene = gkScene.rootNode as? SKScene {
// TODO
}
}

Cannot make app go to main menu (Swift 4 SpriteKit)

I am trying to direct the user to a main menu file as soon my game loads (made with Swift 4 SpriteKit). However, when I try to redirect the user to this .swift file (where a label should be displayed onto the users screen) the screen is simply blank except the for the node and FPS counter.
Here's my code in the MainMenuScene.swift file I created:
import Foundation
import SpriteKit
class MainMenu: SKScene {
override func didMove(to view: SKView) {
print("In scene")
let myLabel = SKLabelNode(fontNamed: "The Bold Font")
myLabel.fontColor = SKColor.blue
myLabel.text = "My Label"
myLabel.fontSize = 50
myLabel.position = CGPoint(x: 0, y: 0)
myLabel.zPosition = 1
self.addChild(myLabel)
}
}
Here's my code in the GameViewController.swift
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: "MainMenuScene") {
// 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
view.showsPhysics = true
}
}
override var shouldAutorotate: Bool {
return true
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if UIDevice.current.userInterfaceIdiom == .phone {
return .allButUpsideDown
} else {
return .all
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
override var prefersStatusBarHidden: Bool {
return true
}
}
I changed the
if let scene = SKScene(fileNamed: "GameScene")
to
if let scene = SKScene(fileNamed: "MainMenuScene")
That line of code should redirect the user to MainMenuScene.swift, but when I run the program the screen is simply blank.
Anyone know what im doing wrong?
Thanks!
Try using the code below after
super.viewDidLoad()
Also make sure that your Menu class is called "MainMenuScene" and that you changed the scene name to the same at MainMenuScene.sks
CODE:
if let scene = GKScene(fileNamed: "MainMenuScene") {
// Get the SKScene from the loaded GKScene
if let sceneNode = scene.rootNode as! MainMenuScene? {
scene.scaleMode = .aspectFill
// Present the scene
if let view = self.view as! SKView? {
view.presentScene(sceneNode)
view.ignoresSiblingOrder = true
//view.showsFPS = true
//view.showsNodeCount = true
}
}
}

Segue between SKScene and UIViewController

I'm writing simple math game with swift 3 and I have a problem with segues. I have two GameViewController's, oneUIViewController and one NavigationViewController.
I want to make two menus, one with game modes and one with difficulties, I want that the difficulties menu be interactive and have gravity so I decided to make it in SkScene. Everything works fine except segue between SkScene with dark screen and difficulties menu when user lost the game. I write a protocol which works when I'm going from main menu to second menu but when I'm going from SkScene with game it doesn't. I was trying to make a manual segue but protocol doesn't want to execute.
MyGVViewController code:
import UIKit
import SpriteKit
import GameplayKit
enum skad1 {
case game,menu
}
var skad = skad1.gra
class MyGVViewController: UIViewController, GameViewControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
// Load the SKScene from 'GameScene.sks'
if let scene = SKScene(fileNamed: "Menugame") {
let gameScene = scene as! MySKScene
gameScene.gameViewControllerDelegate = self
gameScene.scaleMode = .aspectFill
gameScene.size = view.bounds.size
// Present the scene
view.presentScene(gameScene)
}
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
}
}
override var shouldAutorotate: Bool {
return true
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if UIDevice.current.userInterfaceIdiom == .phone {
return .allButUpsideDown
} else {
return .all
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
override var prefersStatusBarHidden: Bool {
return true
}
func goback() {
print("goback executed")
let view = self.view as! SKView?
view?.presentScene(nil)
navigationController?.popViewController(animated: true)
}
func goback2() {
print("goback2 executed")
let view = self.view as! SKView?
view?.presentScene(nil)
self.performSegue(withIdentifier: "comeback", sender: nil)
}
}
My SkScene with difficulties menu code:
import GameKit
import SpriteKit
import CoreMotion
protocol GameViewControllerDelegate: class {
func goback()
func goback2()
}
class MySKScene: SKScene {
//Variables
var motionManager: CMMotionManager!
var ball = SKSpriteNode()
var ball1 = SKSpriteNode()
var ball2 = SKSpriteNode()
var ball3 = SKSpriteNode()
var ball4 = SKSpriteNode()
weak var gameViewControllerDelegate: GameViewControllerDelegate?
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
if ball.contains(location){
showgame(zakres: 200)
}else if ball1.contains(location){
showgame(zakres: 100)
}else if ball2.contains(location) {
showgame(zakres: 50)
}else if ball3.contains(location) {
showgame(zakres: 150)
}else if ball4.contains(location) {
if skad == .menu{
print("should execut goback")
self.gameViewControllerDelegate?.goback()
}else{
print("should execut goback2")
self.gameViewControllerDelegate?.goback2()
}
}
}
}
func showgame(zakres:Int) {
if let view = self.view {
range = zakres
// Load the SKScene from 'GameScene.sks'
if let scene = SKScene(fileNamed: "GameScene") {
// Set the scale mode to scale to fit the window
let gameScene = scene as! GameScene
gameScene.scaleMode = .aspectFill
// Present the scene
gameScene.size = view.bounds.size
view.presentScene(gameScene)
}
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
}
}
override func didMove(to view: SKView) {
ball = self.childNode(withName: "ball") as! SKSpriteNode
ball1 = self.childNode(withName: "ball1") as! SKSpriteNode
ball2 = self.childNode(withName: "ball2") as! SKSpriteNode
ball3 = self.childNode(withName: "ball3") as! SKSpriteNode
ball4 = self.childNode(withName: "ball4") as! SKSpriteNode
motionManager = CMMotionManager()
motionManager.startAccelerometerUpdates()
let border = SKPhysicsBody(edgeLoopFrom: self.frame)
border.friction = 0
border.restitution = 0
self.physicsBody = border
}
override func update(_ currentTime: TimeInterval) {
if let accelerometerData = motionManager.accelerometerData {
physicsWorld.gravity = CGVector(dx: accelerometerData.acceleration.x * 20, dy: accelerometerData.acceleration.y * 35)
}
}
}
PS.
I'm reading what I wrote and I have to correct it, in difficulties menu I have a button which execute protocol that hide SKScene and show main menu. It works only when I'm going from main menu but when segue is from game when user lost, protocol isn't executed

How do I create an outlet for skView?

I Have the same problem as here: SpriteKit GameScene function won't add SKSpriteNode after being called by button.
I Didn't understand the answer. How do I create an outlet for skView ?
Thank you very much for any clarification you could bring me !
Here is my code:
In my GameScene.swift
override func didMoveToView(view: SKView) {
loadMyView()
}
func loadMyView(){
currentScore = 0
loadSpecialView()
}
func loadSpecialView(){
Person = SKSpriteNode(imageNamed: "Person")
Person.size = CGSize(width:40, height: 7)
Person.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 2 + 120)
Person.zRotation = 3.14/2
Person.zPosition = 2.0
self.addChild(Person)
}
When the player dies, a Restart Button appears with the following code in my GameviewController.swift:
var currentGame: GameScene!
override func viewDidLoad() {
super.viewDidLoad()
currentGame = GameScene()
if let scene = GameScene(fileNamed:"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 */
scene.scaleMode = .ResizeFill
scene.viewController = self
skView.presentScene(scene)
}
}
#IBAction func restartGame(sender: UIButton) {
outBuy.hidden = true
outRestart.hidden = true
currentGame.loadMyView()
}
When I launch the simulator, all works well and the Person is added. When I press restart, the person doesn't appear. What happened ?
I found the solution ! Finally !
I changed currentGame = GameScene() to currentGame=scene and moved it just above skView.presentScene(scene)

restarting and presenting in GameScene

Hello my problem is that when I click on a button to restart my game it will restart, but then if I click on a button that transitions to the MainMenuViewController than the scene will freeze. The interesting thing is that if I restart the game and click on the segue button first it will work properly, but then if I click the restart button the game will then freeze. When clicking on the segue button and it crashes I get the error has no segue with identifier 'GameToMain' when it indeed does work the first time. When I click on the restart game it will just crash with no error. Here is the relevant code for this problem:
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let skView = view as! SKView
let scene = GameScene(size: skView.bounds.size)
skView.showsFPS = true
skView.showsNodeCount = true
skView.ignoresSiblingOrder = false
//skView.showsPhysics = true
scene.scaleMode = .AspectFill
skView.presentScene(scene)
scene.viewController = self
}
}
class GameScene: SKScene, SKPhysicsContactDelegate {
var viewController: GameViewController!
This is set up in a func that is called when the player loses:
let tryAgain = SKLabelNode(fontNamed: "Chalkduster")
tryAgain.text = "Try Again?"
tryAgain.color = SKColor.yellowColor()
tryAgain.name = "retryLabel"
tryAgain.fontSize = 28
tryAgain.position = CGPoint(x: size.width/2, y: size.height/2)
playerLayerNode.addChild(tryAgain)
let mainMenuTransition = SKLabelNode(fontNamed: "Chalkduster")
mainMenuTransition.text = "Main Menu"
mainMenuTransition.color = SKColor.yellowColor()
mainMenuTransition.name = "mainMenuTransitionSeque"
mainMenuTransition.fontSize = 20
mainMenuTransition.position = CGPoint(x: size.width/2, y: size.height/2 - 60)
playerLayerNode.addChild(mainMenuTransition)
This is how the labels register and react to being tapped
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in (touches ) {
let location = touch.locationInNode(self)
let node = self.nodeAtPoint(location)
if (node.name == "retryLabel") {
print("restart")
let gameScene = GameScene(size: self.size)
let transition = SKTransition.doorsCloseHorizontalWithDuration(0.5)
gameScene.scaleMode = SKSceneScaleMode.AspectFill
gameScene.viewController = GameViewController()
self.scene!.view?.presentScene(gameScene, transition: transition)
print("complete Reload")
}
if (node.name == "mainMenuTransitionSeque") {
print("go to main menu")
self.viewController!.performSegueWithIdentifier("GameToMain", sender: self)
print("complete2")
}
I solved the problem with the current code:
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let skView = view as! SKView
let scene = GameScene(size: skView.bounds.size)
//skView.showsFPS = true
//skView.showsNodeCount = true
skView.ignoresSiblingOrder = false
//skView.showsPhysics = true
scene.scaleMode = .AspectFill
scene.viewController = self
skView.presentScene(scene)
}
}
In GameScene
var viewController: GameViewController!
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let location = touch.locationInNode(self)
let node = self.nodeAtPoint(location)
if (node.name == "retryLabel") {
let skView = view as SKView!
let scene = GameScene(size: skView.bounds.size)
skView.ignoresSiblingOrder = false
scene.scaleMode = .AspectFill
scene.viewController = viewController.self
skView.presentScene(scene)
}
if (node.name == "mainMenuTransitionSeque") {
self.viewController.dismissViewControllerAnimated(false, completion: nil)
print("complete2")
}
}
}
}
So basically to restart the scene I copy and pasted the code from the GameViewController into GameScene so that it would restart the scene exactly, but the key was redeclaring the viewController variable. Then to get to the mainMenu I dismissed the view controller (GameScene) instead of creating a new segue so that I do not keep adding more and more scenes on top of each other.

Resources