在SwiftUI

时间:2019-06-16 00:28:14

标签: ios swift sprite-kit skscene swiftui

SpriteKit内创建SwiftUI场景时遇到问题。我最初将这个项目创建为SwiftUI项目。

这是我到目前为止的代码:

ContentView.swift:

/// Where the UI content from SwiftUI originates from.
struct ContentView : View {
    var body: some View {
        // Scene
        SceneView().edgesIgnoringSafeArea(.all)
    }
}

SceneView.swift:

/// Creates an SKView to contain the GameScene. This conforms to UIViewRepresentable, and so can be used within SwiftUI.
final class SceneView : SKView, UIViewRepresentable {

    // Conformance to UIViewRepresentable
    func makeUIView(context: Context) -> SKView {
        print("Make UIView")
        return SceneView(frame: UIScreen.main.bounds)
    }
    func updateUIView(_ uiView: SKView, context: Context) {
        print("Update UIView")
    }

    // Creating scene
    override init(frame: CGRect) {
        super.init(frame: frame)

        let scene = Scene(size: UIScreen.main.bounds.size)
        presentScene(scene)
    }
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

Scene.swift:

/// The scene for the game in SpriteKit.
final class Scene : SKScene {

    override func didMove(to view: SKView) {
        super.didMove(to: view)

        print("Scene didMove:")
    }
}

问题

问题是场景正在重新加载多次,如日志所示(因为代码中有print个):

  

场景didMove:

     

制作UIView

     

场景didMove:

     

更新UIView


如您所见,Scene didMove:被打印两次。我只想调用一次,因为我想在这里创建我的精灵。有什么想法吗?

5 个答案:

答案 0 :(得分:4)

您的val futureResultList: Future[List[Result]] = ??? val result = futureResultList.map(_.map(_ == Result.OK) .forall(_ == true)) 实现不正确。

SwiftUI使用结构在其DSL中构建视图-而不是视图。

您要创建一个符合SceneView的{​​{1}}。

struct

有关如何将基于UIViewRepresentable的视图移植到SwiftUI的更多信息,请参见以下出色的WWDC 2019视频:Integrating SwiftUI

答案 1 :(得分:2)

SwiftUI 2

现在有一个本机视图负责显示SKScene-它称为SpriteView

假设我们有一个简单的SKScene

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

我们可以使用SpriteView将其直接显示在SwiftUI视图中:

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

您可以在此处找到更多信息:

答案 2 :(得分:1)

这是我解决的方法:

ContentView.swift

import SwiftUI

struct ContentView: View {
    var body: some View {
        SpriteKitContainer(scene: SpriteScene())
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

SpriteKitContainer.swift

import SwiftUI
import SpriteKit

struct SpriteKitContainer: UIViewRepresentable {
    typealias UIViewType = SKView
    
    var skScene: SKScene!
    
    init(scene: SKScene) {
        skScene = scene
        self.skScene.scaleMode = .resizeFill
    }
    
    class Coordinator: NSObject {
        var scene: SKScene?
    }
    
    func makeCoordinator() -> Coordinator {
        let coordinator = Coordinator()
        coordinator.scene = self.skScene
        return coordinator
    }
    
    func makeUIView(context: Context) -> SKView {
        let view = SKView(frame: .zero)
        view.preferredFramesPerSecond = 60
        view.showsFPS = true
        view.showsNodeCount = true
        
        return view
    }
    
    func updateUIView(_ view: SKView, context: Context) {
        view.presentScene(context.coordinator.scene)
    }
}

struct SpriteKitContainer_Previews: PreviewProvider {
    static var previews: some View {
        Text("Hello, World!")
    }

}

SpriteKitScene.swift

import UIKit
import SpriteKit

class SpriteScene: SKScene {
    
    //change the code below to whatever you want to happen on skscene
    
    override func didMove(to view: SKView) {
        physicsBody = SKPhysicsBody(edgeLoopFrom: frame)
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let touch = touches.first else { return }
        
        let location = touch.location(in: self)
        let box = SKSpriteNode(color: .red, size: CGSize(width: 50, height: 50))
        box.position = location
        box.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 50, height: 50))
        addChild(box)
    }
}

PS:您只会在模拟器中看到spritekitscene,而在预览中则无法使用

答案 3 :(得分:0)

以下是可以通过这种方式使用的SpriteKit容器视图:

SpriteKitContainer(sceneName: "MainScene")

struct SpriteKitContainer : UIViewRepresentable {

    let sceneName: String

    class Coordinator: NSObject {
        var scene: SKScene?
    }

    func makeCoordinator() -> Coordinator {
        return Coordinator()
    }

    func makeUIView(context: Context) -> SKView {
        let view = SKView(frame: .zero)
        view.preferredFramesPerSecond = 60
        view.showsFPS = true
        view.showsNodeCount = true

       //load SpriteKit Scene
       guard let aScene = SKScene(fileNamed: sceneName)
       else {
            view.backgroundColor = UIColor.red
            return view
       }
       aScene.scaleMode = .resizeFill
       context.coordinator.scene = aScene
       return view
    }


    func updateUIView(_ view: SKView, context: Context) {
       view.presentScene(context.coordinator.scene)
    }

}
#if DEBUG
struct ContentView_Previews : PreviewProvider {

   static var previews: some View {

      // Replace "MainScene" with your SpriteKit scene file name
      SpriteKitContainer(sceneName: "MainScene")
         .edgesIgnoringSafeArea(.all)
         .previewLayout(.sizeThatFits)
      }
}
#endif

答案 4 :(得分:0)

不需要协调员来演示场景;上下文就足够了。这是我用来加载Scene.sks文件的方法:

struct ContentView : View {
    var body: some View {

        SKViewContainer()

    }
}

struct SKViewContainer: UIViewRepresentable {

    func makeUIView(context: Context) -> SKView {

        let view = SKView() 

        guard let scene = SKScene(fileNamed: "Scene")
            else {
                view.backgroundColor = UIColor.red
                return view
        }

        view.presentScene(scene)

        return view    
    }

    func updateUIView(_ uiView: SKView, context: Context) {}

}