1
votes

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];
2

2 Answers

0
votes

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()]))
        }
    }  
}
0
votes

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.