Spritekit How to Create and Transition to Different Scenes (Swift Language)

SpriteKit how to create and transition to different scenes (Swift language)

It doesn't seem like you have looked into Apple's documentation. They have an excellent guide for SpriteKit. Also, the tutorials at RayWenderlich.com within the spriteKit category are phenomenal. I haven't read much into Swift yet, but it is my understanding that Swift can be written alongside Objective-C.That being said, I'll give you a starting point (in Objective-C) .

1) Calling the initial scene:

Within your main view controller, you will want to cast the VC's view property to an SKView within viewDidLoad like so:

SKView *spriteKitView = (SKView *)self.view;

some useful debugging properties on SKView :

spriteKitView.showsFPS = YES;
spriteKitView.showsNodeCount = YES;
spriteKitView.showsPhysics = YES;

You will have to configure each scene separately (subclass SKScene). After you have done this, import the main scene to your main VC's class implementation. To present the main scene (still in viewDidLoad):

MyScene *mainScene = [MyScene new];
[spriteKitView presentScene: mainScene];

2) transition between scene via label (or any other SKNode) :
Set relevant nodes as properties and present a new scene via:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInNode:self];

if ([self.playAgainButton containsPoint:touchLocation]) {
[self presentGamePlayScene];
} else if([self.mainMenuButton containsPoint:touchLocation]) {
[self presentMainMenu];
}
}

- (void)presentGamePlayScene {
gamePlayScene *newGamePlay = [[gamePlayScene alloc]init];
newGamePlay.scaleMode = SKSceneScaleModeAspectFill;
SKTransition *arbitraryTransition = [SKTransition crossFadeWithDuration:2.0]; //look into SKTransition for a plethora of different options.
[self.view presentScene:newGamePlay transition:arbitraryTransition];
}

3) To change scenes via contact, conform to the protocol SKPhysicsContactDelegate within any given SKScene. Within that scene's implementation:

- (void)didBeginContact:(SKPhysicsContact *)contact {
if(contact.bodyA.categoryBitMask == enemyCategory && contact.bodyB.categoryBitMask == arbitraryNodeCategory) {
[self presentGameOverScene];
}
}

An SKPhysicsContact has 2 colliding SKPhysicsBodys attached to it via properties. These colliding nodes must have their SKPhysicsBody's initialized. In addition, they must have their contactBitMask property set on their SKPhysicsBody like so:

@implementation SomeNode 

- (instanceType)initCollidingNode {
if(self = [super init]) {
self.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:self.someSize];
self.physicsBody.contactBitMask = enemyCategory | powerUpCategory;
self.physicsBody.categoryBitMask = arbitraryNodeCategory;
self.physicsBody.dynamic = YES
}
return self;
}
  • SKSpriteNode and SKPhysicsBody have other relevant properties you may need

SpriteKit transition between scenes without resetting game

You have lots of options to keep persistent state across your game scenes. I've listed two approaches I've used.

Option A: Maintain a Reference to the Scene

When a scene is swapped out for a new one, the scene is often fully removed from memory. If you hold onto a reference for the scene object somewhere else, and present that reference, no data will be lost.

To maintain a reference over time (and present the scene again when needed), I recommend a scene presenter class with a static instance such as the following:

class SceneCoordinator {
static var shared = SceneCoordinator()

var gameScene : GameScene?
var shopScene : ShopScene?
}

when you initialize a GameScene, also register it with your with SceneCoordinator.shared.gameScene = self. Then, when transitioning away from another scene, you can present the instance you stored in the coordinator class.

didMoveToView() will still be called on the scene when it is presented again. You could move all your initializing code to a separate function, create a new instance var such as var isInitialized = false, and only initialize your content if it is false (and set it to true after your initialize).

The issue with this approach is that scene objects are expensive, which means you could build up a large overhead by not allowing scenes to be released.

Option B: Model Struct

The better way (which would also allow for easier reinit of a scene after your app closes) would be to create a data model of your game state, and provide a function to create a GameScene from your model object.

This method is more consistent with the Model-View-Controller design pattern, and allows your scenes and data to be a lot more lightweight.

Such as:

struct GameModel {
var coins : Int
}

class GameScene : SKScene {
var state : GameModel

convenience init(size: CGSize, state: GameModel) {
self.state = state
// set up scene content from state
}

// lots of fun game scene logic

func playerCollectedCoin() {
state.coins += 1
}

func moveToShopScene() {
// init a new shop scene with the state of this scene
let shop = ShopScene(size: self.view!.bounds.size, state: self.state)
(self.view as! SKView).presentScene(scene)
}
}

