WWDC 2017 の SceneKit サンプル Fox 2 を調べる その9
Swift ファイルが保存されているフォルダ
Shared には全体で共有する Swift ファイルがあり、
iOS、tvOS、macOS ではプラットフォーム別で AppDelegate.swift と Main.storyboard から呼ばれる GameViewController.swift で構成されている
iOS 版のみ、ヴァーチャルキーボードを使用するため 3つ Swift ファイルが追加されている。
Swift ファイルについて
Shared と 各プラットフォームのフォルダmのファイルをざっくり見てゆく。
Shared
以下の Swift ファイルがある
- Character.swift
- GameController.swift
- Overlay.swift
- BaseComponent.swift
- ChaserComponent.swift
- PlayerComponent.swift
- ScaredComponent.swift
- SimdExtensions.swift
- UI フォルダ内の Button.swift、Slider.swift、Menu.swift
Character.swift
基本的にはプレイヤーキャラ Max 自体の振る舞い設定を全てここで決めており、 GameController.swift でこちらの設定を使用し Max を動かしている。
GameController.swift
シーン全体設定する NSObject のクラス。
各プラットフォームの GameViewController の UIViewController でこのクラスをイニシャライズし、その際に各 Main.storyboard で設定されている SCNView 渡して共通の処理をしている。
Overlay.swift
右上のアイコン類、クリア時のロゴと Max の 2D 画像を画面の UI を SpriteKit の SKScene で設定しており、GameController.swift で SceneKit の overlaySKScene でこちらを設定している。
iOS のヴァーチャルパッドは iOS フォルダの Swift ファイルで設定している。
BaseComponent.swift
GameplayKit の GKComponent を継承したクラスで、敵キャラなどの動作の元となる設定がされている。
目標に沿って動作するエージェントシステムが使用できる GKAgent2D を効率よく使用するため、GKComponent を使用している。
また、このファイルで GKAgent2D の Extension を作成している。
GKAgent2D の他に GKAgent3D があるが、今回は Y 座標に対して、追跡を行わないため 3D の方は使用していない模様。
PlayerComponent.swift
BaseComponent を継承したクラスで、Character.swift でキャラ設定しているクラスを GKComponent で取得している。
ChaserComponent.swift と ScaredComponent.swift ではこちらのクラスからキャラ設定を取得して、近づいたり、離れたりするための位置情報取得と、攻撃の状態を調べているために使用している。
ChaserComponent.swift
ScaredComponent.swift
近づく敵や遠ざかる敵の設定。
基本的にはほぼ同じで GKAgent2D 目的地となる複数の GKGoal を設定したり、
敵キャラの状態の設定や状態ごとの振る舞いを決めている。
状態の判別は GameplayKit の State Machine は使用せず、enum の設定から調べている。
SimdExtensions.swift
SIMD で設定している行列の処理を簡単にする Extension。
基本的には simd_float2、3、4 での == や != のオペレーターや、
simd_float4x4 で 位置情報 xyz 代入したり取得する関数が追加されている。
ちなみに、Fox 2 座標変換はほぼ iOS11 などで追加された SIMD で計算されている。
UI フォルダ内の Button.swift、Slider.swift、Menu.swift
デバッグ用の UI と機能があり、Button.swift ボタンに関する UI。
Slider.swift スライダーの UI。Menu.swift はこれらを表示するものとなっており、Overlay.swift 内で設定されている。
ボタンはカメラの切り替え、スライダは被写界深度の調整を行う。
左上の Max の画像をタップすると出現するはずだが、設定している座標の問題でボタンが表示されず、スライダーは IBAction の設定されていないため使用できない。
iOS
以下の Swift ファイルがある
- ButtonOverlay.swift
- PadOverlay.swift
- ControlOverlay.swift
- GameViewController.swift
- AppDelegate.swift
ButtonOverlay.swift
ヴァーチャルパッドで使用する A、B ボタンの SKNode とタッチイベントを設定している。
GameController.swift でメソッドを実行できる用に ButtonOverlayDelegate が設定されている。
PadOverlay.swift
ヴァーチャルパッドで使用するパッドの SKNode とタッチイベントを設定している。
GameController.swift でメソッドを実行できる用に PadOverlayDelegate が設定されている。
ControlOverlay.swift
ヴァーチャルパッドの部品であるパッド2つとボタン2つを配置している SKNode。
Overlay.swift 内で「#if os( iOS ) ... #endif」を使用し、iOS の場合のみこちらを表示し動作するようにしている。
GameViewController.swift
起点となる UIViewController。 Main.storyboard で view に SCNView が設定されている。
Shared フォルダ GameController の呼び出し時に、この view である SCNView を渡している。
また、iPad の場合は UIView の contentScaleFactor を調べ 1.3 より大きい場合は 1.3 に変更し、preferredFramesPerSecond を 60 にしている。
AppDelegate.swift
通常の AppDelegate.swift。
tvOS
GameViewController.swift
起点となる UIViewController。 Main.storyboard で view に SCNView が設定されている。
Shared フォルダ GameController の呼び出し時に、この view である SCNView を渡している。
AppDelegate.swift
通常の AppDelegate.swift。
macOS
GameViewController.swift
通常の macOS アプリ同様に NSWindow の 起点となる NSViewController。 Main.storyboard の view ではカスタムクラスの GameViewMacOS が呼ばれており SCNView が継承され設定されている。
Shared フォルダ GameController の呼び出し時に、この view である SCNView を渡している。
NSViewController では iOS のヴァーチャルパッドと同様の振る舞いを keyUp, keyDown のキーボード操作に該当する関数で設定している。
カスタムクラスの GameViewMacOS は、ウィンドウのサイズ変更時に Overlay.swift の layout2DOverlay() で UI 領域を再描画したり、viewDidMoveToWindow で NSViewController へサブビューとしてこちらが追加された際に contentsScale を 1 にして Retina 表示ではなくしている。
また、NSViewController ではキーボードイベントがないため、この View のキーイベントを NSViewController の関数にアクセスしている。
AppDelegate.swift
通常の AppDelegate.swift。
以上、ざっくりと Fox 2 のプロジェクトで使用している Swift ファイルの説明をしてみた。
次回、コードの深掘りの前に GameplayKit 概要を見てゆく。