如何在SwiftUI中为SpriteKit场景添加手势识别器?

huangapple go评论50阅读模式
英文:

How to add a gesture recognizer for a SpriteKit scene in SwiftUI?

问题

添加手势识别器的旧方法不再有效,因为视图始终为nil。这是因为在SwiftUI中没有视图主动呈现SpriteView场景。

class GameScene: SKScene {
    override func sceneDidLoad() {
        let gestureSwipe = UISwipeGestureRecognizer()
        gestureSwipe.addTarget(self, action: #selector(gestureActionHandleSwipe(_:)))
        view?.addGestureRecognizer(gestureSwipe)
        /// `view` 始终为nil
struct ContentView: View {
    var body: some View {
        SpriteView(scene: GameScene())
    }

要呈现场景,您可以在SKView类上调用presentScene(:)方法或presentScene(:transition:)方法。如果场景当前未呈现,则此属性为nil。
https://developer.apple.com/documentation/spritekit/skscene/1519726-view

模拟拖动手势使用touchesMoved函数似乎很容易。然而,模拟像pinch这样的手势并不那么直接。
那么在SwiftUI中如何为SpriteKit场景添加手势识别器呢?

英文:

The old way of adding a gesture recognizer no longer works because the view is always nil. This is because there is no view actively presenting the SpriteView scene in SwiftUI.

class GameScene: SKScene {
    override func sceneDidLoad() {
        let gestureSwipe = UISwipeGestureRecognizer()
        gestureSwipe.addTarget(self, action: #selector(gestureActionHandleSwipe(_:)))
        view?.addGestureRecognizer(gestureSwipe)
        /// `view` is always nil
struct ContentView: View {
    var body: some View {
        SpriteView(scene: GameScene())
    }

> To present a scene, you call the presentScene(如何在SwiftUI中为SpriteKit场景添加手势识别器? method or presentScene(:transition:) method on the SKView class. If the scene is not currently presented, this property holds nil.
https://developer.apple.com/documentation/spritekit/skscene/1519726-view

Simulating a drag gesture with the touchesMoved function seems easy. However, simulating a gesture like pinch is not as straightforward.
So how can we gesture recognizer for a SpriteKit scene in SwiftUI?

答案1

得分: 1

你将更容易在SwiftUI级别捕获手势,然后将其传递给你的GameScene状态变量。

class GameScene: SKScene {
    func swipeLeft() {
        print("left")
    }
    
    func swipeRight() {
        print("right")
    }
}

struct Gesture: View {
    @State var gameScene = GameScene()
    
    var body: some View {
        SpriteView(scene: gameScene)
            .gesture(DragGesture(minimumDistance: 20, coordinateSpace: .global)
                        .onEnded { value in
                            let horizontalAmount = value.translation.width
                            let verticalAmount = value.translation.height
                            
                            if abs(horizontalAmount) > abs(verticalAmount) {
                                (value.translation.width < 0) ? gameScene.swipeLeft() : gameScene.swipeRight()
                            }
                        })
    }
}
英文:

you will have better luck capturing the gesture at the SwiftUI level, then passing it to your GameScene state variable

class GameScene: SKScene {
    func swipeLeft() {
        print(&quot;left&quot;)
    }
    
    func swipeRight() {
        print(&quot;right&quot;)
    }

}
        
struct Gesture: View {
    @State var gameScene = GameScene()
    
    var body: some View {
        SpriteView(scene: gameScene)
            .gesture(DragGesture(minimumDistance: 20, coordinateSpace: .global)
                        .onEnded { value in
                            let horizontalAmount = value.translation.width
                            let verticalAmount = value.translation.height
                            
                            if abs(horizontalAmount) &gt; abs(verticalAmount) {
                                (value.translation.width &lt; 0) ? gameScene.swipeLeft() : gameScene.swipeRight()
                            }
                        })
    }
}

答案2

得分: 0

要在didMove(to:)方法中向场景的视图添加手势识别器,请使用SKSceneconvertPoint(fromView:)SKNodeconvert(_:to:)方法来获取所需坐标空间中的触摸点。

    /// 在将场景呈现到视图之前,SpriteKit会调用didMove(to:)方法;
    /// 这是设置场景内容的一好地方。
    ///
    /// 您可以使用这个方法来实现场景即将被视图呈现时的任何自定义行为。
    /// 例如,您可以使用这个方法来创建场景的内容。
    /// https://developer.apple.com/documentation/spritekit/skscene/1519607-didmove
    override func didMove(to view: SKView) {        
        /// https://stackoverflow.com/a/50623843/2226315
        /// https://munirwanis.github.io/blog/2020/wwdc20-spritekit-swiftui/
        
        let pinchGesture = UIPinchGestureRecognizer()
        pinchGesture.addTarget(self, action: #selector(gestureHandlerPinch(_:)))
        view.addGestureRecognizer(pinchGesture)

        let gestureSwipe = UISwipeGestureRecognizer()
        gestureSwipe.addTarget(self, action: #selector(gestureHandlerSwipe(_:)))
        view.addGestureRecognizer(gestureSwipe)
    }
英文:

To add a gesture recognizer to the scene's view in didMove(to:), use SKScene's convertPoint(fromView:) and SKNode's convert(_:to:) methods to obtain the touch in the required coordinate space.

    /// SpriteKit calls the method didMove(to:) before it presents your scene
    /// in a view; it’s a good place to do some initial setup of your scene’s contents.
    ///
    /// You can use this method to implement any custom behavior for your scene
    /// when it is about to be presented by a view. For example, you might use this method to create the scene’s contents.
    /// https://developer.apple.com/documentation/spritekit/skscene/1519607-didmove
    override func didMove(to view: SKView) {        
        /// https://stackoverflow.com/a/50623843/2226315
        /// https://munirwanis.github.io/blog/2020/wwdc20-spritekit-swiftui/
        
        let pinchGesture = UIPinchGestureRecognizer()
        pinchGesture.addTarget(self, action: #selector(gestureHandlerPinch(_:)))
        view.addGestureRecognizer(pinchGesture)

        let gestureSwipe = UISwipeGestureRecognizer()
        gestureSwipe.addTarget(self, action: #selector(gestureHandlerSwipe(_:)))
        view.addGestureRecognizer(gestureSwipe)
    }

huangapple
  • 本文由 发表于 2023年6月12日 11:45:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/76453535.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定