天天看點

SpriteKit遊戲開發适配iPad/iPhone6/7/8/Plus及iPhoneX的尺寸及安全區域

SpriteKit遊戲開發适配iPad/iPhone6/7/8/Plus及iPhoneX的尺寸及安全區域

如何适配不同的iPhone、iPhoneX及iPad的螢幕尺寸,如何适配不同的iPhone、iPhoneX及iPad的螢幕尺寸呢?

我們開發一個App的時候, 通常希望它在 iPhone, iPad, Mac上同時能運作, 尤其是遊戲。

這樣就需要我們考慮不同裝置不同的分辨率,但處理起來比較麻煩,比如說,按照官方的做法,我們需要提供諸如 ifiero@1x,ifiero@2x,ifiero@3x, 這樣不同尺寸的圖檔,那如何簡便的适配裝置不同的分辨率呢,我們的做法是, 固定一個大小, 向下相容不同的裝置。

即場景中的所有圖檔, 都按照螢幕大小為 2048 * 1536 來繪制。 也就是說, 我們的背景圖的大小是 2048 * 1536, 其他圖檔也是依照這個比

SpriteKit遊戲開發适配iPad/iPhone6/7/8/Plus及iPhoneX的尺寸及安全區域

未适配前:Ball球超過螢幕的上下方

SpriteKit遊戲開發适配iPad/iPhone6/7/8/Plus及iPhoneX的尺寸及安全區域

适配後:Ball球就在螢幕的可視範圍内運動了

一、那麼如何适配不同的iPhone、iPhoneX及iPad的螢幕尺寸呢?

我們開發一個App的時候, 通常希望它在 iPhone, iPad, Mac上同時能運作, 尤其是遊戲。

這樣就需要我們考慮不同裝置不同的分辨率,但處理起來比較麻煩,比如說,按照官方的做法,我們需要提供諸如 ifiero@1x,ifiero@2x,ifiero@3x, 這樣不同尺寸的圖檔,那如何簡便的适配裝置不同的分辨率呢,我們的做法是, 固定一個大小, 向下相容不同的裝置。

即場景中的所有圖檔, 都按照螢幕大小為 2048 * 1536 來繪制。 也就是說, 我們的背景圖的大小是 2048 * 1536, 其他圖檔也是依照這個比例來繪制。

為什麼這樣做呢?

我們知道 2048 * 1536 是iPad Retina 的分辨率。也是我們需要适配的裝置裡面分辨率最高的。 是以我們在遊戲中都選擇了這個大小,讓它來相容分辨率低的裝置。 2048 * 1536 在iPad Retina上是完美顯示的。 那在其他裝置上呢? 這裡就要依靠 AspectFill來進行縮放了,代碼如下:

if let scene = GameScene(fileNamed: "GameScene") {
                scene.size = CGSize(width: 2048, height: 1536)
                scene.scaleMode = .aspectFill /// 縮放
                view.presentScene(scene)
 }
           
SpriteKit遊戲開發适配iPad/iPhone6/7/8/Plus及iPhoneX的尺寸及安全區域

不同尺寸的iPhone的螢幕尺寸比例

橙色整體區域表示我們場景的真實大小, 黑色線框内的區域表示場景展示在裝置上的真實大小。

iPad Retina:橙色區域和黑色線框内的區域是完美吻合的,也就是說在裝置上能完整顯示。

iPhone6/7/8/Plus:黑色線框内的區域是2048 * 1152,這邊要注意的是,超出黑色框的内容看不見,設計遊戲時,盡量不要把精靈的Position位置放在位于不可見的區域。

不同尺寸的iPhone的螢幕尺寸比例

裝置 螢幕比例 螢幕比值
iPad Retina 4 / 3 1.33
iPhone 6/7/8 16 / 9 1.77
iPhone 6/7/8 Plus 16 / 9 1.77
iPhone X -- 2.16

iPhoneX的Safe Area為觸發互動行為的區域

SpriteKit遊戲開發适配iPad/iPhone6/7/8/Plus及iPhoneX的尺寸及安全區域

