swift SKLightNode未使用SKCameraNode进行缩放

6ioyuze2  于 2023-09-30  发布在  Swift
关注(0)|答案(2)|浏览(102)

在Sprite Kit中,我使用SKCameranode来放大和缩小SKScene。场景中的任何SKLightNode都不会缩放。它们不是相机的子项,因此不应该是不变的。找不到任何关于此的内容-在SO上搜索“SKLightNode SKCameraNode”会产生0个结果。
使用Xcode 8.3.3,从一个基本的Game/Swift项目开始,我将GameScene.swift中的sceneDidLoad()替换为:

override func sceneDidLoad() {

    let cameraNode = SKCameraNode()
    cameraNode.position = CGPoint(x:0.0, y:0.0)
    self.addChild(cameraNode)
    self.camera = cameraNode

    let bg = SKSpriteNode(color:.red, size:self.size)
    bg.lightingBitMask = 0b0001
    self.addChild(bg)

    let lightNode = SKLightNode()
    lightNode.position = CGPoint(x:0.0, y:0.0)
    lightNode.categoryBitMask = 0b0001
    lightNode.lightColor = .white
    lightNode.falloff = 1.0
    self.addChild(lightNode)

    let zoomDuration:TimeInterval = 10.0
    let zoomAction = SKAction.sequence([
        SKAction.scale(to:0.25, duration:zoomDuration),
        SKAction.scale(to:1.0, duration:zoomDuration)
        ])
    self.camera?.run(zoomAction)

}

如您所见,在缩放过程中灯光保持不变。
为了解决这个问题,我尝试了以下自定义操作来调节灯光的衰减属性。这是一种确定的,但它不是一个忠实的变焦。

let lightAction1 = SKAction.customAction(withDuration: zoomDuration) {
        (node, time) -> Void in
        let lightNode = node as! SKLightNode
        let ratio:CGFloat = time / CGFloat(zoomDuration)
        let startFalloff:CGFloat = 1.0
        let endFalloff:CGFloat = 0.25
        let falloff:CGFloat = startFalloff*(1.0-ratio) + endFalloff*ratio
        lightNode.falloff = falloff
    }
    let lightAction2 = SKAction.customAction(withDuration: zoomDuration) {
        (node, time) -> Void in
        let lightNode = node as! SKLightNode
        let ratio:CGFloat = time / CGFloat(zoomDuration)
        let startFalloff:CGFloat = 0.25
        let endFalloff:CGFloat = 1.0
        let falloff:CGFloat = startFalloff*(1.0-ratio) + endFalloff*ratio
        lightNode.falloff = falloff
    }
    let lightSequence = SKAction.sequence([lightAction1, lightAction2])
    lightNode.run(lightSequence)

摄像机应该放大光线吧?我是不是漏了什么?
编辑:下面的建议是一些缩放SKView的代码:

let originalWidth:CGFloat = UIScreen.main.bounds.width
    let originalHeight:CGFloat = UIScreen.main.bounds.height

    let lightAction1 = SKAction.customAction(withDuration: zoomDuration) {
        (node, time) -> Void in
        let ratio:CGFloat = time / CGFloat(zoomDuration)
        let startFalloff:CGFloat = 1.0
        let endFalloff:CGFloat = 1.5
        let falloff:CGFloat = startFalloff*(1.0-ratio) + endFalloff*ratio
        self.view?.frame = CGRect(x: (originalWidth-originalWidth*falloff)/2.0, y: (originalHeight-originalHeight*falloff)/2.0, width: originalWidth*falloff, height: originalHeight*falloff)
    }
    let lightAction2 = SKAction.customAction(withDuration: zoomDuration) {
        (node, time) -> Void in
        let ratio:CGFloat = time / CGFloat(zoomDuration)
        let startFalloff:CGFloat = 1.5
        let endFalloff:CGFloat = 1.0
        let falloff:CGFloat = startFalloff*(1.0-ratio) + endFalloff*ratio
        self.view?.frame = CGRect(x: (originalWidth-originalWidth*falloff)/2.0, y: (originalHeight-originalHeight*falloff)/2.0, width: originalWidth*falloff, height: originalHeight*falloff)
    }
    let lightSequence = SKAction.sequence([lightAction1, lightAction2])
    lightNode.run(lightSequence)

