Sunday, 15 June 2014

XCode 5 versus XCode 6 default generated Game (Sprite Kit) project and scene sizes

As a way to learn about Swift I've been trying to write a simple game using Sprite Kit. My initial plan was to just allow a ball to be dragged around the screen and ensure it was constrained by the screen edges. This was a little harder than originally envisioned. This was partly because the default Game project generated by Xcode 6 is slightly different to that generated by Xcode 5 and so none of the existing Sprite Kit tutorials referred to this area.

My main issue was that I could move the ball around and when the drag finished the ball was endowed with velocity so it travelled after release and despite writing some simple code to ensure if the additional travel would take it off the screen this would bound it.

func boundPosToScene(newPos : CGPoint) -> CGPoint
{
  var retVal
  let radius = ball.size.width / 2

  if newPos.xradius < 0
  {
    retVal.xradius
  }

  if newPos.xradius > self.size.width
  {
    retVal.x = self.size.widthradius
  }

  if newPos.yradius < 0
  {
    retVal.yradius;
  }

  if newPos.yradius > self.size.height
  {
    retVal.y = self.size.heightradius
  }

  return retVal;

}

Where ball is a member variable of the class containing this method that is an instance of SKSpriteNode.

Despite this the ball kept disappearing. Reading various online articles, tutorials & StackOverflow posts there seemed to be an issue with Sprite Kit projects always starting up in landscape mode. When I added some debug to this statement (& else where), i.e.


println("view.bounds\(view.bounds), self.frame:\(self.frame), self.size:\(self.size)")

I got:

view.bounds(0.0,0.0,320.0,568.0), scene:(0.0,0.0,1024.0,768.0), scene.size:(1024.0,768.0)

OK. The view looks good but the scene is in landscape and even if orientated to portrait it's a lot larger than the actual view. But why? There were lots of posts about the landscape issues but nothing about the non-aligned size with Xcode 5. Well, a quick test by generating projects with 5 & 6 (NOTE: I'm new to Sprite Kit as well as Swift so I hadn't used it with 5) shows that the generated 'Game' Xcode 5 projects programmatically creates a scene that is sized to the view:

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Configure the view.
    SKView * skView = (SKView *)self.view;
    skView.showsFPS = YES;
    skView.showsNodeCount = YES;
    
    // Create and configure the scene.
    SKScene * scene = [MyScene sceneWithSize:skView.bounds.size];
    scene.scaleMode = SKSceneScaleModeAspectFill;
    
    // Present the scene.
    [skView presentScene:scene];
}

whereas with XCode 6 it uses an SKS file (called GameScene):

override func viewDidLoad() {
  super.viewDidLoad()

  if let scene = GameScene.unarchiveFromFile("GameScene") as? GameScene {
    // Configure the view.
    let skView = self.view as SKView
    skView.showsFPS = true
    skView.showsNodeCount = true
            
    /* Sprite Kit applies additional optimizations to improve rendering performance */
    skView.ignoresSiblingOrder = true
            
    /* Set the scale mode to scale to fit the window */
    scene.scaleMode = .AspectFill

  }
}

Looking at the GameScene.sks:



You can see that the default scene size is 1024x768, i.e. iPad in landscape mode. Changing this to 320x576 (for iPhone 4 inch) fixes the problem.

NOTE: When making this change make sure you explicitly save the changes. Just modifying the values and building/running the project often seems to result in them being reset. I make sure I navigate away from the Size boxes before pressing Cmd-S.

Of course this is inflexible as it doesn't size to device. As I'd like my app to run on multiple device types I'm probably better of following the Xcode 5 generated code or perhaps just adding re-sizing code once the Scene has been loaded from the SKS file; as I'm not sure what else that gives me.

If you do this. In GameViewController.swift you'll also probably want to change

scene.scaleMode = .AspectFill

to

scene.scaleMode = .ResizeFill

Anyway, this difference in the generated starter apps is something to be aware of & the fact that the initial landscape startup issue reported against Xcode 5 seems to be present though possibly in a different guise. Certainty in the generated app from Xcode 5 it all works fine for me. When I added logging code to display the View and Scene size they were both reported as 320x568.

No comments: