Scenes not deallocating - ios

I am creating a SpriteKit game and I am having a lot of trouble. The first screen is a menu, when you click the play button, the player is put into the game itself using the code:
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
for touch in touches {
let location:CGPoint = touch.locationInNode(self)
if self.nodeAtPoint(location).name == "play" {
playButton.fontColor = colorPressed
var scene = PlayScene(size: self.size)
let skView = self.view! as SKView
skView.ignoresSiblingOrder = true
skView.showsFPS = false
skView.showsNodeCount = false
scene.scaleMode = .AspectFill
gameStart(scene, skView: skView)
}
}
}
func gameStart(scene:SKScene, skView:SKView) {
let scale = SKAction.scaleTo(0.0, duration: 0.17)
about.runAction(scale, completion: {
self.scene?.removeAllChildren()
self.scene?.removeFromParent()
skView.presentScene(scene)
})
}
(PlayScene is the scene for where the player plays the game) This transition works fine. The player is able to play the game fine. Next, when the player loses the game, I go to a game over scene using this code:
func lineHitBadDot(dot: SKSpriteNode) {
var sceneGG = OverScene(size: self.size)
let skViewGG = self.view! as SKView
skViewGG.ignoresSiblingOrder = true
skViewGG.showsFPS = false
skViewGG.showsNodeCount = false
sceneGG.scaleMode = .AspectFill
let scale = SKAction.scaleTo(0.0, duration: 0.17)
scoreCounter.runAction(scale, completion: {
self.scene?.removeAllChildren()
self.scene?.removeFromParent()
skViewGG.presentScene(sceneGG)
})
}
(OverScene is the game over scene) Then, the player has two options, to try again, or return to the menu scene. This uses this code:
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
for touch in touches {
let location:CGPoint = touch.locationInNode(self)
if self.nodeAtPoint(location).name == "retry" {
var sceneCookie = PlayScene(size: self.size)
let skViewCookie = self.view! as SKView
skViewCookie.ignoresSiblingOrder = true
skViewCookie.showsFPS = false
skViewCookie.showsNodeCount = false
sceneCookie.scaleMode = .AspectFill
gameStart(sceneCookie, skViewD: skViewCookie)
}
else if self.nodeAtPoint(location).name == "menu" {
var sceneCookieB = GameScene(size: self.size)
let skViewCookieB = self.view! as SKView
skViewCookieB.ignoresSiblingOrder = true
skViewCookieB.showsFPS = false
skViewCookieB.showsNodeCount = false
sceneCookieB.scaleMode = .AspectFill
gameStart(sceneCookieB, skViewD: skViewCookieB)
}
}
}
func gameStartE(sceneD:SKScene, skViewD:SKView) {
let scale = SKAction.moveToY(self.size.height + 300, duration: 0.17)
homeB.runAction(scale, completion: {
self.scene?.removeAllChildren()
self.scene?.removeFromParent()
skViewD.presentScene(sceneD)
})
}
The problem arrises when going back to the menu or re-trying the game. When going back to the menu, I see a blank screen, meaning the buttons have animated away, so it is displaying the initial menu scene, instead of deallocating the old one, and creating a new one like I want it to. The same thing happens when re-trying the game, it brings back the old scene instead of deallocating it and creating a new one. I have looked all over the internet and have found no solutions to this problem. Help would be very much appreciated.
Thanks.

Related

Swift 2 Game Main Menu

I am trying to implement a main menu to my Spritekit game, but whenever I try to present the scene I get a blank gray screen. Here is the code right now, which presents the game itself and not a menu:
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let scene = GameScene(fileNamed:"GameScene") {
let skView = self.view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
skView.showsDrawCount = true
skView.ignoresSiblingOrder = true
scene.scaleMode = SKSceneScaleMode.AspectFill
skView.presentScene(scene)
}
}
I'm new to this, and I wasn't sure what to do so I tried replacing GameScene with the menu scene, which gave me the gray screen. Any help will be appreciated.
Use this code to load a SKScene file that is created in code only and not in the Scene editor
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
if let skView = self.view as? SKView {
if skView.scene == nil {
let scene = MenuScene(size: skView.bounds.size)
skView.showsFPS = false
skView.showsNodeCount = true
skView.showsPhysics = true
skView.ignoresSiblingOrder = true
scene.scaleMode = .aspectFill
skView.presentScene(scene)
}
}
}
and then in your MenuScene file you will need an init func
init(size: CGSize) {
super.init(size: size)
name = "menuScene"
}

SKTransition Problems and scene loading

