你如何在自定义类中获得GameScene的frame.width?

Tro*_*y R 3 sprite-kit swift

我在尝试将GameScene 的frame.width变成自定义类时遇到了麻烦,因为我需要在我的自定义类init中定位节点的场景宽度.

HudController.swift片段

import SpriteKit

    class HudController:SKNode {
        var width:CGFloat

        override init(){
            width = GameScene().frame.width //I was hoping to add the scene width here
        }
    }
Run Code Online (Sandbox Code Playgroud)

下面的代码崩溃了,我尝试了其他大量的解决方案但没有成功.

有人可以帮我解决这个问题吗?

谢谢!

更新的代码===

GameScene.swift

import SpriteKit

class GameScene: SKScene {
    var hud = HudController(gameScene: self) 
    // set as global because I'm using it to also call hud functions in my game

}
Run Code Online (Sandbox Code Playgroud)

HudController.swift

import SpriteKit

class HudController:SKNode {

    var width:CGFloat

    init(gameScene:SKScene){
        width = gameScene.size.width
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
Run Code Online (Sandbox Code Playgroud)

Luc*_*tti 7

SpriteKit中的每个节点都可以使用scene属性检索它所在的场景.

let node = SKNode()
node.scene
Run Code Online (Sandbox Code Playgroud)

scene属性返回a SKScene?,该值是可选的,因为如果当前节点不属于某个场景,当然也没有要检索的场景.

现在,您可能想self.scene在您的初始化程序中使用该属性HudController.

class HudController: SKNode {
    var width:CGFloat

    override init() {
        super.init() //  error: property 'self.width' not initialized at super.init call
        width = self.scene!.frame.width
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
Run Code Online (Sandbox Code Playgroud)

但它现在可以工作,因为super.init在初始化width属性之前无法调用.

好的,那你可以尝试一下.

class HudController: SKNode {
    var width:CGFloat

    override init() {
        width = self.scene!.frame.width // error: use of 'self' in property access 'scene' before super.init initializes self

        super.init()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
Run Code Online (Sandbox Code Playgroud)

再次编译错误,因为您self在调用之前使用super.init().

最后还有另一个问题,当执行初始化程序时,正在创建的节点还没有父节点,因此该self.scene属性确实返回nil.

怎么解决这个?

首先声明你初始化器接收一个GameScene.

class HudController: SKNode {
    var width: CGFloat

    init(gameScene:SKScene) {
        width = gameScene.frame.width
        super.init()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,当你创建这个对象时(我希望你是从场景或已经添加到场景中的节点进行的,否则我们遇到了麻烦)你只需要写

class Foo : SKNode {

    func foo() {
        guard let scene = self.scene else { return }
        let controller = HudController(gameScene: scene)
    }
}
Run Code Online (Sandbox Code Playgroud)

另一方面,如果你从你的场景创建HudController你只需写:

class MyScene : SKScene {

    override func didMoveToView(view: SKView) {
        super.didMoveToView(view)
        let controller = HudController(gameScene: self)
    }
}
Run Code Online (Sandbox Code Playgroud)

而已.

更新

如果你想在GameScene里面有一个HudController的实例属性,这就是代码.

class HudController: SKNode {
    var width: CGFloat

    init(gameScene:SKScene) {
        width = gameScene.frame.width
        super.init() // <-- do not forget this
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

class GameScene: SKScene {
    var hud : HudController?

    override func didMoveToView(view: SKView) {
        super.didMoveToView(view)
        hud = HudController(gameScene: self)
    }
}
Run Code Online (Sandbox Code Playgroud)