未适配前:Ball球超过屏幕的上下方安全
适配后:Ball球就在屏幕的可视范围内运动了ide
1、那么如何适配不一样的iPhone、iPhoneX及iPad的屏幕尺寸呢?
咱们开发一个App的时候, 一般但愿它在 iPhone, iPad, Mac上同时能运行, 尤为是游戏。oop
这样就须要咱们考虑不一样设备不一样的分辨率,但处理起来比较麻烦,好比说,按照官方的作法,咱们须要提供诸如 ifiero@1x,ifiero@2x,ifiero@3x, 这样不一样尺寸的图片,那如何简便的适配设备不一样的分辨率呢,咱们的作法是, 固定一个大小, 向下兼容不一样的设备。spa
即场景中的全部图片, 都按照屏幕大小为 2048 1536 来绘制。 也就是说, 咱们的背景图的大小是 2048 1536, 其余图片也是依照这个比例来绘制。设计
为何这样作呢?code
咱们知道 2048 1536 是iPad Retina 的分辨率。也是咱们须要适配的设备里面分辨率最高的。 因此咱们在游戏中都选择了这个大小,让它来兼容分辨率低的设备。 2048 1536 在iPad Retina上是完美显示的。 那在其余设备上呢? 这里就要依靠 AspectFill来进行缩放了,代码以下:blog
if let scene = GameScene(fileNamed: "GameScene") { scene.size = CGSize(width: 2048, height: 1536) scene.scaleMode = .aspectFill /// 缩放 view.presentScene(scene) }
不一样尺寸的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为触发交互行为的区域图片
了解了原理后,咱们就开始来编写代码吧
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球就只在可视区域内运动了
2、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 44 / 812 (已知812对应44,求2048对应y的值)|
安全区域
// 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...
更多游戏教程: http://www.iFIERO.com