[SceneKit專題]23-跨平臺遊戲(macOS,tvOS,watchOS)

蘋果API搬運工發表於2017-12-25

說明

本系列文章是對<3D Apple Games by Tutorials>一書的學習記錄和體會

此書對應的程式碼地址

SceneKit系列文章目錄

更多iOS相關知識檢視github上WeekWeekUpProject

以前面的遊戲為例,將其改為跨平臺版本:

  • macOS遊戲Geometry Fighter
    WX20171202-194556@2x.png
  • tvOS遊戲Breaker
    WX20171202-194627@2x.png
  • watchOS遊戲Geometry Fighter
    WX20171202-194641@2x.png

16-macOS遊戲Geometry Fighter

建立專案

開啟Xcode建立新專案,選擇macOS平臺,選擇Game型別,點選Next繼續.

WX20171202-203043@2x.png

輸入遊戲名SceneKitGame,選擇Swift語言,SceneKit遊戲技術,取消UnitUI Tests,點選Finish.

WX20171202-203139@2x.png

生成的專案類似於iOS專案,但不完全相同:

WX20171202-203807@2x.png

  • GameView.swift:繼承於SCNView,可以響應滑鼠鍵盤事件但不能觸控.
  • GameViewController.swift:繼承於NSViewController.
  • MainMenu.xib:控制器的xib.

選擇My Mac,執行一下游戲:

WX20171202-203823@2x.png

轉換SceneKit遊戲

可以在projects/ starter/GeometryFighter/ 中打到原iOS版的專案.

開啟iOS版專案,點選GeometryFighter,新增新的target:

WX20171202-205516@2x.png

選擇Add Target...

WX20171202-205530@2x.png

選擇macOS平臺,然後選擇Game

WX20171202-210513@2x.png

輸入專案名GeometryFighterMac,選擇SceneKit,取消Unit TestsUI Tests,點選Finish:

WX20171202-210528@2x.png

選擇GeometryFighterMac > My Mac作為Active Scheme.

WX20171202-210842@2x.png

執行後,看到的還是預設的飛機場景,那是因為還需要其他步驟.

多個target內容共享

可以在iOS和macOS之間共享原來的程式碼和資源.建立一個Shared分組

WX20171202-212027@2x.png

將下列檔案和資料夾移動到Shared下面:

WX20171202-212430@2x.png
WX20171202-212449@2x.png

按住Shift鍵,選中GeometryFighter/ Shared/Particles下面的全部檔案,開啟右側的屬性檢查器,勾選Target Membership下面的GeometryFighterMac;這樣就能在iOS target和macOS target之間共享了.

WX20171202-213237@2x.png

Shared下面的其他幾個也是類似操作.

WX20171202-213444@2x.png
WX20171202-213503@2x.png
WX20171202-213521@2x.png

為了解決跨平臺帶來的問題,還需要新增下列程式碼:

#if os(iOS)
import UIKit
#endif
#if os(macOS)
import Cocoa
#endif
複製程式碼

當然了,我們不需要每個檔案都去新增,只需要將已建立好的resources/ GameUtils/ 檔案匯入進來就可以了.首先,刪除一些舊檔案,選中GameHelper.swiftUIColor+Extensions.swift. 右鍵--刪除--Move to Trash. 將resources/ GameUtils/ 下面的所有檔案拖放到Shared/ GameUtils/ 資料夾下

WX20171202-215444@2x.png
WX20171202-215540@2x.png

清理

還需要清理一下專案.選中GameView.swift, GameViewController.swiftart.scnassets.右鍵刪除--Move to Trash.

然後從示例程式碼中本章節的resources/GameViewController資料夾下拖放GameView.swiftGameViewController.swift到專案中,選中Copy items if neededGeometryFighterMac,點選Finish完成.

WX20171202-220527@2x.png

還要做的是恢復新的GameViewControllerMainMenu.xib之間的聯絡.

WX20171202-221725@2x.png

滑鼠輸入

選中MainMenu.xib,從右側物件庫中拖放一個Click Gesture RecognizerGame View中.

WX20171202-221925@2x.png

新增連線函式:

WX20171202-222021@2x.png

現在還差最後一步,新增AppIcon,你可以從本章節的resources/AppIcon/資料夾中找到,拖放到Assets.xcassets中的AppIcon下:

WX20171202-222317@2x.png

執行一下程式:

WX20171202-222411@2x.png

本專案的最終完成版程式碼可以在對應章節的projects/ final/GeometryFighter/ 下找到.

17-tvOS遊戲Breaker

建立專案

建立專案

WX20171203-094525@2x.png
WX20171203-094555@2x.png

Active Scheme中選擇SceneKitGame > tvOS Simulator > Apple TV 1080p:

WX20171203-094800@2x.png

