0

设置:

我正在子类化SKSpriteNode()以创建一个名为SubNode().

SKSPriteNode() 类有一个称为physicsBody存储SKPhysicsBody()对象的属性。SKPhysicsBody有一个叫做“速度”的属性,它是CGVector()

目标:

在我的子类中,我希望有一个始终保留前一个的变量CGVector()。例如,只要我打电话subNode.physicsBody?.velocity = CGVector(dx: 10, dy: 10)的意思。subNode.previousVelocity应设置为以前的subNode.physicsBody?.velocity值。

问题

如果velocity只是超类的继承属性,我可以只是override该属性并附加一个didSet观察者。但是,因为velocity它是的一个属性,SKPhysicsBody()并且 SKPhysicsBody()当它的一个属性发生变化时,对象不会改变,didSet所以不会被触发,我无法听到它的变化。

如果我的解释不清楚,请要求更多澄清。

我的子类:

class SubNode: SKSpriteNode {
    
    var previousVelocity: CGVector = .zero

    // This doesn't get triggered because the physiceBody object doesn't change when one of its properties changes.
    override var physicsBody: SKPhysicsBody? {
        didSet {
            previousVelocity = oldValue?.velocity
        }
    }
    
    // If velocity would be a property of the superclass, this would trigger.
    override var velocity: CGVector {
        didSet {
            previousVelocity = oldValue
        }
    }
}

从 SubNode() 子类创建对象 subNode,设置物理体,然后设置速度"

let subNode = SubNode()
subNode.physicsBody = SKPhysicsBody()
subNode.physicsBody?.velocity = CGVector(dx: 10, dy: 10)
subNode.physicsBody?.velocity = CGVector(dx: 0, dy: 0)
//should be true: subnode.previousVelocity == CGVector(dx: 10, dy: 10)
4

1 回答 1

0

这只是部分答案!只是试图找到解决问题的方法。

我试图以某种方式找到解决方法。我注意到,一旦对象的属性发生变化,对象的 getter 就会被触发。我创建了以下游乐场文件,它似乎工作。一旦我更改了对象的文本,以前的名称就会存储在另一个变量中。但从我的测试来看,这似乎有效。我不确定我的逻辑是否正确,或者我是否遗漏了一些东西,实现应该更简单的东西也可能有点太多了。

下面我为我的子类添加了代码,并且到目前为止我可以测试它确实有效。但是,我希望得到一些反馈,因为该解决方案可能存在缺陷。

import UIKit

class ObjectClass {
    var name: String = "Initial Name"
}

class SuperClass {
    var object: ObjectClass?
}

class SubClass: SuperClass {
    
    var _oldObjectName: [String?] = [nil]
    
    var oldObjectName: String? {
        _ = object?.name
        return _oldObjectName.first ?? nil
    }
    
    override var object: ObjectClass? {
        get {
            // Is also being called before the object has been written to.
            if !_oldObjectName.contains(super.object?.name) {
                _oldObjectName.append(super.object?.name)
                _oldObjectName = _oldObjectName.suffix(2)
            }
            return super.object
        }
        set {
            super.object = newValue
        }
    }
}

let subClass = SubClass()

subClass.object = ObjectClass()

将上述解决方案与我的子类一起使用:

class SubNode: SKSpriteNode {
    
    private var _previousVelocity: [CGVector?] = []
    var previousVelocity: CGVector {
        _ = physicsBody?.velocity
        return (_previousVelocity.first ?? CGVector.zero)!
    }
    
    override var physicsBody: SKPhysicsBody? {
        get {
            if !_previousVelocity.contains(super.physicsBody?.velocity) {
                _previousVelocity.append(super.physicsBody?.velocity)
                _previousVelocity = _previousVelocity.suffix(2)
            }
            return super.physicsBody
        }
        set {
            super.physicsBody = newValue
        }
    }
}

从我最初的测试来看,这似乎到目前为止有效:

let subNode = SubNode()
subNode.physicsBody = SKPhysicsBody()
subNode.physicsBody?.velocity = CGVector(dx: 10, dy: 10)
subNode.physicsBody?.velocity = CGVector(dx: 0, dy: 0)
//true: subnode.previousVelocity == CGVector(dx: 10, dy: 10)

更新:

我发现这个解决方案的一个问题是,当 ObjectClass() 中的对象首先创建为自己的变量,然后直接通过变量进行更改时,子类的 getter 将不会被触发,直到通过子类访问它。就我而言,这不是问题,但绝对不理想。

let subClass = SubClass()

let object = ObjectClass()

subClass.object = object

// This won't trigger the getter obviously since the subclass is not accessed.
object.name = "New Name"
object.name = "Another Name"
于 2021-01-24T15:45:23.297 回答