SpriteKit在iOS8和OSX10.10中的新特性(强悍来袭)
在iOS8和OSX10.10中SpriteKit迎來了重大升級。在物理表現方面增加了著色器,光照和陰影;在物理模擬方面增加了像素物理體、力場和宇宙動力學和約束等;在Xcode中集成了場景編輯器,你不需要寫代碼就能完成一些復雜的工作;此外它還集成了SceneKit以及其他的改進。
Shader
有時候為了表現一些形變和模糊效果,比如透過熱氣和火焰看一些物體,或者是飛船被攻擊而產生彎曲。SpriteKit新加入了?SKShader?類來幫助我們更簡單的實現這個效果。它通過使用自定義的OpenGL ES碎片著色來完成繪制一些?SKNode的自定義行為。現在支持以下幾種類型的繪制:
- SKSpriteNode
- SKShapeNode
- SKEmitterNode
- SKEffectNode
- SKScene
放一張官方演示的效果圖:
SKShader?內建了一些?uniforms?,用?SKUniform?來描述,當你創建一個?SKShader?時,需要通過一個?fsh?文件或者一個字符串代碼來創建,也可選擇性的傳入?uniforms?來定義游戲中一些額外的參數。下面是創建Shader方法的集合:
(下面的只是偽代碼,不是OC也不是Swift語法,只是為了更簡潔的標記方法名,后面類似情形都會標記為“偽代碼”)
| ? | + shaderWithFileNamed: + shaderWithSource:uniforms: + shaderWithSource: + shader - initWithSource:uniforms: - initWithSource: |
這些方法很相似,都是傳入?source?或?source?與?uniforms?來創建shader。官方建議我們用?fsh?文件作為?source?而不是字符串代碼;并且避免更改?source?或添加刪除?uniforms?(修改?uniforms?是可以的),因為這樣會導致后臺花時間重新編譯shader;盡量在加載時初始化shader。這些注意事項都可以總結為盡量使用內建的?uniforms?和共享shader對象。
我們可以將創建好的?SKShader?對象賦值給支持Shader渲染對象的?shader屬性。
下面列舉一下Shader中的預定義符號:
Lighting and Shadows
燈光和陰影效果可以給游戲增加真實感,SpriteKit這次增加了?SKLightNode來作為光源節點。我們可以定義光源的顏色,陰影和衰弱程度。
SKLightNode?繼承于?SKNode?,也就是說你可以把它加在其他?SKNode上,并能夠動起來,它是一個會發光的?SKNode?,cool!NOTE:它的光照以及陰影效果只對?SKSpriteNode?起作用。
下面我們看看?SKLightNode?的一些屬性:
- enabled?光源的開關
- ambientColor?環境色,默認是黑色,也就是沒有環境色。它無視自身的alpha以及?SKLightNode?的?falloff?屬性和?SKSpriteNode?的normalTexture?屬性,分分鐘照亮全場。
- lightColor?顧名思義就是光的顏色,默認是白色。
- shadowColor?被精靈物體遮擋產生的陰影顏色。
- falloff?光源強度的衰減比率
- categoryBitMask?光的種類,32位整型數。?SKSpriteNode?的lightingBitMask?、?shadowedBitMask?和?shadowCastBitMask存儲著光的種類,分別意味著:被何種光照亮、被何種光產生的陰影覆蓋和遮擋何種光線并產生陰影。
為了在?SKSpriteNode?上實現更加逼真的光照效果(如陰影和反射光),SKSpriteNode?新增了?normalTexture?屬性來儲存原帖圖的法線貼圖(Normal Map):
上圖中左側的是原貼圖,加上中間的法線貼圖就合成出最右側帶有質感的光照紋理。當然提供這樣一張發現紋理圖片會增加開發者的工作量,蘋果還提供了另一種更加簡單的方案-“automatic normal map”:
SpriteKit能夠根據給出的紋理圖片,用一系列算法分析原貼圖,然后生成一個最佳的法線貼圖,又是蘋果的黑魔法!
畢竟眾口難調,所以SpriteKit讓你也可以在生成法線貼圖的時候給出平滑度(smoothness)和對比度(contrast)來調節你想要的效果:(偽代碼)
| ? | - textureByGeneratingNormalMapWithSmoothness:contrast: |
PS:法線貼圖將具有高細節的模型通過映射烘焙出法線貼圖,貼在低端模型的法線貼圖通道上,使之擁有法線貼圖的渲染效果。可以大大降低渲染時需要的面數和計算內容,從而達到優化動畫渲染和游戲渲染的效果。
在一個場景中可以添加多個光源,程序會運行的很快;但是如果用兩個或以上的光源照亮同一個精靈,在某些iOS設備上可能保證不了60幀的刷新頻率。
New Physics
Per-Pixel Physics
在定義一些復雜輪廓的物理體時,我們經常用簡單圖形代替,否則就用CGPath?一點點描繪多邊形或者把多個物理體組合在一起(這也是新加入的API,后面會提到),比如下面這把斧頭,大多數程序員直接用矩形當做它的物理體:
而Per-Pixel Physics根據紋理圖片的alpha通道遮罩來生成一個粗略的形狀,然后再用粗略的形狀生成精確的形狀,它讓以前復雜的?CGPath?創建工作轉變成一行代碼:
畢竟眾口難調,所以SpriteKit給出了一個可以自由調節alpha閾值的物理體生成方法,所有alpha值大于?alphaThreshold?的像素點都將被認為是不透明的,并納入物理體范圍內:(偽代碼)
| ? | + bodyWithTexture:alphaThreshold:size: |
因為SpriteKit是逐個像素計算才得出精確的物理體輪廓,所以我們應該盡量給出合適大小的圖片,不要將分辨率過高的圖片用在很小的?SKSpriteNode?上。
Constrains
試想如果你要做一款塔防游戲,你需要讓你的大炮一直瞄準某個怪物,大炮會隨著怪物的行走來轉動炮臺。我們需要不停地根據怪物和大炮的位置來計算需要旋轉的角度,甚至當怪物跑的快的時候還要考慮怪物的速度來調整大炮旋轉的速度,這是一個很麻煩的事情。現在SpriteKit幫你把這些都做好了,你只需要建立一個SKConstrains?對象,并約束大炮的角度跟怪物一致就行。
約束的計算工作發生在模擬物理之后,SpriteKit提供了一個回調函數didApplyConstraints?,我們可以在約束完成后在里面做一些善后工作:
在SpriteKit中我們可以向SKNode添加三種約束:(工廠方法的偽代碼)
- 位置約束:
| ? | //約束節點的X坐標范圍 + positionX: //約束節點的Y坐標范圍 + positionY: //約束節點的X和Y坐標范圍 + positionX:Y: |
- 方向約束:
| ? | //約束節點基于另一個SKNode旋轉 + orientToNode:offset: //約束節點基于一個固定點旋轉 + orientToPoint:offset: //約束節點基于另一個SKNode坐標系中的一個固定點旋轉 + orientToPoint:inNode:offset: //約束節點的方向范圍 + zRotation: |
- 距離約束:
| ? | //約束節點與另一節點保持一定距離 + distance:toNode: //約束節點與一個固定點保持一定距離 + distance:toPoint: //約束節點與另一個SKNode坐標系中的一個固定點保持一定距離 + distance:toPoint:inNode: |
向?SKNode?添加約束很簡單,只需要將一個?SKConstrains?數組賦值給SKNode.constraints?屬性即可。約束執行的順序取決于它們在數組中的順序。
Inverse Kinematics
反向運動學,沒有機械工程學位或沒寫過動畫引擎的人干脆不知道這是個啥。它其實是解決連接體運動的,比如現在有一個機器人的手臂,我們想讓它動起來去用手抓某個東西。我們會想到每個關節轉多少度才能準確讓機器手抓到物體,計算的時候還應該考慮連接體的層級關系:肩膀連接上臂,上臂連接小臂,小臂連接手。哦天啊這真蛋疼,不過SpriteKit的反向動力學解決了這一點,我們只需要指定每個SKNode?的活動約束還有需要抓取物體的位置,那么這一切只需要幾行代碼就能搞定。
機器人手臂轉動約束是靠?SKReachConstraints?類來定義的,它只有一個初始化方法:(偽代碼)
| ? | - initWithLowerAngleLimit:upperAngleLimit: |
這個方法給?lowerAngleLimit?和?upperAngleLimit?屬性賦值,約束了reach事件使其發生旋轉角度的下限和上限。
當一個?SKReachConstraints?創建好后,將其賦值給?SKNode?的reachConstraints?屬性,然后用?SKPhysicsJoint?將這些?SKNode?連接起來。使用?SKAction?的一套工廠方法創建來讓連接體reach到活動目標或固定點的動作:(偽代碼)
| ? | + reachTo:rootNode:duration: + reachTo:rootNode:velocity: + reachToNode:rootNode:duration: + reachToNode:rootNode:velocity: |
讓機器人的手部節點運行創建好的?SKAction?對象即可達到最初描述的動畫效果。如果機器人的手觸碰不到指定的位置或節點(gif中就是這樣),?SKAction會執行動畫讓其盡可能接近目的地。
PS:IK(Inverse Kinematics)也能在SceneKit上運行。
Physics Fields
在一個模擬宇宙空間的游戲中,星球對其他物體的引力是不可忽視的,這就涉及到物理場。SpriteKit為我們提供了一個專門描述物理場的類?SKFieldNode?,它繼承于?SKNode?,也就是說它可以被添加到其他節點中。它能夠描述多種場:電場、磁場、矢量重力場、輻射重力場、噪聲場等十余種場。?SKFieldNode?的strength?和?falloff?屬性決定了場的強度和衰減比率。
SKFieldNode?還有一些屬性決定了游戲中哪些物理體會被場影響:
- region?描述了場的影響區域,類型是?SKRegion?。?SKRegion?可以是無限區域,矩形、圓形、?CGPath?多邊形區域,還可以用兩個?SKRegion做邏輯運算得出新的?SKRegion?,比如交集,并集,差集,還可對一個SKRegion?取反得到剩下的區域。
- minimumRadius?一些場對物體的影響程度跟距離有關,當物體與場的距離小于?minimumRadius?屬性的值時,仍被當做?minimumRadius?的值進行處理計算。?minimumRadius?的默認值很小很小,但不是0
- categoryBitMask?場的類別。當一個節點進入了場的影響區域,會根據節點的物理體屬性的?fieldBitMask?屬性來判斷此節點是否收到場的影響。此外?SKPhysicsBody?的?charge?屬性還會標記物理體所帶的電荷量,這在跟電磁有關的場中會影響到物理體的運動。默認為 0xFFFFFFFF
- enabled?場的“開關”
- exclusive?唯我獨尊,這個場的地盤內,別的場的影響被無視。別讓兩個唯我獨尊的場影響區域重疊,那樣會出亂子的。默認為?NO?。
我用SpriteKit的力場中的噪聲場和輻射重力場做了一個小游戲?ColorAtom?,有興趣的可以去看看。應用了很多粒子系統和碰撞檢測知識,把SpriteKit之前的內容能加的都加進去了,歡迎指正。
Integration with SceneKit
在SpriteKit這樣的2D游戲引擎中也可以引入3D的內容,可以將SceneKit中的3D物體當做SpriteKit中的?SKNode?來操作,為了達到這一目的SpriteKit這次增加了SK3DNode?類作為3D物體到SpriteKit中的橋接。
通過?SK3DNode?的?scnScene?屬性可以獲取到?SCNScene?,因為SK3DNode?把3D場景渲染成2D貼圖,所以創建?SK3DNode?對象的時候需要傳入一個渲染后貼圖的尺寸?viewportSize?。?pointOfView?屬性存儲了游戲視角的位置,你可以嘗試實現個上帝視角。
由于我也不太了解新出的SceneKit,所以這部分不過多介紹了。
Tools
Xcode6增加了SpriteKit編輯器,一行代碼都不用寫就能創建出個游戲場景。這樣你就將游戲內容從游戲邏輯沖分離出來。我們只需要將控件拖拽到游戲場景你想要的位置上,而不必每次調整一個飛船的位置,編譯運行看看結果,然后再改代碼微調位置再次編譯運行。。。
SpriteKit編輯器不僅有編輯功能,也可用來debug。你可以再運行過程中將當前狀態存儲在一個sks文件中。
SpriteKit編輯器強大到你可以直接拖拽出一個SKSpriteNode并定義它的物理體,甚至使用Per-Pixel Physics。還可以編輯光照和陰影,編輯Shader并調整Uniforms,建立一個Inverse Kinematics并預覽其效果,強大極了。
其實說白了SpriteKit編輯器就像IB一樣可以可視化編輯屬性,并課即時預覽效果,整個過程不需一行代碼。
Xcode能編輯fsh文件,與SpriteKit場景編輯器對照編輯,并做語法檢查和編譯。
Improvements
SKScene
SpriteKit每一幀場景的執行過程:
除了之前提到新加的Constrains,SpriteKit這次還加入了一個回調函數didFinishUpdate?。這絕對是SpriteKit將每幀所有東西打包好交給GPU渲染之前調用的最后一個函數。
SKTexture
- SKMutableTexture?是?SKTexture?新加的子類,它的內容可以通過modifyPixelDataWithBlock:?方法動態地修改。
- SKTexture?現在可以生成“noise textures”,參見textureVectorNoiseWithSmoothness:size:?和textureNoiseWithSmoothness:size:grayscale:?
SKShapeNode
- 增加了一些常見圖形便捷的構造方法,比如矩形,圓形,橢圓和曲線。
- 可以用貼圖和Shader來美化形狀的描邊和填充
Physics Updates
- SKPhysicsBody?新加了?pinned?屬性來標志此物理體對應的節點是否被釘在它的父節點上。如果父節點也有物理體,那么這兩個物理體被認為被一個pin連接。如果將?allowsRotation?設為NO并且?pinned?設為YES,那么它相當于被焊在父節點上了,因為它不能轉動了。
- SKPhysicsBody?允許用?bodyWithBodies:?把多個物理體組合在一起來創建一個新的物理體,還記得前面提到過的斧頭么:?
SKTexture Atlas
- 同時支持SpriteKit和SceneKit
- 同時支持Retina和非Retina
- 同時支持16位和32位格式
- 支持4k x 4k 分辨率
- 支持運行時紋理圖集的生成。比如從網上下載資源,SpriteKit會自動將透明的像素裁剪下去
總結
以上是生活随笔為你收集整理的SpriteKit在iOS8和OSX10.10中的新特性(强悍来袭)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【毫米波雷达】人体目标探测理论
- 下一篇: word实现多级自动编号