简体   繁体   中英

Change Node Positioning Depending on Screen Size Swift/Sprite Kit

I want to change to positioning of my nodes depending on the size of the screen. For example, when I run my app on an iPhone 4s, not all of the nodes fit on the screen, since I developed the app with iPhone 6 dimensions in mind. How can I make it so the nodes reposition themselves depending on which device it's running on? I know I can achieve this with constraints normally, but I don't know how to do that in Sprite Kit. I have included a screen shot down below.

    lblRocketCount.position = CGPoint(x: 100, y: 150)
    lblRocketCount.text = "Bullets: 30"
    self.addChild(lblRocketCount)

    lblMissileCount.position = CGPoint(x: -100, y: 150)
    lblMissileCount.text = "Missiles: 5"
    self.addChild(lblMissileCount)


    leftBorder.position = CGPoint(x: -333, y: 0)
    self.addChild(leftBorder)

    rightBorder.position = CGPoint(x: 333, y: 0)
    self.addChild(rightBorder)

    topBorder.position = CGPoint(x: 0, y: 187)
    self.addChild(topBorder)

    bottomBorder.position = CGPoint(x: 0, y: -187)
    self.addChild(bottomBorder)

    buttonDirUp.position = CGPoint(x: -200, y: -50)
    buttonDirUp.setScale(2.0)
    self.addChild(buttonDirUp)

    ship.setScale(0.33)
    shootButton.setScale(0.7)
    missileButton.setScale(0.5)


    buttonDirLeft.position = CGPoint(x: -250, y: -100)
    buttonDirLeft.setScale(2.0)
    self.addChild(buttonDirLeft)

    buttonDirDown.position = CGPoint(x: -200, y: -150)
    buttonDirDown.setScale(2.0)
    self.addChild(buttonDirDown)

    buttonDirRight.position = CGPoint(x: -150, y: -100)
    buttonDirRight.setScale(2.0)
    self.addChild(buttonDirRight)

    self.view?.multipleTouchEnabled = true

    self.backgroundColor = SKColor.blackColor()

    self.anchorPoint = CGPointMake(0.5, 0.5)

    self.addChild(base)
    base.position = CGPointMake(200, -100)

    self.addChild(ball)
    ball.position = base.position

    self.addChild(ship)
    ship.position = CGPoint(x: self.frame.midX, y: self.frame.midY)

    self.addChild(shootButton)
    shootButton.position = CGPoint(x: self.frame.midX, y: -100)

    self.addChild(missileButton)
    missileButton.position = CGPoint(x: -200, y: 50)

Screen Shot

This is a technique that I've found to be effective for dealing with multiple resolutions. You'll need to create two global variables in your GameViewController that reflect the size of the current view:

import SpriteKit


// global variables
var SKViewSize: CGSize?
var SKViewSizeRect: CGRect?


class GameViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let skView = self.view as! SKView
        SKViewSize = skView.bounds.size
        let scene = GameScene(size: SKViewSize!)

        scene.scaleMode = .AspectFill
        skView.presentScene(scene)
        SKViewSizeRect = getViewSizeRect()
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        SKViewSize = self.view.bounds.size
        SKViewSizeRect = getViewSizeRect()

        let skView = self.view as! SKView
        if let scene = skView.scene {
            if scene.size != self.view.bounds.size {
                scene.size = self.view.bounds.size
            }
        }
    }

    func getViewSizeRect() -> CGRect {
        return CGRect(x: ((SKViewSize!.width  * 0.5) * -1.0), y: ((SKViewSize!.height * 0.5) * -1.0), width: SKViewSize!.width, height: SKViewSize!.height)
    }
}

Then create an extension for all SKNode types that allows you to position them using a percentage of the current screen size:

public extension SKNode {

    public func posByScreen(x: CGFloat, y: CGFloat) {
        self.position = CGPoint(x: CGFloat((SKViewSizeRect!.width * x) + SKViewSizeRect!.origin.x), y: CGFloat((SKViewSizeRect!.height * y) + SKViewSizeRect!.origin.y))
    }
}

For example, to create a sprite node and center it on any screen size, you'd use this in your GameScene :

let sprite = SKSpriteNode(color: SKColor.whiteColor(), size: CGSizeMake(32, 32))
addChild(sprite)
sprite.posByScreen(0.5, y: 0.5)

There is no easy answer to what you are looking for, you first need to decide what your game should be like at the different aspect ratios, and plan around that. In a lot of cases, you want to just give the 16:9 phones more FOV (They can see more of the game world). To do this, design your game with 2 layers: a game layer, and a hud overlay.

The game layer will utilize .AspectFill to keep your game the same "size" across devices, with the iPhone 4s folk losing the ability to see some of the screen above and below them (You can adjust where they lose some of the screen by moving the game layer nodes position)

The HUD overlayer will handle the things that need to stay at a fixed position on screen, like buttons and life bars. Now you can use the % based coordinates like some people have mentioned, or you can keep the absolute coordinates, and just add/subtract the pixel difference from your overlay nodes if your game detects a 3:2 (or 4:3 if you want iPad) ratio

Basic principle: (Do not copy verbatum)

Lets say we create a game scene that is 160x284 points

This means on an iphone 4s our resolution is 320x480, aspect fill is going to take the smallest of the distance between top/bottom or left/right and scale to that. In our case 160 is going to scale to 320, 284 is going to scale to 568. Uh oh, iphone only has 480, so you are losing out on 88 pixels, which means in the game world we are losing 44 points.

//This means that the top and bottom will lose out on 22 points each, so lets make that our iphone4s padding

class GameScene
{
  let gameNode = SKNode();
  let overlayNode = SKNode();
  let iPhone4sPadding = 22;
  func init()
  {
     //add all of the games nodes that you would add to the scene to gameNode instead
      self.addChild(gameNode);

     //add all of your overlay nodes (buttons, lifebars, etc) to the overlayNode

     //do a check on uiscreen to see if the height is 480, if it is
     //  all nodes on the bottom add iphone4spadding to the y
     //  all nodes on the top subtract iphone4spadding from the y
     self.addChild(overlayNode);

  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM