如何在 SKSpriteNode 中正确封装触摸事件处理并将数据传回 SKScene
How to properly encapsulate touch event handling in a SKSpriteNode and pass data back to a SKScene
我正在用 SpriteKit 编写一个游戏,它有一个操纵杆来控制玩家。以前,我将大部分游戏杆逻辑保留在主要 GameScene 的 touchesBegan
、touchesMoved
和 touchesEnded
方法中。
因为我有多个 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)
}
}
我正在用 SpriteKit 编写一个游戏,它有一个操纵杆来控制玩家。以前,我将大部分游戏杆逻辑保留在主要 GameScene 的 touchesBegan
、touchesMoved
和 touchesEnded
方法中。
因为我有多个 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)
}
}