1

I'm coding a game where when the user loses I want there to be a reset button in the middle of the screen with the rest of it dimmed out. For some reason I can't get transparency to work. I've looked up solutions but couldn't get it to work with mine (there are too many variables that aren't defined) and I can't comment because I don't have enough rep:

Making a SKScene's background transparent not working... is this a bug?

I have a gamescene that extends SKScene where I add all of my SKNodes to a mainView node. I've tried setting the transparency to YES and adding a new skscene with clearColor on top of it but it just shows a black screen:

SKView *dimView = [[SKView alloc] initWithFrame:self.frame];
[self.view addSubview:dimView];
[dimView setBackgroundColor:[UIColor clearColor]];
[dimView setAllowsTransparency:YES];

I know I'm doing something wrong I just don't know what it is. Can anyone pinpoint my mistake?

Update:

I've also tried this and it doesn't work either, also black screen:

CGRect screenRect = [[UIScreen mainScreen] bounds];
//create a new view with the same size
UIView* coverView = [[UIView alloc] initWithFrame:screenRect];
// change the background color to black and the opacity to 0.6
coverView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.6];
// add this new view to your main view
[self.view addSubview:coverView];

Update 2:

I've edited the first code set to try to overlay the skview with another skview whose transparency is set to true and color is set to clear color. This way I just get a gray screen. I've been at this for a while and really can't seem to figure out why this isn't working. Any help would be appreciated.

Update 3:

So I think the correct implementation of overlaying a view with another is like so but even with this it still shows a completely black screen:

    CGRect screenFrame = [UIScreen mainScreen].bounds;
    SKView *dimView = [[SKView alloc] initWithFrame:screenFrame];
    SKScene *currentScene = [[SKScene alloc]initWithSize:dimView.bounds.size];
    [self.view addSubview:dimView];
    [currentScene setBackgroundColor:[[UIColor clearColor] colorWithAlphaComponent:0.5f]];
    [dimView setAllowsTransparency:YES];
    [dimView presentScene:currentScene];
Community
  • 1
  • 1
Minimi
  • 921
  • 10
  • 29

2 Answers2

0

According to overview section of the SKScene Class Reference:

An SKScene object represents a scene of content in Sprite Kit. A scene is the root node in a tree of Sprite Kit nodes (SKNode). These nodes provide content that the scene animates and renders for display. To display a scene, you present it from an SKView object.

You do not nest SKScene 's. You can't have two scenes running at the same time (only transitioning between them).

If you want to "overlaying" two scenes you always have to switch from using a transition.

An alternative could be a GitHub project to customize transition scene with shaders called SpriteKitShaderTransitionExample

As you can see from the sources below, it's extended the SKScene to integrate the shader.

Source:

//private let totalAnimationDuration = 1.0
private let kNodeNameTransitionShaderNode = "kNodeNameTransitionShaderNode"
private let kNodeNameFadeColourOverlay = "kNodeNameFadeColourOverlay"
private var presentationStartTime: CFTimeInterval = -1
private var shaderChoice = -1

