Adding a screen before GameScene.swift in SpriteKit - ios

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

Related

SKScene not loaded when add GKComponent to GameScene.sks

I am currently creating a 2D game with Swift SpriteKit and GameplayKit.
I have a GameScene.sks file and a GameScene.swift file that is of type SKScene.
Now I wanted to add a Component of type GKComponent. I created my component and added it to one of my SKSpriteNodes in GameScene.sks
However after adding the Component to the SpriteNode in the Scene Editors Inspector the Scene is no longer loaded and the app shows only a grey screen.
Is this a known issue in XCode?
Is there a way of bypassing this issue?
I have not uploaded any example code. The issue is reproducable by any new XCode Project (ios / Game) that supports SpriteKit and GameplayKit.
Just add a class that is derived from GKComponent and add the class to the given helloLabel in the Scene Editor.
This is how the GameScene is loaded:
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let scene = GKScene(fileNamed: "GameScene") {
if let sceneNode = scene.rootNode as! GameScene? {
// This gets only executed when I remove the Component from the SKSpriteNode in the Scene Editor.
}
}
...

Swift: How to handle view controllers for my game

i have a general question about view controllers and how to handle them in a clean way when i develop a SpriteKit based game.
What i did so far:
Use storyboard only for defining view controllers
SKScene's are presented in each view controller (Home, LevelSelection, Game) by presentScene
in each view controller i call performSegueWithIdentifier with the identifier i defined in the storyboard between the view controllers
all the content i show programmatically using SKSpritenode etc. on the SKScene's
on the storyboard i only have view controllers with segue relations and identifiers defined
all the stuff i do in viewDidDisappear is because it seems to be the only way to get my SKScene deinited correctly
My problems are:
everytime i segue to another view, my memory raises, because the view controller is re-initialized, the old one keeps staying in the stack
it is not clear for me how to handle the segue's between the view controllers, on some tutorial pages i see people using the navigation controller, others are using strong references of some view controllers and using the singleton pattern for the view controller in order to decide either to init the view controller or just show it
my view controllers are not deiniting, i understand my home view can't because it is the initial one, but since ios is reiniting it anyways, why then not unloading it?
What is the correct way for a Swift based game using SpriteKit to handle the view controller? Below you can see my initial view controller (Home) showing an SKScene with a simple play button which calls the play() function to segue to the levelselection
import UIKit
import SpriteKit
class Home : UIViewController {
private var scene : HomeScene!
override func viewDidLoad() {
print(self)
super.viewDidLoad()
self.scene = HomeScene(size: view.bounds.size)
self.scene.scaleMode = .ResizeFill
let skView = view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
skView.ignoresSiblingOrder = true
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(play), name: Constants.Events.Home.play, object: nil)
skView.presentScene(self.scene)
}
override func viewDidDisappear(animated: Bool) {
super.viewDidDisappear(animated)
let v = view as! SKView
self.scene.dispose()
v.presentScene(nil)
NSNotificationCenter.defaultCenter().removeObserver(self)
self.scene = nil
self.view = nil
print("home did disappear")
}
func play() {
self.performSegueWithIdentifier("home_to_levelselection", sender: nil)
}
deinit {
print("Home_VC deinit")
}
}
Your way seems very complicated to essentially present 3 scenes. Its not what you are supposed to do for SpriteKit games, you only really need 1 view controller (GameViewController).
Load your first scene from GameViewController (e.g HomeScene) and nothing else.
Create your playButton and other UI directly in HomeScene. Use SpriteKit APIs for your UI (SKLabelNodes, SKNodes, SKSpriteNodes etc).
You should never really use UIKit (UIButtons, UILabels) in SpriteKit. There are some exceptions to this, like maybe using UICollectionViews for massive level select menus, but basic UI should be done with SpriteKit APIs.
There is plenty tutorials to google on how to create sprite kit buttons, how to use SKLabelNodes etc. Xcode has a SpriteKit level editor so you can do all that visually similar to storyboards.
Than from HomeScene transition to the LevelSelect Scene and than to the GameScene and vice versa. Its super easy to do.
/// Home Scene
class HomeScene: SKScene {
...
func loadLevelSelectScene() {
// Way 1
// code only, no XCode/SpriteKit visual level editor used
let scene = LevelSelectScene(size: self.size) // same size as current scene
// Way 2
// with xCode/SpriteKit visual level editor
// fileNamed is the LevelSelectScene.sks you need to create that goes with your LevelSelectScene class.
guard let scene = LevelSelectScene(fileNamed: "LevelSelectScene") else { return }
let transition = SKTransition.SomeTransitionYouLike
view?.presentScene(scene, withTransition: transition)
}
}
/// Level Select Scene
class LevelSelectScene: SKScene {
....
func loadGameScene() {
// Way 1
// code only, no XCode/SpriteKit visual level editor used
let scene = GameScene(size: self.size) // same size as current scene
// Way 2
// with xCode/SpriteKit visual level editor
// fileNamed is the GameScene.sks you need to create that goes with your GameScene class.
guard let scene = GameScene(fileNamed: "GameScene") else { return }
let transition = SKTransition.SomeTransitionYouLike
view?.presentScene(scene, withTransition: transition)
}
}
/// Game Scene
class GameScene: SKScene {
....
}
I strongly recommend you scratch your storyboard and ViewController approach, and just use different SKScenes and 1 GameViewController.
Hope this helps
Go to the segues and use Show Detail Segues anywhere that you don't want the previous view controller to be kept in the stack. Keep in mind that you will have to reinitialize everything appropriately in those view controllers whenever you do return to them.
If you pay attention, viewDidAppear loads every time that you see the view appear, while with your current setup, viewDidLoad would only be called initially and if you returned to the viewController, only viewDidAppear would be called.
When you use a segue to transition out of a viewController, prepareForSegue is called, but deinit() is only called when you use a show detail segue (or custom segue with those specific properties about it), because the view, like you said, is loaded into memory so it can be retrieved easier.

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

Showing keyboard on SKScene and performing action on a sprite node based on key tapped

I am trying to learn SpriteKit and play with some simple sample apps.
Currently I am trying to achieve below things:
Show keyboard over SKScene
If user taps 'A', perform some action on a sprite node, if user taps 'B' perform some other action on other sprite nodes
To achieve 1st requirement I tried below steps:
Step 1: In GameViewController.swift, added a reference to the view.
var keyView: KeyboardDummyView?
Step 2: In viewDidLoad(), created the view, assigned it to the ivar, and added it to the controller's view. Also assigned "self" to a backreference ivar in GameScene.
override func viewDidLoad() {
super.viewDidLoad()
if let scene = GameScene.unarchiveFromFile("GameScene") as? GameScene {
// So scene can forward touch event back here.
scene.gvc = self
// Other config
keyView = KeyboardDummyView(frame: self.view.frame)
self.view.addSubview(keyView!)
}
}
Step 3: Added a function to handle a tap/touch.
func handleTap() {
// Show the keyboard
keyView!.becomeFirstResponder()
}
Step 4: In GameScene.swift added the reference to the controller.
var gvc: GameViewController?
Step 5: In touchesBegan handled tap.
gvc!.handleTap()
But for some reasons it is not showing the keyboard when screen is tapped :(
Here is the code base: KeyboardOverSKScene
Please suggest if I am doing any thing wrong?
Note: I am trying this in Xcode 6.0.1

Resources