如何在 SKSpriteNode 中正确封装触摸事件处理并将数据传回 SKScene
Posted
技术标签:
【中文标题】如何在 SKSpriteNode 中正确封装触摸事件处理并将数据传回 SKScene【英文标题】:How to properly encapsulate touch event handling in a SKSpriteNode and pass data back to a SKScene 【发布时间】:2020-04-13 19:53:03 【问题描述】:我正在用 SpriteKit 编写一个游戏,它有一个操纵杆来控制玩家。以前,我将大部分操纵杆逻辑保留在主 GameScene 的 touchesBegan
、touchesMoved
和 touchesEnded
方法中。
由于我有多个SKScenes
,我想将此逻辑抽象为SKSpriteNode
子类JoyStick
,其中包含自己的touches
事件处理程序。这似乎是一个很好的解决方案,因为它会自动处理触摸是否在操纵杆的“范围内”,并允许我从场景本身中删除逻辑。
但是,我找不到任何好的资源来概述如何在 SKScene
和已实现触摸事件处理程序的 SKSpriteNode
实例之间正确地来回传递信息。我可以将我想要修改的对象的实例(如玩家精灵)传递给操纵杆,但我很好奇是否有适当的方法来来回传递数据而不将操纵杆耦合到特定的 " 实例-修改”.
此外,在我的 SKSpriteNode 实例中实现触摸事件处理程序而不是在场景的处理程序中处理所有内容是否还有其他缺点?
【问题讨论】:
【参考方案1】:我喜欢尽可能多地处理对象类中的代码。因此,我将处理其类文件中的任何对象触摸代码,并将触摸发送回场景以在需要时由场景单独处理,并使用委托将有关触摸的信息发送到场景。
删除此代码没有缺点,但也有几个优点。
更简洁的代码 如果场景的线条较少,xcode 中的加载时间会更快(我自己的发现) 您不必精确定位触摸所在的节点,因为它被封装在子类中
在子类(猫)中
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)")
【讨论】:
感谢@RonMyschuk,我刚刚实现了这个模式并且它有效。此外,我发现我的委派类(在此示例中为Cat
)需要在应用 SKConstraint 后进行计算。委托GameScene
中有一个函数didApplyConstraints
,但文档建议不要直接调用它。是否有一种干净的方法可以将不可直接调用的函数集成到此模式中?更具体地说,我的委托类子类 SKSpriteNode
并在 touchesMoved
中调用委托 - 这似乎与对 didApplyConstraints
的每帧调用一次冲突。【参考方案2】:
我很抱歉,但以前的答案根本不完整。这里是相同的,包含使其工作所需的所有代码。
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)
【讨论】:
以上是关于如何在 SKSpriteNode 中正确封装触摸事件处理并将数据传回 SKScene的主要内容,如果未能解决你的问题,请参考以下文章
如何使用该节点的自定义类检测在单独场景中创建的 skspritenode 上的触摸