class ShopScene : SKScene {
var state : GameModel

convenience init(size: CGSize, state: GameModel) {
self.state = state
// set up scene content from state
}

// lots of fun shop scene logic

func playerSpentCoins(amount: Int) {
state.coins -= amount
}

func moveToGameScene() {
// init a new game scene with the updated state of this scene
let game = GameScene(size: self.view!.size, state: self.state)
(self.view as! SKView).presentScene(game)
}
}

Switching Scenes in SpriteKit Swift 2

In my games, I use this:

// Setting a size (or else it may look like its zoomed in)
var selectView = BallSelect(size: view!.bounds.size)
// Setting a file for that scene
selectView = BallSelect(fileNamed: "BallSelect")!
// Setting the scale
selectView.scaleMode = SKSceneScaleMode.AspectFill
// Transitioning scenes wit a specific transition
self.scene?.view?.presentScene(selectView, transition: SKTransition.fadeWithColor(color, duration: 1))

Tell me if it works :)

Simplest Way To Change Scene In Swift + Sprite Kit

when changing between scenes, you're going to need to set up a transition, how the scene will change to the next and define which scene you want to transition to.

For the transition,

 var transition:SKTransition = SKTransition.fadeWithDuration(1)

The fadeWithDurationcan be replaced with any SKTransition a list of which can be found in the documentation https://developer.apple.com/library/prerelease/ios/documentation/SpriteKit/Reference/SKTransition_Ref/index.html

as for defining the scene,

var scene:SKScene = GameScene(size: self.size)

You're stating which scene you wish to transition to, in this case GameScene, but should be replaced with whichever scene you wish to transition to.

In order to start the transition, call:

self.view?.presentScene(scene, transition: transition)

Which will move to the scene scene which was set up in the line prior, using the transition transition which was also defined.

Navigating between scenes in Sprite Kit?

Sprite Kit makes it easy to transition between scenes. You can either
keep scenes around persistently, or dispose of them when you
transition between them. In this example, you create a second scene
class to learn some other game behaviors. When the “Hello, World!”
text disappears from the screen, the code creates a new scene and
transitions to it. The Hello scene is discarded after the transition.

Sprite Kit Programming Guide

https://developer.apple.com/library/ios/documentation/GraphicsAnimation/Conceptual/SpriteKit_PG/GettingStarted/GettingStarted.html#//apple_ref/doc/uid/TP40013043-CH2-SW10

Swift spritekit change scenes?

It turns out I had a particle emitter in the menu scene. I forgot to remove it when transitioning. So it was trying to emitting to a scene that did not exist anymore. Fixing it was as simple as adding this line before transitioning to the game scene.

myparticle.removeFromParent();

Swift: Deallocate GameScene after transition to new scene?

In my project, I used the following mechanism and it worked well. All my scenes SKScene objects were optional variables. When i need the new scene to show, i create it and present at SKView. When i need to display the new scene, I set the previous object scene object to nil, this immediately reducing the reference count by 1, and becouse of at this moment no one object is not use my scene, the reference count becomes zero and scene was deleted.

The SKScene object is a ordinary class object and ARC works with them like with all reference type objects. You only need to monitor the number of references to the scene. All are finished with the various resources I was start in deinit of SKScene object

The simple example:

At UIViewController we have optional objects of GameScene:

class GameViewController: UIViewController {
var scene1: GameScene?
var scene2: GameScene?
var skView: SKView?

// Action to present next Scene
@IBAction func nextSceneAction(sender: AnyObject) {
print("Next scene")
// Create new GameScene object
scene2 = GameScene(fileNamed:"GameScene")
// Present scene2 object that replace the scene1 object
skView!.presentScene(scene2)
scene = nil
}

override func viewDidLoad() {
super.viewDidLoad()

// Create GameScene object
scene = GameScene(fileNamed:"GameScene")
skView = (self.view as! SKView)
skView!.showsFPS = true
skView!.showsNodeCount = true

skView!.ignoresSiblingOrder = true

scene!.scaleMode = .AspectFill

// Present current scene
skView!.presentScene(scene)
}
}

At GameScene in deinit print some text to show that it object will be deleted:

class GameScene: SKScene {
...

deinit {
print("Deinit scene")
}
}

Debug output after push the nextSceneAction button:

Next scene

Deinit scene

Swift: How to keep track of and communicate scores between scenes in SpriteKit

NSUserDefaults is a great way to keep track of scores.

To save the high score:

let x : Int = 45 // This int is your high score
var myString = String(x) // This String is you high score as a String

var defaults = NSUserDefaults.standardUserDefaults()

defaults.setObject(myString, forkey : "High_Score") // Saving the String to NSUserDefaults

To access the high score:

var defaults = NSUserDefaults.standardUserDefaults()

var HighScore = defaults.objectForKey("High_Score") // Retrieving your high score as a String


Related Topics



Leave a reply



Submit