#前回までの記事
効率的にゲームをつくるためのフレームワーク①では、GameplayKitの概要を説明してサンプルプロジェクトの準備をしています。
#この記事の概要
エンティティにジオメトリコンポーネントを実装します
エンティティはGKEntity
クラスのオブジェクトで、各種コンポーネントの器となることによって、その機能を実装します。
GKComponent
クラスのオブジェクトであるコンポーネントは、エンティティの特定的な見た目や振る舞いの役割をします。
つまり、コンポーネントはエンティティに縛られることなく自由に割り振ることができます。
ゲームシーンに配置されているSCNNode
オブジェクトである各色ボックスノードと、GKEntity
オブジェクトである各色エンティティを混同しないように注意したい。
一つのコンポーネントは、一つのボックスノードを参照している。
このコンポーネントをエンティティに追加することで、シーンにあるボックスノードを操作する。
#手順
大まかな作業は以下の通りです。
ジオメトリコンポーネントを定義
エンティティにジオメトリコンポーネントを実装
ビルド
##ジオメトリコンポーネントクラスを定義
メニューバー「File > New > File... > iOS > Source > Swift File」を選択してファイルを新規作成する。(GeometryComponent.swift)
SceneKitとGameplayKitをimportする。
GKComponentクラスを定義する
import SceneKit
import GameplayKit
class GeometryComponent: GKComponent {
}
SCNNode
型のgeometryNode
プロパティを定義する。
イニシャライザを実装する。
class GeometryComponent: GKComponent {
let geometryNode: SCNNode
init(geometryNode: SCNNode) {
self.geometryNode = geometryNode
super.init()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
GeometryComponentクラスのイニシャライザは、ゲームシーンの生成時に呼び出されます。
このイニシャライザで引数として受けるSCNNode
オブジェクトの各色ボックスノードを、自身のメンバプロパティとして参照します。この引数geometryNodeには、シーンに配置した各色ボックスが渡ってきます。
個々のコンポーネントは、互いにどのエンティティに追加されているか関知しません。
また、required init?(coder)がないとエラーになるので、実装しておきます。
##ボックスにジオメトリコンポーネントを適用
GameクラスにGameplayKitをインポートする。
エンティティのファクトリメソッドを実装する。
import GameplayKit
class Game: NSObject, SCNSceneRendererDelegate {
let scene = SCNScene(named: "GameScene.scn")!
override init() {
super.init()
}
func makeBoxEntity(forNodeWithName name: String) -> GKEntity {
let node = scene.rootNode.childNode(withName: name, recursively: false)
guard let boxNode = node else { fatalError("no exist \(name) node.") }
let geometryComponent = GeometryComponent(geometryNode: boxNode)
let box = GKEntity()
box.addComponent(geometryComponent)
return box
}
}
エンティティオブジェクトbox
を新たに生成して、コンポーネントオブジェクトを追加しています。コンポーネントには、ボックスノードを参照しています。
イニシャライザでファクトリメソッドを呼び出す。
class Game: NSObject, SCNSceneRendererDelegate {
let scene = SCNScene(named: "GameScene.scn")!
override init() {
super.init()
setUpEntities()
}
func setUpEntities() {
let redBoxEntity = makeBoxEntity(forNodeWithName: "redBox")
let yellowBoxEntity = makeBoxEntity(forNodeWithName: "yellowBox")
let greenBoxEntity = makeBoxEntity(forNodeWithName: "greenBox")
let blueBoxEntity = makeBoxEntity(forNodeWithName: "blueBox")
let purpleBoxEntity = makeBoxEntity(forNodeWithName: "purpleBox")
}
func makeBoxEntity(forNodeWithName name: String) -> GKEntity {
let node = scene.rootNode.childNode(withName: name, recursively: false)
guard let boxNode = node else { fatalError("no exist \(name) node.") }
let geometryComponent = GeometryComponent(geometryNode: boxNode)
let box = GKEntity()
box.addComponent(geometryComponent)
return box
}
}
ファクトリメソッドmakeBoxEntity
では、ジオメトリコンポーネントのオブジェクトgeometryComponent
を生成して、エンティティにジオメトリコンポーネントを追加しています。
エンティティを追跡管理するために、メンバプロパティの配列を宣言して格納する。
import SceneKit
import GameplayKit
class Game: NSObject {
let scene = SCNScene(named: "GameScene.scn")!
var entities = [GKEntity]()
override init() {
super.init()
setUpEntities()
}
func setUpEntities() {
let redBoxEntity = makeBoxEntity(forNodeWithName: "redBox")
let yellowBoxEntity = makeBoxEntity(forNodeWithName: "yellowBox")
let greenBoxEntity = makeBoxEntity(forNodeWithName: "greenBox")
let blueBoxEntity = makeBoxEntity(forNodeWithName: "blueBox")
let purpleBoxEntity = makeBoxEntity(forNodeWithName: "purpleBox")
entities = [redBoxEntity, yellowBoxEntity, greenBoxEntity, blueBoxEntity, purpleBoxEntity]
}
func makeBoxEntity(forNodeWithName name: String) -> GKEntity {
let node = scene.rootNode.childNode(withName: name, recursively: false)
guard let boxNode = node else { fatalError("no exist \(name) node.") }
let geometryComponent = GeometryComponent(geometryNode: boxNode)
let box = GKEntity()
box.addComponent(geometryComponent)
return box
}
}
##ビルド
いったん、ビルドしてジオメトリコンポーネントが正しくアタッチされているかを確認する。
ジオメトリコンポーネントでは、まだ何もしていないので正常にビルドができても変化はありません。
#続く
効率的にゲームをつくるためのフレームワーク③に続きます。