iPhoneX的Safe Area為觸發互動行為的區域

了解了原理後,我們就開始來編寫代碼吧

1.extension拓展UIDevice,判斷裝置是iPhone或者iPhoneX或iPad

import UIKit
import SpriteKit

// iPhone X  375*812(H) @1x
// 豎屏
public let AREA_INSET_HEIGHT_TOP   :CGFloat = (UIScreen.main.bounds.height == 812) ? 44.0 : 0
public let AREA_INSET_HEIGHT_BOTTOM:CGFloat = (UIScreen.main.bounds.height == 812) ? 34.0 : 0
// 橫屏(安全區域)
public let AREA_INSET_WIDTH_TOP    :CGFloat = (UIScreen.main.bounds.width == 812) ? 44.0 : 0
public let AREA_INSET_WIDTH_BOTTOM :CGFloat = (UIScreen.main.bounds.width == 812) ? 34.0 : 0

public let iPhoneX_REAL_HEIGHT:CGFloat = 812.0   /// 豎屏

extension UIDevice {
    
    /// 是不是iPhoneX ,如果是豎屏則 UIScreen.main.bounds.height == 812
    public func isPhoneX() -> Bool {
        if UIScreen.main.bounds.width == 812 {  /// 橫屏
            return true
        }
        return false
    }
    /// 是不是iPad
    public func isPad() -> Bool {
        
        if UIScreen.main.bounds.height > 812 {
            return true
        }
        return false
    }
}
           

2.GameScene定義可視範圍的起點及高度 (因為是橫屏,是以定義高度)

private var playableRect:CGRect!   /// 可視範圍
    private var playableHeight:CGFloat  = 0.0   /// 可視範圍的高度
    private var playableMargin:CGFloat = 0.0   /// 可視範圍的起點
    
    override func didMove(to view: SKView) {
        self.physicsWorld.gravity = CGVector(dx: 0, dy: 0)
        self.physicsWorld.contactDelegate = self
        
        initCheckDevice()
        setupBall()
        
    }
           

3.檢測是哪種裝置

// MARK: - 檢測是哪種裝置
    func initCheckDevice(){
        if UIDevice.current.isPhoneX() {
            maxAspectRatio = 2.16         /// iPhoneX 2.16 ratio
        }else {
            maxAspectRatio  = UIDevice.current.isPad() ? (4.0 / 3.0) : (16.0 / 9.0)  /// iPhone 16:9,iPad 4:3
        }
        /// 畫出可視區域
        drawPayableArea(size: self.size,ratio: maxAspectRatio)
    }
           

4.畫出可視區域并賦于可視區域的邊屆實體特性

// MARK: - 畫出可視區域
    func drawPayableArea(size:CGSize,ratio:CGFloat){
        /*
         /// 安全區域即使用者互動的區域,非可視區域 (iPhoneX的安全區域 < 可視區域)
         let safeInsetTop    =  self.size.height * AREA_INSET_TOP    / iPhoneX_REAL_HEIGHT
         let safeInsetBottom =  self.size.height * AREA_INSET_BOTTOM / iPhoneX_REAL_HEIGHT
         let safeHeight = self.size.height - safeInsetTop - safeInsetBottom
         */
        
        playableHeight  = size.width / ratio
        playableMargin = (size.height - playableHeight ) / 2.0   /// P70
        playableRect = CGRect(x: 0, y: playableMargin, width: size.width, height:  playableHeight)  /// 注意 scene的anchorPoint(0,0)原點的位置;
        
        let shapeFrame = SKShapeNode(rect: playableRect)
        shapeFrame.zPosition = 1
        shapeFrame.strokeColor = SKColor.red
        shapeFrame.lineWidth = 5.0
        addChild(shapeFrame)
        
        /// 可視區域的實體狀态
        let playableBody = SKPhysicsBody(edgeLoopFrom: playableRect)
        playableBody.friction = 0
        self.physicsBody = playableBody
        playableBody.categoryBitMask    = PhysicsCategory.Frame
        playableBody.contactTestBitMask = PhysicsCategory.Ball
        playableBody.collisionBitMask   = PhysicsCategory.Ball
        
    }
    
           

