3

In Sprite Kit, I'm using an SKCameraNode to zoom in and out of an SKScene. Any SKLightNodes in the scene are not zoomed at all. They are not children of the Camera so should not be invariant. Can't find anything on this - Search "SKLightNode SKCameraNode" on SO yields 0 results.

Using Xcode 8.3.3 and starting from a basic Game/Swift project, I have replaced sceneDidLoad() in GameScene.swift with:

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)

}

As you can see, the light stays the same during the zooms.

In an attempt to fix this problem, I've tried the following custom action to modulate the falloff property of the light. It's sort of ok but it's not a faithful zoom.

    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)

Surely the camera should zoom on the light? Am I missing something?

EDIT: following suggestions below here is some code that scales the 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)

You will also need to halve the Camera zoom. The only problem with this is that everything is scaled (even nodes added as children to the CameraNode like scores/buttons).

Christian Cerri
  • 1,233
  • 2
  • 15
  • 19

1 Answers1

2

I would like to thank you for providing an example we can test. By playing around with it, I can definitely see the light growing and shrinking but it is not by much, (it is more noticeable if you move the camera off position (0,0) Perhaps theres a math problem on apples end, or a drawing order priority problem.

I have even attempted to add the SKLightNode to a separate SKNode, and scale the node, but that left the same result.

I also attempted to resize the scene to a larger size, and still the same result.

I then decided to play with the view size, low and behold I was able to get different results when I adjusted this. This means that SKLightNode goes off of the SKView size, and not the SKScene size (Really apple?). Either that or it goes off of the context that the SKView provides. Either way, looks like you are not zooming with SKLightNode. (Btw, the shadow still zooms, so perhaps you just need to work in a better lighting affect?)

Knight0fDragon
  • 16,609
  • 2
  • 23
  • 44
  • Thanks! I don't really want to change the SKView size as this will change sprites and other nodes, won't it? Also not using shadows. SKCamera is good and easy to use for zoom effects but it is annoying that lighting is 'left out'. My workaround is acceptable-ish but still a hack. – Christian Cerri Jun 12 '17 at 03:30
  • 1
    I do not know if changing the view dynamically is even an option, it would produce some artifacts I will tell you that, but no everything will stay the same size if the view is aspect fill and the scene is aspect fill – Knight0fDragon Jun 12 '17 at 03:33
  • you *can* change the view! Thankfully that frame is editable! `view!.frame.size.height += 2500` totally works @ChristianCerri – Fluidity Jun 12 '17 at 03:44
  • Ok if it works then that is a workaround, but damn is that an ugly work around – Knight0fDragon Jun 12 '17 at 03:46
  • Yes, changing the view.frame works and the light is scaled correctly... BUT you can't use SKCameraNode, which is needed to have invariant nodes. I think varying the falloff, whilst not perfect, is perhaps the best workaround. – Christian Cerri Jun 12 '17 at 04:02
  • The answer I am really looking for is how to make SKCameraNode and SKLightNode play nice together... Otherwise sounds like a bug report is in order. – Christian Cerri Jun 12 '17 at 04:04
  • You can use SKCameraNode, you just need to scale both at the same time – Knight0fDragon Jun 12 '17 at 04:05
  • Oh it is def a bug if Fluidity tested the size and it worked. I would file a report (of course they will just tell you to f off in a polite way) – Knight0fDragon Jun 12 '17 at 04:06
  • Yes, I can confirm you can vary view.frame and use SKCameraNode together. However, any children of the camera (which should stay invariant) are scaled by the view.frame changes. – Christian Cerri Jun 12 '17 at 04:09
  • 1
    I will play with this some more tomorrow, sounds like the scaling is not doing its job – Knight0fDragon Jun 12 '17 at 04:11
  • 1
    @ChristianCerri so I haven't played around with any of this yet, but you could do an old fashioned camera that may work better with your project. Basically you just make a "world" node and move it around. There was a guide on doing that somewhere I can't find it now though. It's a basic 2d camera though from 10-20 years ago. – Fluidity Jun 12 '17 at 13:17
  • 1
    @Fluidity, he wants to do scaling though, I have attempted to try old school camera, did not work. (My first attempt is this method) – Knight0fDragon Jun 12 '17 at 13:18
  • @ChristianCerri, I have been playing around this morning, I was able to get the view to resize, but the SKScene does not scale with the view, not sure if you or Fluidity were able to get the scene to "resize" with the view. (I put the resize in quotes because I expect the pixel size to be larger, but the point size to stay the same) – Knight0fDragon Jun 12 '17 at 13:21
  • KoD, I meant old school + view frame scaling. Does that not make a difference compared to the CamNode? – Fluidity Jun 12 '17 at 13:21
  • "_I was able to get the view to resize, but the SKScene does not scale with the view_" and can't you just manually scale the scene along with the view? – Fluidity Jun 12 '17 at 13:23
  • 1
    The old school method was to just take a node and pan/scale it, not to use `SKCameraNode`. You pretty much worked in the opposite direction of the `SKCameraNode`, so for example, if you shift the camera 10 points left, you would have to shift the node 10 points right – Knight0fDragon Jun 12 '17 at 13:23
  • @Fluidity, he wants everything to stay the same size, this requires we use `aspectFill` methods. Resizing the scene would make things go smaller, which is more work on the processor to scale it back to size. – Knight0fDragon Jun 12 '17 at 13:25
  • I wonder if recreating the light / camera node after scaling would have any effect? – Fluidity Jun 12 '17 at 13:27
  • @Fluidity, +KoD, thanks for good suggestions. The worldNode idea is good I will try it as I already use it for pausing (don't pause the SKScene!!!). Fundamentally: you have a game with zoomable bits (e.g. sprites) and non-zoomable bits (e.g. scores/buttons). SKCamera handles this well; resizing the view changes the non-zoomable bits as well. Maybe resizing worldNode will work... but then you would need to work around for invariants not added to worldNode. Basically it's getting very complicated and not worth it when modulating .falloff works ok. I just wanted to know if I was missing something – Christian Cerri Jun 12 '17 at 13:38
  • @ChristianCerri I'm trying to get your code to work but I keep getting a random metal error from the lightnode when it's added. sigh. – Fluidity Jun 12 '17 at 13:41
  • @Fluidity best run on a device, simulator is crap with lights... maybe Xcode 9 will fix this! – Christian Cerri Jun 12 '17 at 13:42
  • @ChristianCerri haha, I ran it on a mac device :) I always use OSX spritekit builds and runs much faster for my machine at least. Trying it on ios now – Fluidity Jun 12 '17 at 13:43
  • 1
    I didnt even think to try it on a real device LOL – Knight0fDragon Jun 12 '17 at 13:44
  • @ChristianCerri I wouldn't bet on it. SK got nothing but ARKit it seems this year. – Fluidity Jun 12 '17 at 13:44
  • @ChristianCerri I just posted this on the SKAlliance slack so maybe you will get some more eyes on this. Could be bounty worhty as well – Fluidity Jun 12 '17 at 13:46
  • definitely not pro, just an avid developer. Trying to find a way to get this scene to "resize" when the view resizes, otherwise it is going to make some of my iPad development ideas a little disappointing in the future. – Knight0fDragon Jun 12 '17 at 13:48
  • added some view scaling code to the original question - works OK but can't handle invariant nodes (children if SKCamera) like scores – Christian Cerri Jun 12 '17 at 13:48
  • @ChristianCerri ok your code works fine on iOS. if you are planning to port to macOS then you should know it is crashing :) – Fluidity Jun 12 '17 at 13:48
  • @Fluidity sorry dude MacOS is dead to me, but thanks – Christian Cerri Jun 12 '17 at 13:48
  • @ChristianCerri @ KoD resetting the lightnode and manually changing its scale as a `.run()` didn't do anything =/ – Fluidity Jun 12 '17 at 13:56