您还需要将相机变焦减半。唯一的问题是,所有内容都是缩放的(即使是作为子节点添加到CameraNode的节点,如分数/按钮)。

j8ag8udp

j8ag8udp1#

我想感谢你提供了一个我们可以测试的例子。通过摆弄它,我可以肯定地看到光线的增长和收缩,但它不是很多,(如果你把相机移离位置(0,0),它会更明显)也许苹果端有一个数学问题,或者绘图顺序优先级问题。
我甚至尝试将SKLightNode添加到一个单独的SKNode,并缩放该节点,但结果相同。
我还尝试将场景大小调整为更大的大小,结果仍然相同。
然后,我决定发挥与视图大小,低,看我能够得到不同的结果,当我调整这一点。这意味着SKLightNode会偏离SKView大小,而不是SKScene大小(真的是苹果吗?)。或者它脱离了SKView提供的上下文。无论哪种方式,看起来你都没有使用SKLightNode进行缩放。(顺便说一句,阴影仍然缩放,所以也许你只需要在一个更好的照明效果工作?)

kognpnkq

kognpnkq2#

我一直在与这个确切的问题作斗争相当长一段时间,解决方案是您需要随着cameraNode的缩放动态调整两个参数:衰减和亮度。
衰减需要乘以比例的平方根。
亮度需要除以刻度的平方根。
不要问我是怎么做到的,因为我自己也不太确定,但它确实有效,我最终做到了。
为此,我们将SKLightNode子类化(在本例中为DXScalableLightNode),并设置新类以响应相机比例更改时发送的消息。

class DXScalableLightNode: SKLightNode {
    
    var baseFalloff     : CGFloat
    var baseHue         : CGFloat = 0.0
    var baseSaturation  : CGFloat = 1.0
    var baseBrightness  : CGFloat = 0.0
    var baseAlpha       : CGFloat = 0.0

    init(falloff: CGFloat, color: UIColor) {
        color.getHue(&baseHue, saturation: &baseSaturation, brightness: &baseBrightness, alpha: &baseAlpha)
        baseFalloff = falloff
        super.init()
        self.lightColor = color
        NotificationCenter.default.addObserver(self, selector: #selector(scaleDidChange), name: NSNotification.Name.cameraScaleDidChange, object: nil)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    @objc func scaleDidChange(notification: Notification) {
        guard let scale = notification.userInfo?["scale"] as? CGFloat else {
            fatalError("Notification.cameraScaleDidChange received with no scale")
        }
        falloff     = baseFalloff * sqrt(scale)
        lightColor  = UIColor(hue: baseHue, saturation: baseSaturation, brightness: baseBrightness / sqrt(scale), alpha: baseAlpha)
    }
}

我们首先将原始颜色转换为其基本HSBA值并存储它们。
当比例变化时,我们适当地调整衰减和亮度。
所以我们创建了一个新的类,我们初始化一个灯光,如下所示:

let myLight = DXScalableLightNode(falloff: 0.75, color: .white)

下一步是确保您的可扩展光节点获得有关缩放更改的通知。
在您的代码中,每当更改相机比例(例如,作为捏手势的结果)时,您都要执行以下操作:

cameraNode.setScale(newScale)
NotificationCenter.default.post(name: .cameraScaleDidChange, object: self, userInfo: ["scale": newScale])

...它会向场景中的每个DXScalableLightNode发送消息并调整它们,以便正确缩放其照明效果。
请注意,Apple文档中说SKLightNode.falloff应该在0.0...1.0范围内,并且使用大于1.0的falloff确实会稍微破坏一些东西。
我希望你们觉得这个有用。
p.s.这是我第一次在Stack Overflow上发布代码,所以如果我做了任何错误的事情,我道歉。

相关问题