LoginSignup
2

More than 5 years have passed since last update.

【GameplayKit】効率的にゲームをつくるためのフレームワーク②

Last updated at Posted at 2016-12-07

前回までの記事

効率的にゲームをつくるためのフレームワーク①では、GameplayKitの概要を説明してサンプルプロジェクトの準備をしています。

この記事の概要

エンティティにジオメトリコンポーネントを実装します
エンティティはGKEntityクラスのオブジェクトで、各種コンポーネントの器となることによって、その機能を実装します。
GKComponentクラスのオブジェクトであるコンポーネントは、エンティティの特定的な見た目や振る舞いの役割をします。
つまり、コンポーネントはエンティティに縛られることなく自由に割り振ることができます。

ゲームシーンに配置されているSCNNodeオブジェクトである各色ボックスノードと、GKEntityオブジェクトである各色エンティティを混同しないように注意したい。

一つのコンポーネントは、一つのボックスノードを参照している。
このコンポーネントをエンティティに追加することで、シーンにあるボックスノードを操作する。

手順

大まかな作業は以下の通りです。
ジオメトリコンポーネントを定義
エンティティにジオメトリコンポーネントを実装
ビルド

ジオメトリコンポーネントクラスを定義

メニューバー「File > New > File... > iOS > Source > Swift File」を選択してファイルを新規作成する。(GeometryComponent.swift)
SceneKitとGameplayKitをimportする。
GKComponentクラスを定義する

GeometryComponent.swift
import SceneKit
import GameplayKit

class GeometryComponent: GKComponent {

}

SCNNode型のgeometryNodeプロパティを定義する。
イニシャライザを実装する。

GeometryComponent.swift
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をインポートする。
エンティティのファクトリメソッドを実装する。

Game.swift
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を新たに生成して、コンポーネントオブジェクトを追加しています。コンポーネントには、ボックスノードを参照しています。
イニシャライザでファクトリメソッドを呼び出す。

Game.swift
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を生成して、エンティティにジオメトリコンポーネントを追加しています。

エンティティを追跡管理するために、メンバプロパティの配列を宣言して格納する。

Game.swift
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
    }   
}

ビルド

いったん、ビルドしてジオメトリコンポーネントが正しくアタッチされているかを確認する。
ジオメトリコンポーネントでは、まだ何もしていないので正常にビルドができても変化はありません。

続く

効率的にゲームをつくるためのフレームワーク③に続きます。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2