是否可以在Delegating类内部的didApplyConstraints之后处理计算?

问题描述 投票:0回答:1

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

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

但是,我不确定如何整合

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类内,但也将委托模式放在一起。相反,我通过JoyStick方法访问了handlePosition内部的GameScene getter(作为矢量),并将其作为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() }
虽然这仅通过应用以操纵杆半径为边界的速度即可达到预期的行为,但似乎不够优雅,并且大大减少了我使用委托模式所具有的封装/通用性的数量-随着游戏的发展,这种封装/特性变得显而易见。 

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

我制作了一个名为JoyStick的SKSpriteNode子类,该子类遵循委托模式,其委托是GameScene。为了进一步清理GameScene,JoyStick类还实现了...

swift sprite-kit event-handling skspritenode skscene
1个回答
0
投票
您内部有两个对象,它们具有不同的方法。您不能将两个方法直接移到一个类中。但是可以用这种方式做:

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

© www.soinside.com 2019 - 2024. All rights reserved.