我制作了一个SKSpriteNode
的子类,称为JoyStick
,它遵循委托模式,其委托人是GameScene
。为了进一步清理GameScene
,JoyStick
类还实现了自己的touchesBegan
,touchesMoved
和touchesEnded
方法。
问题是JoyStick
的touchesMoved
方法中有一些位置计算,在将某些SKConstraints
应用于操纵杆之后(例如,将操纵杆手柄绑定到底座),需要进行一些位置计算。我知道有didApplyConstraints
的SKScene
实例方法,并且文档指示应该重写它,而不应该调用它,因为它已经每帧被调用一次。
但是,我不确定如何整合
didApplyConstraints
到我的委派操纵杆类的touchesMoved
方法中,而不求助于将逻辑移回我的GameScene
的didApplyConstraints
中。 这里是我目前使用委托模式实现的简化示例。请注意,以下代码允许变量joyVector
接受超出可接受范围的值,因为尚未应用约束。
GameScene.swift
import SpriteKit import GameplayKit class GameScene: SKScene { var shipNode: SKSpriteNode? var joyStick: JoyStick? override func didMove(to view: SKView) { self.view?.isMultipleTouchEnabled = true // Init the ship guard let shipNode = self.childNode(withName: "ShipNode") as? SKSpriteNode else { fatalError("Player node not loaded!") } self.shipNode = shipNode // Init the joystick joyStick = JoyStick() joyStick?.isUserInteractionEnabled = true joyStick?.position = CGPoint(x: -500, y: -200) joyStick?.delegate = self self.addChild(joyStick!) } } extension GameScene: JoyStickDelegate{ var objPhysicsBody: SKPhysicsBody? { return self.shipNode?.physicsBody } }
JoyStick.swift
import Foundation import SpriteKit protocol JoyStickDelegate: class { var objPhysicsBody: SKPhysicsBody? {get} } class JoyStick: SKSpriteNode { weak var delegate: JoyStickDelegate! var joyVector: CGVector = CGVector() var handle: SKSpriteNode? init () { let baseTexture = SKTexture(imageNamed: "joyStickBase") super.init(texture: baseTexture, color: UIColor.clear, size: baseTexture.size()) // Add the joystick handle onto the base handle = SKSpriteNode(imageNamed: "joyStickHandle") handle?.position = CGPoint(x: 0 , y: 0) // Add constraints let range = CGFloat(self.size.width/2 - (handle?.size.width)! / 2) let moveRange = SKRange(lowerLimit: 0, upperLimit: range) let rangeConstraint = SKConstraint.distance(moveRange, to: CGPoint(x: 0,y: 0)) handle?.constraints = [rangeConstraint] self.addChild(handle!) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } func moveJoyStick(_ touches: Set<UITouch>) { guard let fingerPosition = touches.first?.location(in: self) else { return } self.handle!.position = fingerPosition } func getJoyVector(handlePosition: CGPoint) -> CGVector { return CGVector(dx: handlePosition.x, dy: handlePosition.y) } func resetJoyStick() { delegate?.objPhysicsBody?.velocity = CGVector(dx: 0, dy: 0) //animation to return the joystick to the center... } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { self.moveJoyStick(touches) joyVector = getJoyVector(handlePosition: self.handle!.position) delegate?.objPhysicsBody?.velocity = joyVector } override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { self.moveJoyStick(touches) joyVector = getJoyVector(handlePosition: self.handle!.position) delegate?.objPhysicsBody?.velocity = joyVector } override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { resetJoyStick() } override func touchesEstimatedPropertiesUpdated(_ touches: Set<UITouch>) {} override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {} }
一种完成了[[工作正常]]的替代实现是将触摸事件方法保留在
JoyStick
类内,但也将委托模式放在一起。相反,我通过JoyStick
方法访问了handlePosition
内部的GameScene
getter
(作为矢量),并将其作为GameScene
的didApplyConstraints
方法内部的速度应用。这是添加的两个代码片段,以实现此目的:
添加到JoyStick.swift:
func getPositionVelocity() -> CGVector {
guard let handlePosition = self.handle?.position else { return CGVector() }
return CGVector(dx: handlePosition.x, dy: handlePosition.y)
}
添加到GameScene.swift:
...
//joyStick?.delegate = self
...
override func didApplyConstraints() {
self.shipNode?.physicsBody?.velocity = self.joyStick?.getPositionVelocity() ?? CGVector()
}
虽然这仅通过应用以操纵杆半径为边界的速度即可达到预期的行为,但似乎不够优雅,并且大大减少了我使用委托模式所具有的封装/通用性的数量-随着游戏的发展,这种封装/特性变得显而易见。最终,是否有可能避免将约束后逻辑堆叠到
didApplyConstraints
中的单个GameScene
定义中以实现此功能?为什么UIResponder
触摸事件似乎总是在:didApplyConstraints
之前处理-即使它们似乎不在SKScene Frame-Cycle
之外?
我制作了一个名为JoyStick的SKSpriteNode子类,该子类遵循委托模式,其委托是GameScene。为了进一步清理GameScene,JoyStick类还实现了...
class GameScene: SKScene {
var onJoysticNeedVerticalPosition: (()-> CGVector)?
....
override func didApplyConstraints() {
self.shipNode?.physicsBody?.velocity = onJoysticNeedVerticalPosition?() ?? CGVector()
}
}