如何在 SKSpriteNode 中正确封装触摸事件处理并将数据传回 SKScene

How to properly encapsulate touch event handling in a SKSpriteNode and pass data back to a SKScene

我正在用 SpriteKit 编写一个游戏,它有一个操纵杆来控制玩家。以前,我将大部分游戏杆逻辑保留在主要 GameScene 的 touchesBegantouchesMovedtouchesEnded 方法中。

因为我有多个 SKScenes,所以我想将这个逻辑抽象成一个 SKSpriteNode 子类 JoyStick,它包含自己的 touches 事件处理程序。这似乎是一个很好的解决方案,因为它会自动处理触摸是否是操纵杆的 "in bounds",并允许我从场景本身中删除逻辑。

但是,我找不到任何好的资源概述如何在 SKScene 和已实现触摸事件处理程序的 SKSpriteNode 实例之间正确地来回传递信息。我可以将 JoyStick 传递给我想要修改的对象实例(比如玩家精灵),但我很好奇是否有适当的方法来回传递数据而不将操纵杆耦合到特定 "instance-to-modify".

此外,在我的 SKSpriteNode 实例中实现触摸事件处理程序,而不是在场景的处理程序中处理所有内容,还有其他缺点吗?

我喜欢尽可能多地处理对象 class 中的代码。所以我会处理它的 class 文件中的任何对象触摸代码,并将触摸发送回场景,以便在需要时由场景单独处理,并使用委托将有关触摸的信息发送到场景.

删除此代码没有坏处,但也有一些好处。

更简洁的代码 如果场景中的线条较少(我自己的发现),xcode 中的加载时间会更快 你不必精确定位触摸登陆的节点,因为它被封装在一个子类中

中子class(猫)

protocol CatDelegate: class{
    func catTouched(cat: Cat)
}

class Cat: SKSpriteNode {

    weak var delegate: CatDelegate!

    var isEnabled = true
    var sendTouchesToScene = true
    var color: SKColor = .white

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent!) {

         guard isEnabled else { return }

         //send touch to scene if you need to handle further touches by the scene
         if sendTouchesToScene {
             super.touchesBegan(touches, with event)
         }

         //handle touches for cat
         delegate?.catTouched(cat: self)
    }
}

同时在游戏场景中...

class GameScene: SKScene {

    private var cat1: Cat!
    private var cat2: Cat!

    …

    func createCats() {
   
     cat1 = Cat()
        cat1.color = .magenta
        cat1.delegate = self
        addChild(cat1)
    
        cat2 = Cat()
        cat2.color = .green
        cat2.delegate = self
        addChild(cat2)
    }
}

extension GameScene: CatDelegate {

    func catTouched(cat: Cat) {
        print("cat of color \(cat.color)")
    }
}

很抱歉,之前的回答根本不完整。这是相同的,包含使其工作所需的所有代码。

import SwiftUI
import SpriteKit

class GameScene: SKScene {

private var cat1: Cat!
private var cat2: Cat!

func createCats() {
    cat1 = Cat(imageNamed: "img1")
    cat1.position = CGPoint(x: 64, y: 128)
    cat1.color = .magenta
    cat1.isUserInteractionEnabled = true
    cat1.delegate = self
    addChild(cat1)
    
    cat2 = Cat(imageNamed: "img2")
    cat2.position = CGPoint(x: 128, y: 128)
    cat2.color = .green
    cat2.isUserInteractionEnabled = true
    cat2.delegate = self
    addChild(cat2)
}

override func didMove(to view: SKView) {
    createCats()
}

}

extension GameScene: CatDelegate {

func catTouched(cat: Cat) {
    print("cat of color \(cat.color)")
}
}


protocol CatDelegate {
  func catTouched(cat: Cat)
}

class Cat: SKSpriteNode {
 var delegate: CatDelegate!

 var isEnabled = true
 var sendTouchesToScene = true
 var colour: SKColor = .blue

 override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent!) {
    
    guard isEnabled else { return }
    
    //send touch to scene if you need to handle further touches by the scene
    if sendTouchesToScene {
        super.touchesBegan(touches, with: event)
    }
    
    //handle touches for cat
    delegate?.catTouched(cat: self)
}
}



struct ContentView: View {

var scene: SKScene {
    let scene = GameScene()
    scene.size = CGSize(width: 256, height: 256)
    scene.scaleMode = .fill
    scene.backgroundColor = .white
    return scene
}

var body: some View {
    SpriteView(scene: scene)
        .frame(width: 256, height: 256)
        .border(Color.red)
}
}