這樣子Ball球就隻在可視區域内運動了

二、iPhoneX的尺寸及安全區域
SpriteKit遊戲開發适配iPad/iPhone6/7/8/Plus及iPhoneX的尺寸及安全區域

iPhoneX的螢幕尺寸 375(W)x812(H)

SpriteKit遊戲開發适配iPad/iPhone6/7/8/Plus及iPhoneX的尺寸及安全區域

iPhoneX的Safe Area為觸發互動行為的區域

SpriteKit遊戲開發适配iPad/iPhone6/7/8/Plus及iPhoneX的尺寸及安全區域

互動行為(按鈕)須在安全區域内

SpriteKit遊戲開發适配iPad/iPhone6/7/8/Plus及iPhoneX的尺寸及安全區域

安全區域

SpriteKit遊戲開發适配iPad/iPhone6/7/8/Plus及iPhoneX的尺寸及安全區域

頂部狀态欄 44points

SpriteKit遊戲開發适配iPad/iPhone6/7/8/Plus及iPhoneX的尺寸及安全區域

底部間隔 34points

SpriteKit遊戲開發适配iPad/iPhone6/7/8/Plus及iPhoneX的尺寸及安全區域

iPhoneX的螢幕尺寸及安全區域

iPhoneX的螢幕尺寸及安全區域:

裝置 螢幕尺寸 圖檔存放的位置 安全區域
iPhoneX 375x812 @1x 375x(812 - 34 - 44),互動的起點Position(x:0,y:34)
iPhoneX 750x1624 @2x 互動的起點Position(x:0,y:2 x 34)
iPhoneX 1125x2436 @3x 互動的起點Position(x:0,y:3 x 34)
iPhoneX 1536x2048 @1x y:2048 x 34 / 812 (已知812對應34,求2048對應y的值)
SpriteKit遊戲開發适配iPad/iPhone6/7/8/Plus及iPhoneX的尺寸及安全區域

圖檔存放的位置

安全區域

// iPhone X  375*812(H) @1x
// 豎屏
public let AREA_INSET_HEIGHT_TOP   :CGFloat = (UIScreen.main.bounds.height == 812) ? 44.0 : 0
public let AREA_INSET_HEIGHT_BOTTOM:CGFloat = (UIScreen.main.bounds.height == 812) ? 34.0 : 0
// 橫屏(安全區域)
public let AREA_INSET_WIDTH_TOP    :CGFloat = (UIScreen.main.bounds.width == 812) ? 44.0 : 0
public let AREA_INSET_WIDTH_BOTTOM :CGFloat = (UIScreen.main.bounds.width == 812) ? 34.0 : 0

public let iPhoneX_REAL_HEIGHT:CGFloat = 812.0   /// 豎屏


 /// 安全區域即使用者互動的區域,非可視區域 (iPhoneX的安全區域 < 可視區域)
let safeInsetTop    =  self.size.height * AREA_INSET_WIDTH_TOP  / iPhoneX_REAL_HEIGHT
let safeInsetBottom =  self.size.height * AREA_INSET_WIDTH_BOTTOM    / iPhoneX_REAL_HEIGHT
let safeHeight = self.size.height - safeInsetTop - safeInsetBottom   // 安全區域的高度
           

可視區域

playableHeight  = size.width / ratio  /// ratio為2.16
 playableMargin = (size.height - playableHeight ) / 2.0 
 playableRect = CGRect(x: 0, y: playableMargin, width: size.width, height:  playableHeight)  /// 注意 scene的anchorPoint(0,0)原點的位置;
        
           

重要的一點就是要了解螢幕尺寸和安全區域的不同,通俗點講就是,螢幕尺寸可以放任何元素,但不可放互動行為,所有的使用者互動行為都要放在安全區域内。

源碼傳送門:http://www.iFIERO.com/uploads/BreakOutGameVansV.zip

更多遊戲教程: http://www.iFIERO.com