extension SKScene {
    private var transitionShader: SKShader? {
        get {
            if let shaderContainerNode = self.childNodeWithName(kNodeNameTransitionShaderNode) as? SKSpriteNode {
                return shaderContainerNode.shader
            }
            return nil
        }
    }
    private func createShader(shaderName: String, transitionDuration: NSTimeInterval) -> SKShader {
        var shader = SKShader(fileNamed:shaderName)
        var u_size = SKUniform(name: "u_size", floatVector3: GLKVector3Make(Float(UIScreen.mainScreen().scale * size.width), Float(UIScreen.mainScreen().scale * size.height), Float(0)))
        var u_fill_colour = SKUniform(name: "u_fill_colour", floatVector4: GLKVector4Make(131.0 / 255.0, 149.0 / 255.0, 255.0 / 255.0, 1.0))
        var u_border_colour = SKUniform(name: "u_border_colour", floatVector4: GLKVector4Make(104.0 / 255.0, 119.0 / 255.0, 204.0 / 255.0, 1.0))
        var u_total_animation_duration = SKUniform(name: "u_total_animation_duration", float: Float(transitionDuration))
        var u_elapsed_time = SKUniform(name: "u_elapsed_time", float: Float(0))
        shader.uniforms = [u_size, u_fill_colour, u_border_colour, u_total_animation_duration, u_elapsed_time]
        return shader
    }
    func presentScene(scene: SKScene?, shaderName: String, transitionDuration: NSTimeInterval) {
        // Create shader and add it to the scene
        var shaderContainer = SKSpriteNode(imageNamed: "dummy")
        shaderContainer.name = kNodeNameTransitionShaderNode
        shaderContainer.zPosition = 9999 // something arbitrarily large to ensure it's in the foreground
        shaderContainer.position = CGPointMake(size.width / 2, size.height / 2)
        shaderContainer.size = CGSizeMake(size.width, size.height)
        shaderContainer.shader = createShader(shaderName, transitionDuration:transitionDuration)
        self.addChild(shaderContainer)
        // remove the shader from the scene after its animation has completed.
        let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(transitionDuration * Double(NSEC_PER_SEC)))
        dispatch_after(delayTime, dispatch_get_main_queue(), { () -> Void in
            var fadeOverlay = SKShapeNode(rect: CGRectMake(0, 0, self.size.width, self.size.height))
            fadeOverlay.name = kNodeNameFadeColourOverlay
            fadeOverlay.fillColor = SKColor(red: 131.0 / 255.0, green: 149.0 / 255.0, blue: 255.0 / 255.0, alpha: 1.0)
            fadeOverlay.zPosition = shaderContainer.zPosition
            scene!.addChild(fadeOverlay)
            self.view!.presentScene(scene)
        })
        // Reset the time presentScene was called so that the elapsed time from now can
        // be calculated in updateShaderTransitions(currentTime:)
        presentationStartTime = -1
    }
    func updateShaderTransition(currentTime: CFTimeInterval) {
        if let shader = self.transitionShader {
            let elapsedTime = shader.uniformNamed("u_elapsed_time")!
            if (presentationStartTime < 0) {
                presentationStartTime = currentTime
            }
            elapsedTime.floatValue = Float(currentTime - presentationStartTime)
        }
    }
    // this function is called by the scene being transitioned to when it's ready to have the view faded in to the scene i.e. loading is complete, etc.
    func completeShaderTransition() {
        if let fadeOverlay = self.childNodeWithName(kNodeNameFadeColourOverlay) {
            fadeOverlay.runAction(SKAction.sequence([SKAction.fadeAlphaTo(0, duration: 0.3), SKAction.removeFromParent()]))
        }
    }  
}
Alessandro Ornano
  • 34,887
  • 11
  • 106
  • 133
  • I don't necessarily want to overlay two scenes, what I actually want is to overlay a view with another view where the view on top is a black color with a .5-.6 opacity. This is to give the background a dimmed out effect when the user loses the game. With the code above I wasn't able to achieve this as the overlaying scene is always opaque. – Minimi Jul 27 '16 at 15:41
  • I don't understand you, what do you mean? You must distinguish UIKit from Sprite-kit, so what are you actually get? – Alessandro Ornano Jul 27 '16 at 16:03
  • 1
    Sorry for the confusion, I've attempted to overlay my SKScene with a different SKView but this doesn't seem to work, it isn't transparent. I've also attempted to overlay my SKScene with a UIView but this also isn't transparent. What I want is for my SKScene nodes to be visible through another view or scene, I don't really care which. The effect I'm looking for is a dimmed effect for my originial scene. – Minimi Jul 27 '16 at 16:06
0

I FINIALLY FIGURED IT OUT! My problem was that I had my code in the update method and wasn't checking to see if it was already added. I was adding multiple views every iteration of the update loop all with an opacity of .5 which caused it to seem black.

Minimi
  • 921
  • 10
  • 29