Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change SKView letterbox color when scaleMode .AspectFit is used

I'm using standard full screen SpriteKit view from the boilerplate code (new game iOS project), and when I use

scene.scaleMode = .AspectFit

to make sure that scene fits, remaining (letterboxed) area is colored in black.

I've tried these options to change the color:

let skView = self.view as SKView

// was hoping this one would work
skView.backgroundColor = UIColor.redColor()

// didn't expect this would work, since scene is scaled anyways
scene.backgroundColor = SKColor.redColor()

Also tried to change SKView background color in storyboard editor to another color, but no luck.

Any tips on where to look to change the color of the letterboxed area?

like image 602
Rudi Avatar asked Sep 02 '14 22:09

Rudi


2 Answers

I think the should be a way to set the colour or place sprites in the ears of the letterhead... but it seems that there isn't. Also, I disagree with LearnCocos2D. There's nothing wrong with AspectFit. It has its use.

What I've done is use AspectFit but also calculate the size of the scene based on screen size. This isn't that helpful for an OSX game but it'll work fine for iOS.

func createScene() -> GameScene {
    let screenSize  = UIScreen.mainScreen().bounds.size
    var size:CGSize = CGSizeZero

    size.height = Constants.sceneHeight
    size.width  = screenSize.width * (size.height / screenSize.height);


    return GameScene(size: size)
}

override func viewDidLoad() {
    super.viewDidLoad()

    let scene = self.createScene()

    // Configure the view.
    let skView = self.view as SKView
    skView.showsFPS = false
    skView.showsNodeCount = false

    /* Sprite Kit applies additional optimizations to improve rendering performance */
    skView.ignoresSiblingOrder = true

    /* Set the scale mode to scale to fit the window */
    scene.scaleMode = .AspectFit

    skView.presentScene(scene)
}
like image 176
AutomatonTec Avatar answered Nov 06 '22 00:11

AutomatonTec


After a scene is rendered, its contents are copied into the presenting view. If the view and the scene are the same size, then the content can be directly copied into the view. If the two differ, then the scene is scaled to fit in the view. The scaleMode property determines how the content is scaled.

The letterboxing is create IN the view so there is no way around it. That said there is often the need for an .aspectFit setting if you want to use a specific scene size and universal coordinate system. If that is your case, the following should help.

You need to figure out how much a standard .aspectFit would need in padding to remove the letter boxing from your current device and add that to your scene. You finish with a scene that is lighter a little bigger or a little wider then your original sizes but the scene has at least the same size as your original scene size. You can then move the anchorPoint to the original (0, 0) coordinates or the (0.5, 0.5) one depending on what coordinate system you want to use for your game.

The code for this is convoluted and could change in time. If you want a quick fix, I created a Framework exactly for that purpose. It's small but portable :)

https://github.com/Tokuriku/tokuriku-framework-stash

Just:

  1. Download the ZIP file for the Repository
  2. Open the "SceneSizer" sub-folder
  3. Drag the SceneSizer.framework "lego block" in your project
  4. Make sure that the Framework in Embedded and not just Linked
  5. Import the Framework somewhere in your code import SceneSizer

And you're done, you can now call the sizer Class with: SceneSizer.calculateSceneSize(#initialSize: CGSize, desiredWidth: CGFloat, desiredHeight: CGFloat) -> CGSize

Documentation is in the folder for a clean and full use with a standard scene. Hope this helps!

like image 36
Tokuriku Avatar answered Nov 05 '22 22:11

Tokuriku