user1763430
user1763430

Reputation: 77

Swift - Adding background image behind a Sprite Kit Scene in View Controller

I am trying to add a background image in my view controller so my sprite kit game scenes can be in the foreground. It's important for me for my background image to stay on screen while the game scenes transition to each other. The problem I am having is how to place the subview I created for my background to be behind my skscene, at the moment my background image is in front of my game scene and all you can see is the image sendSubviewToBack doesn't seem to work. The following is my viewDidLoad Thanks

import UIKit
import SpriteKit

class GameViewController: UIViewController {

    override func viewDidLoad() {

        super.viewDidLoad()
        let scene = MainMenuScene(size: CGSize(width: 1536, height: 2048))
        let skView = self.view as! SKView

        scene.scaleMode = .AspectFill
        skView.presentScene(scene)

        let backgroundImageView = UIImageView(image: UIImage(named: "bg.jpg"))
        backgroundImageView.frame = view.frame
        backgroundImageView.contentMode = .ScaleAspectFill
        view.addSubview(backgroundImageView)
        view.sendSubviewToBack(backgroundImageView)

    }
}

Upvotes: 2

Views: 5786

Answers (5)

Roberto Moctezuma
Roberto Moctezuma

Reputation: 54

I dealt with the same issue, and here is how to fix it:

  1. Put the code in viewWillLayoutSubviews(), not in viewDidLoad() - this will ensure you have access to all the view's properties.
  2. Don't cast the self.view as an SKView, leave it as an UIView and instead create two child views: one for the background image and one for the SKScene

Here is the corrected code:

var skView : SKView? = nil

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()

    if (skView == nil) {
        let backgroundImageView = UIImageView(image: UIImage(named: "bg.jpg"))
        view.addSubview(backgroundImageView)

        skView = SKView(frame: CGRect(origin: CGPointZero, size: CGSize(width: 1536, height: 2048)))
        skView!.ignoreSiblingOrder = true
        let scene = MainMenuScene(size: CGSize(width: 1536, height: 2048))
        scene.scaleMode = .AspectFill

        view.addSubView(skView!)
        skView!.presentScene(scene)
    }
}

My particular reason to do this was so I could have a game that would be playable on both iPhones and iPads without aspect ratio distortion. The 'playable area' is always 16:9, and when seen on an iPad, you see a background image that extends to the sides of the playable area.

What I did was to load a background image meant for the iPad (which has an aspect ratio of 4:3), defined the skView to have an aspect ratio of 16:9 (So instead of 1536/2048 I am using 750/1334, for example) and set the scene's scaleMode to .AspectFit. When seen on an iPhone, the scene covers the background completely. When seen on an iPad, you can see the background image complement the sides of the playable area.

Hope this helps!

Upvotes: 2

Aryaman Goel
Aryaman Goel

Reputation: 538

Make a SKSpriteNode with the background texture!

background.size = self.frame.size //Make the background as big as the screen

Upvotes: 1

Epic Byte
Epic Byte

Reputation: 33968

What you're describing can't be done with UIKit because your view can't be visible behind the SKView which renders your scene.

In iOS 8+ you can use the SKView's allowsTransparency property. Documentation states:

This property tells the drawing system as to how it should treat the view. If set to NO, the drawing system treats the view as fully opaque, which allows the drawing system to optimize some drawing operations and improve performance. If set to YES, the drawing system composites the view normally with other content. The default value of this property is NO.

But in my opinion this is not the best solution. The best solution is to use Sprite Kit, but the problem is you can't preserve nodes across scenes. You must add the node again during each scene transition. This is why I do not use Apple's scene transitions the way the documentation describes. Instead I use my own custom SKNodes and make my own custom transitions using those nodes, which I highly recommend you do. I gave a detailed answer about this here

Upvotes: 2

Rod
Rod

Reputation: 779

You can use insertSubView: instead of addSubView and specify the index, which determines z-order of views. A view with a higher index lies above those with lower indices.

Upvotes: 0

LinusG.
LinusG.

Reputation: 28982

Generally UI elements are placed on top of each other depending on the order they were added to the view.

If you want to customize that you can use the property .layer.zPosition which is any value you pick. The lowest value is in the very back while the highest one is on top.

Hope that helps :)

Upvotes: 0

Related Questions