So I'm currently creating a game. I have a number of Scenes: Menu, settings, gameScene and GameOverScene.
Transition between ALMOST ALL scenes is without a problem, the code I'm using to transition is:
(e.g. for menu to GameScene)
let secondScene = GameScene(size: self.size)
let transition = SKTransition.pushWithDirection(.Up, duration: 0.7)
secondScene.scaleMode = SKSceneScaleMode.AspectFill
self.scene!.view?.presentScene(secondScene, transition: transition)
However, my GameScene to GameOverScene is extremely glitchy. There is usually a lengthy pause.
The entire contents of GameOverScene is:
import Foundation
import SpriteKit
class GameOverScene: SKScene {
override func didMoveToView(view: SKView) {
let myLabel = SKLabelNode(fontNamed:"American Typrewriter")
myLabel.text = "Game Over!";
myLabel.fontSize = 45;
myLabel.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame));
self.addChild(myLabel)
}
}
Therefore I believe it's unlikely that this is the cause of the delay in transition.
The code I'm using to invoke a 'game over' is:
override func update(currentTime: CFTimeInterval) {
if sprite.position.y < 100 {gameOver()}
}
func gameOver() {
// Loads GameOver Scene //
let secondScene = GameOverScene(size: self.size)
// Creates vibration //
AudioServicesPlayAlertSound(SystemSoundID(kSystemSoundID_Vibrate))
func boatSink() {
sprite.physicsBody = nil
sprite.physicsBody?.affectedByGravity = false
sprite.physicsBody?.dynamic = false
let spritefly = SKAction.moveTo(CGPointMake(400,20), duration:2.0)
car.runAction(spritefly) }
let transition = SKTransition.pushWithDirection(.Up, duration: 3.0)
let nextScene = GameOverScene(size: scene!.size)
nextScene.scaleMode = .AspectFill
scene?.view?.presentScene(nextScene, transition: transition)
}
I've experimented with the use of Delays, such as using:
let skView = self.view! as SKView
let scene = GameOverScene(size: self.scene!.size)
scene.size = skView.bounds.size
scene.scaleMode = .AspectFill
let time = dispatch_time(dispatch_time_t(DISPATCH_TIME_NOW), 1 * Int64(NSEC_PER_SEC))
dispatch_after(time, dispatch_get_main_queue()) {
let sceneTransition = SKTransition.doorsCloseHorizontalWithDuration(2.0)
sceneTransition.pausesOutgoingScene = true;
skView.presentScene(scene, transition: sceneTransition)}
To give time to load but this does not work.
I've also tried using 'pausesOutgoingScene' and pausesIncomingScene' to no avail.
I finally tried slowing the current scene to 0.0 using:
func pauseGameScene() {
self.physicsWorld.speed = 0.0
self.speed = 0.0
}
though this just stopped the code from progressing any further.
My questions are:
1. Is there anything really obvious I'm not thinking about with my transitions?
2. Is there a way to load all Scenes in advance, I'm sure that this probably will only provide minor improvement but it is definitely an area I've not yet looked at.

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.

How to create a main menu for a spritekit game made with swift in xcode?

I created a really simple game in xcode using spritekit and swift. I have finished coding the actual game itself. Now I want to create a main menu so that when the game opens, there will be a menu with buttons either going into settings or starting the game. I have no idea how I can do this. Should I use storyboard? And if so, how can i implement it in xcode. Thanks everyone :)
Swift 3.0
import SpriteKit
class MenuScene: SKScene {
var playButton = SKSpriteNode()
let playButtonTex = SKTexture(imageNamed: "play")
override func didMove(to view: SKView) {
playButton = SKSpriteNode(texture: playButtonTex)
playButton.position = CGPoint(x: frame.midX, y: frame.midY)
self.addChild(playButton)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let pos = touch.location(in: self)
let node = self.atPoint(pos)
if node == playButton {
if let view = view {
let transition:SKTransition = SKTransition.fade(withDuration: 1)
let scene:SKScene = GameScene(size: self.size)
self.view?.presentScene(scene, transition: transition)
}
}
}
}
}
Create two new files. One sprite kit scene and one cocoa touch file. Name them the same so for example MenuScene. To create the files you click on the folder in the sidebar of your xcode project. Then to have the MenuScene show when you run your app go into the GameViewController file. There is a line under viewDidLoad. if let scene = GameScene.unarchiveFromFile("GameScene") as? GameScene { change this into if let scene = MenuScene.unarchiveFromFile("MenuScene") as? Menu Scene { Then in your MenuScene you have to have a button that leads you to your GameScene
import SpriteKit
class MenuScene: SKScene {
var playButton = SKSpriteNode()
let playButtonTex = SKTexture(imageNamed: "play")
override func didMoveToView(view: SKView) {
playButton = SKSpriteNode(texture: playButtonTex)
playButton.position = CGPointMake(frame.MidX, frame.midY)
self.addChild(playButton)
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
if let touch = touches.first as? UITouch {
let pos = touch.locationInNode(self)
let node = self.nodeAtPoint(pos)
if node == playButton {
if let view = view {
let scene = GameScene.unarchiveFromFile("GameScene") as! GameScene
scene.scaleMode = SKSceneScaleMode.AspectFill
view.presentScene(scene)
}
}
}
}
Ask If you need further explanation.

Resources