此篇文章是對上一篇文章(http://www.ifiero.com/index.p...)的進一步補充,主要說明如何適配Apple的最新三款手機iPhoneXs、iPhoneXs Max及iPhoneXr !!!php
回顧:爲什麼要把場景中的全部圖片, 都按照屏幕大小爲 2048 1536 來繪製。 也就是說, 咱們的背景圖的大小是 2048 1536, 其餘圖片也是依照這個比例來繪製。git
爲何這樣作呢?github
咱們知道 2048 1536 是iPad Retina 的分辨率。也是咱們須要適配的設備裏面分辨率最高的。 因此咱們在遊戲中都選擇了這個大小,讓它來兼容分辨率低的設備。 2048 1536 在iPad Retina上是完美顯示的。 那在其餘設備上呢? 先用 AspectFill來進行縮放,並應用相應的屏幕辨率高寬比值Ratio, 來適配各個不一樣的iPhone尺寸。AspectFill縮放的代碼以下:api
if let scene = GameScene(fileNamed: "GameScene") { scene.size = CGSize(width: 2048, height: 1536) scene.scaleMode = .aspectFill /// 縮放 view.presentScene(scene) }
瞭解了用 AspectFill來進行縮放,那麼咱們如今就來看看iPhoneX的屏幕尺寸分辨率
iPhoneX的屏幕尺寸分辨率(上圖中 高度812 = 2436縮小1/3):安全
設備 | 屏幕尺寸分辨率 | 圖片存放對應的位置 |
---|---|---|
iPhoneX (1倍 @1x) | 375x812 | @1x |
iPhoneX (2倍 @2x) | 750x1624 | @2x |
iPhoneX (3倍 @3x) | 1125x2436 | @3x |
iPhoneX/iPhoneXs/iPhoneXs Max/iPhoneXr的屏幕尺寸分辨率
iPhoneX系列的屏幕分辨率:oop
設備 | 屏幕分辨率 | 圖片存放的位置 |
---|---|---|
iPhoneX (3倍 @3x) | 1125x2436 | @3x |
iPhoneXs (3倍 @3x) | 1125x2436 | @3x |
iPhoneXs Max (3倍 @3x) | 1242x2688 | @3x |
iPhoneXr (2倍 @2x) | 828x1792 | @2x |
根據以上iPhoneX系列的屏幕分辨率,得出高寬比Ratio都爲2.16
橙色總體區域表示咱們場景的真實大小, 用 AspectFill來進行縮放後,scene.scaleMode = .aspectFill,黑色線框內的區域表示場景展現在設備上的真實大小(即屏幕可視範圍)。spa
iPad Retina:橙色區域和黑色線框內的區域是完美吻合的,也就是說在設備上能完整顯示。設計
iPhone6/7/8/Plus:黑色線框內的區域是2048 * 1152,這邊要注意的是,超出黑色框的內容看不見,設計遊戲時,儘可能不要把精靈的Position位置放在位於不可見的區域。code
iPhoneX:黑色線框內的區域是2048 * 948(蘭色爲安全區域),其中948高度=2048 / 2.16(高寬比)。blog
不一樣尺寸的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/Xs/Xr/Xs Max | -- | 2.16 |
再者咱們主要是適配SpriteKit遊戲開發,所以不須要計算Navigation導航欄的高度,也不須要TabBar狀態欄的高度,只須要計算可視區域(屏幕可視範圍),還有,注意要把須要交互的元素放在安全區域SafeArea,而不要放在危險區域 Danger Area就好了。
可視區域(屏幕可視範圍)= 安全區域 Safe Area + 危險區域 Danger 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 || UIScreen.main.bounds.height == 896) ? 44.0 : 0 public let AREA_INSET_HEIGHT_BOTTOM:CGFloat = (UIScreen.main.bounds.height == 812 || UIScreen.main.bounds.height == 896) ? 34.0 : 0 // 橫屏(安全區域) public let AREA_INSET_WIDTH_LEFT :CGFloat = (UIScreen.main.bounds.width == 812 || UIScreen.main.bounds.width == 896) ? 44.0 : 0 public let AREA_INSET_WIDTH_RIGHT :CGFloat = (UIScreen.main.bounds.width == 812 || UIScreen.main.bounds.width == 896) ? 34.0 : 0 extension UIDevice { /// 是否是iPhoneX ,若是是豎屏則 UIScreen.main.bounds.height == 812 public func isPhoneX() -> Bool { if UIScreen.main.bounds.width == 812 || UIScreen.main.bounds.width == 896 { /// 橫屏 return true } return false } /// 是否是iPad public func isPad() -> Bool { return (UIDevice.current.userInterfaceIdiom == .pad) ? true : false; } }
2.檢測是哪一種設備
// MARK: - 檢測是哪一種設備 func initCheckDevice(){ if UIDevice.current.isPhoneX() { maxAspectRatio = 2.16 /// iPhoneX || iPhoneXs || iPhoneXs Max || iPhoneXr 2.16 高/寬比 ratio }else { maxAspectRatio = UIDevice.current.isPad() ? (4.0 / 3.0) : (16.0 / 9.0) /// iPhone 16:9,iPad 4:3 } /// 畫出可視區域 drawPlayableArea(size: self.size,ratio: maxAspectRatio) /// 畫出安全區域 drawSafeArea(size: self.size,ratio: maxAspectRatio) }
3.畫出安全區域
// MARK: - 安全區域即用戶交互的區域,非可視區域 (iPhoneX的安全區域 < 可視區域) func drawSafeArea(size:CGSize,ratio:CGFloat){ playableHeight = size.width / ratio playableMargin = (size.height - playableHeight ) / 2.0 /// P70 let safeInsetLeft = AREA_INSET_WIDTH_LEFT * ratio let safeInsetRight = size.width - safeInsetLeft - AREA_INSET_WIDTH_RIGHT * ratio playableRect = CGRect(x: safeInsetLeft, y: playableMargin, width:safeInsetRight, height: playableHeight) /// 注意 scene的anchorPoint(0,0)原點的位置; let shapeFrame = SKShapeNode(rect: playableRect) shapeFrame.zPosition = 2 shapeFrame.strokeColor = SKColor.green shapeFrame.lineWidth = 6.0 addChild(shapeFrame) }
4.畫出可視區域並賦於可視區域的邊屆物理特性
// MARK: - 畫出可視區域 func drawPlayableArea(size:CGSize,ratio:CGFloat){ 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)原點的位置; print("playable Margin",playableMargin) 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 /// 地板 setupFloor() }
這樣子Ball球就只在可視區域內(屏幕可視範圍)運動了。
重要的一點就是要了解屏幕尺寸和安全區域的不一樣,通俗點講就是,屏幕可視範圍能夠聽任何元素,但全部的用戶交互行爲都要放在安全區域內(蘭色框內)。
便可視區域(屏幕可視範圍)= 安全區域 Safe Area + 危險區域 Danger Area
源碼傳送門: https://github.com/apiapia/Br...
更多遊戲教程: http://www.iFIERO.com -- 爲遊戲開發深感自豪