Spritekit and Swiftui, Change Scene a Better Way

Spritekit and swiftui, change scene a better way

You are using a standard way of switching views. You could clean your code up a bit like this:

struct ContentView: View {
@State var changeScene = false
var body: some View {
ZStack{
SpriteView(scene: (changeScene ? FirstScene() : SecondScene())) // this is a terniary operator

Button {
changeScene.toggle()
} label: {
Text("Change")
}
}
}
}

The new views do not need to be @StateObjects. You can call the View Types directly in your view.

Note: I am away from my computer so this is not tested.

Move From SpriteKit scene to SwiftUI View

You can use

@Environment(.presentationMode) var presentationMode

So you can create a button and call

presentationMode.wrappedValue.dismiss()

Or you can pass a binding var to Content View and set to false like so:

In MainMenu

struct MainMenu: View {
@State var isPresented = false
var body: some View {
NavigationView {
VStack {
Text("Replicator")
.font(.largeTitle)
.fontWeight(.bold)
.padding()
NavigationLink(destination: ContentView(isPresented: $isPresented).navigationBarBackButtonHidden(true), isActive: $isPresented) {
HStack {
Image(systemName: "play.circle")
.font(.title3)
Text("Start")
.font(.title)

}
.frame(width: 250, height: 50)
.background(.cyan)
.cornerRadius(25)
.foregroundColor(.white)
}
}
}
}
}

In ContentView:

struct ContentView: View {
@Binding var isPresented: Bool
var scene: SKScene {
let scene = Level_1()
scene.size = CGSize(width: 750, height: 1334)
scene.scaleMode = .aspectFit
return scene
}
var body: some View {
ZStack {
SpriteView(scene: scene)
.ignoresSafeArea()
Button(action: { //You can put the button wherever you want as long as you pass in the isPresented Binding
isPresented.toggle()
}) {
Text("Back to MainMenu")
}
}
}
}

SwiftUI handling SpriteKit scene recreation when data changes

I managed to work around my problem by creating a view model that manages the SpriteKit scene creation if needed.

class TamagotchiViewModel {

private var spriteKitScenes: [SpriteKitScene] = []

func scene(for tamagotchi: TamagotchiModel) -> SpriteKitScene {
if let scene = spriteKitScenes.first(where: { $0.tamagotchi?.tamagotchiModel.id == tamagotchi.id}) {
return scene
} else {
let newScene = SpriteKitScene(model: tamagotchi)
spriteKitScenes.append(newScene)
return newScene
}
}
}

SwiftUI, changing a view from scene(:continue

It would be appropriate to use EnvironmentObject in this scenario

class AppState: ObservableObject
@Published var someVar: Sometype
}

class SceneDelegate {
let appState = AppState()

func scene(_ scene: UIScene,
continue userActivity: NSUserActivity) {

// ... other code
appState.someVar = ... // modify
}
}

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {

// .. other code
let contentView = ContentView()
.environmentObject(appState)
//
}
}

struct ContentView: View {
@EnvironmentObject var appState

var body: some View {
VStack {
// ... other code
appState.someVar // use here as needed
}
}
}

Scene with SpriteView and SwiftUI does not fill whole screen

You have height at width and width at height parameter at scene property. (How @aheze mentioned in the comment)

SpriteKit and SwiftUI. GameScene func not working from UI button

Two problems:

  1. Your scene is a computed property so you are recreating the scene every time you try use it in SpriteView.
  2. You are creating a new scene when you try add the ball. This should be added to the current scene, not a new instance.

Change scene to this:

let scene: GameScene = {
let scene = GameScene()
scene.size = CGSize(width: 800, height: 930)
scene.scaleMode = .fill
scene.backgroundColor = .red

return scene
}()

And change the action on the pause button to this:

scene.ball()
print("Image tapped!")

Side note: with a fixed scene size like this, you got to be careful - you can only really see the play/pause buttons on iPad screens since the scene size is so big. Consider keeping it at a specific aspect ratio instead, then fitting it to the screen.

How to switch between scenes in Sprite Kit?

It looks like your issue is in didMoveToView: in your PauseScene. You don't want to change your anchor point for self.pauseBackground Normally anchor point is based on 0 to 1. (.5,.5) being the center of the sprite. You are setting it to something much higher than that and if you are setting the position to half the width and hight of the scene I don't see why you would want to change the anchor point at all. Looks like just deleting the line of code should fix the issue.

class PauseScene: SKScene {
let pauseBackground = SKSpriteNode (imageNamed: "pauseBackground")

override func didMoveToView(view: SKView) {
self.pauseBackground.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
self.addChild(pauseBackground)
}
}

Also I see you are changing the size of your scene after you init it. I would just init it with the size you want.

override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if self.nodeAtPoint(location) == self.pause {
let skView = self.view as SKView!
skView.ignoresSiblingOrder = true
var pauseScene = PauseScene(size: skView.bounds.size)
scene?.paused = true
pauseScene.scaleMode = .AspectFill
skView.presentScene(pauseScene)
}
}
}

Hopefully that helps and makes sense.

Using SpriteKit inside SwiftUI

SwiftUI 2

There is now a native view responsible for displaying a SKScene - it's called SpriteView.

Assuming we have a simple SKScene:

class Scene: SKScene {
override func didMove(to view: SKView) {
...
}
}

we can use a SpriteView to display it directly in a SwiftUI view:

struct ContentView: View {
var scene: SKScene {
let scene = Scene()
scene.size = CGSize(width: 300, height: 400)
scene.scaleMode = .fill
return scene
}

var body: some View {
SpriteView(scene: scene)
.frame(width: 300, height: 400)
.edgesIgnoringSafeArea(.all)
}
}

You can find more information here:

  • How to integrate SpriteKit using SpriteView.


Related Topics



Leave a reply



Submit