執行一下,可以看到預設的飛機模型.但是真實的Apple TV是要用遙控器操作的,怎麼用呢?在模擬器的Hardware > Show Apple TV Remote中,就可以調出遙控器了:

WX20171203-095059@2x.png

移植到tvOS

在程式碼中找到本章節的projects/ starter/Breaker/ 資料夾接著處理.

和前面類似,選中Breaker,新增新的target,在彈出窗中選擇tvOSGame.

WX20171203-095620@2x.png
WX20171203-095637@2x.png
WX20171203-095650@2x.png
WX20171203-095741@2x.png

targets間內容共享

新增一個Shared分組,並將原來的檔案拖放進來:

WX20171203-095834@2x.png
WX20171203-095850@2x.png

逐一選中資料夾下的所有檔案,新增Target Membership:

WX20171203-100814@2x.png
WX20171203-100828@2x.png
WX20171203-100912@2x.png
WX20171203-100927@2x.png

還需要清理一下程式碼. 選中BreakerTV/art.scnassetsBreakerTV/GameViewController.swift,刪除--Move To Trash:

新增專用程式碼

開啟GameViewController.swift,在setupNodes()末尾新增程式碼:

#if os(tvOS)
  scnView.pointOfView = horizontalCameraNode
#endif
複製程式碼

還有shouldAutorotate, prefersStatusBarHiddenviewWillTransition()也不需要了:

#if os(iOS)
override var shouldAutorotate: Bool {
... }
override var prefersStatusBarHidden: Bool {
... }
override func viewWillTransition(to size: CGSize, with coordinator:
  UIViewControllerTransitionCoordinator) {
... }
#endif
複製程式碼

遙控觸控事件

和iOS的觸控事件不同,遙控上更接近MacBook的觸控板的邏輯,touchesBegin()的初始位置總是(x:960, y: 540),即1080p顯示器的中心,touchesMoved()時的位置則是相對於初始點的位置.

另外還有一個問題:tvOS遙控器的觸控板太靈敏了,輕微移動就是很長距離.我們需要在GameViewController中找到下面的程式碼:

 paddleNode.position.x = paddleX +
  (Float(location.x - touchX) * 0.1)
複製程式碼

將其更改為:

#if os(iOS)
  paddleNode.position.x = paddleX +
    (Float(location.x - touchX) * 0.1)
#elseif os(tvOS)
  paddleNode.position.x = paddleX +
    (Float(location.x - touchX) * 0.01)
#endif
複製程式碼
圖示

圖示資源在本章節對應的resources資料夾下.

開啟BreakerTV/Assets.xcassets,選中App Icon & Top Shelf Image,將圖片拖放進去:

WX20171203-110510@2x.png

執行一下,看到圖示出現在Apple TV首頁上了:

WX20171203-110525@2x.png

點選進入遊戲,開始玩吧:

WX20171203-111349@2x.png

18-watchOS遊戲Geometry Fighter

在Xcode中,並沒有專門的watchOS版遊戲的模板,我們需要做的是建立一個iOS的遊戲,再給它新增watchOS的支援.

新增watchOS支援

我們直接在原iOS專案基礎上新增watchOS的target:

WX20171203-111712@2x.png
WX20171203-111736@2x.png
WX20171203-111810@2x.png

Active Scheme中選擇GeometryFighterWatch > iPhone 6s Plus + Apple Watch - 42mm

WX20171203-112044@2x.png

執行一下,看看效果:

WX20171203-112108@2x.png

targets間內容共享

建立Shared資料夾,移動需要的檔案

WX20171203-113835@2x.png

然後依次選中各個資料夾下面的所有檔案,新增Target Membership:

WX20171203-113941@2x.png
WX20171203-114001@2x.png
WX20171203-114021@2x.png
WX20171203-114035@2x.png

新增介面控制器

首先清理專案,選中InterfaceController.swiftart.scnassets.右鍵--刪除--Move to Trash.

WX20171203-114804@2x.png

現在需要新增新的InterfaceController.swift.在本章節對應程式碼的resources/source資料夾下,拖放到Xcode中.

WX20171203-115029@2x.png

然後建立連線:

WX20171203-115144@2x.png

新增觸控輸入

選中Interface.storyboard,拖放一個Tap Gesture Recognizer過來.

WX20171203-115320@2x.png

建立手勢的連線:

WX20171203-115417@2x.png

現在已經基本完成了.

圖示

所需圖片資源在本章節對應的resource/AppIcon資料夾下.

選中Assets.xcassets下面的AppIcon,將圖片拖放到其中:

WX20171203-115723@2x.png

執行一下,可以愉快地玩耍了!

WX20171203-115751@2x.png

專案的最終完成版本章節對應的projects/ final/GeometryFighter/ 資料夾下.

相關文章