在Delegating类内部执行ApplyConstraints后,是否可以处理计算



我创建了SKSpriteNode的一个子类JoyStick,它遵循委托模式,其中它的委托是GameScene。为了进一步清理GameSceneJoyStick类还实现了自己的touchesBegantouchesMovedtouchesEnded方法。

问题是,我在JoySticktouchesMoved方法中有一些位置计算,需要在将某些SKConstraints应用于操纵杆之后进行(例如将操纵杆手柄绑定到底座(。我知道有一个SKScenedidApplyConstraints实例方法,并且文档指示应该重写它,而不是调用它,因为它已经每帧调用一次了。

但是,我不知道如何didApplyConstraints集成到我的委派操纵杆类的touchesMoved方法中,而不将逻辑移回我的GameScenedidApplyConstraints中。

下面是我目前使用委托模式实现的一个简化示例。请注意,由于约束尚未应用,下面的代码允许变量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类中,但同时删除委派模式。相反,我通过getter方法访问了GameScene中的JoyStickhandlePosition(作为矢量(,并将其作为GameScenedidApplyConstraints方法中的速度应用。以下是添加的两个代码片段:

添加到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()
}

虽然这实现了只应用受操纵杆半径限制的速度的预期行为,但它似乎远没有那么优雅,并大大减少了我对代理模式的封装/通用性——随着游戏的发展,这一点变得越来越明显。

最终,是否可以避免将后约束逻辑堆积到GameScene中的单个didApplyConstraints定义中以实现此功能?为什么UIResponder触摸事件似乎总是在:didApplyConstraints之前处理——尽管它们似乎在SKScene Frame-Cycle之外?

您有两个内部方法不同的对象。不能将两个方法直接移动到一个类中。但可以这样做:

class GameScene: SKScene {
var onJoysticNeedVerticalPosition: (()-> CGVector)? 
....
override func didApplyConstraints() {
self.shipNode?.physicsBody?.velocity = onJoysticNeedVerticalPosition?() ?? CGVector()
}
}

protocol JoyStickDelegate: class {
var objPhysicsBody: SKPhysicsBody? {get}
var onJoysticNeedVerticalPosition: (()-> CGVector)? {get set}
}

然后

class JoyStick: SKSpriteNode {
...
init () {
self.delegate?.onJoysticNeedVerticalPosition = {[weak self] in
self?.getPositionVelocity()
}
}
...
func getPositionVelocity() -> CGVector {
guard let handlePosition = self.handle?.position else { return CGVector() }
return CGVector(dx: handlePosition.x, dy: handlePosition.y)
}
}

所以事实上,它仍然是两个不同的对象,但第一个对象(GameScene(用计算逻辑保持闭包,事实上在第二个对象(JoyStick(中计算,第二个通过委托方法将其详细地提供给第一个对象。

最新更新