連載
» 2017年07月10日 05時00分 公開

「人工知能」の作り方(終):3DゲームのAIをiOSのSceneKitとGameplayKitで作る基本 (1/2)

ゲーム用フレームワークであるGameplayKitを使ったアプリ制作を通して人工知能(AI)について学んでいく連載。最終回は、3Dゲーム用のフレームワークSceneKitを使った簡単なアプリ制作を通して、3Dゲーム用のAIについて学ぶ。

[杉本裕樹,マネーフォワード]

最終回は、3Dゲームの人工知能

 本連載『ゲームの「敵」キャラで分かる「人工知能」の作り方』では、ゲーム用フレームワークであるGameplayKitを使ったアプリ制作を通して人工知能(AI)について学んでいきます。

 前回の「iOS GameplayKitのRule SystemsでゲームAIプログラミングはどう変わるのか」までは、iPhone向け鬼ごっこアプリ制作を通して2DゲームにおけるAIの実装を行いました。

 連載最終回となる本稿では、簡単な3Dアプリ制作を通して、3Dゲーム用のAIについて学びます。

SceneKitで3Dゲームプロジェクトの作成

 今回はオブジェクトが目的地に向かって移動するアプリを作っていきます。

 まずは3Dゲームのプロジェクトを作成します。Xcodeで新規プロジェクト作成を選択してください。

 テンプレート選択画面では「Game」を選択します。

 最後に、アプリの詳細を入力しますが、ここでは「SceneKit」を選択します。

 これでプロジェクトを作成できました。起動すると、飛行機が回っている画面が表示されるかと思います。

SceneKitとは、その主な機能

 SceneKitとは、3Dゲーム用のフレームワークで、3Dゲームを作るためのさまざまな機能を提供します。

 サンプルのソースコードを基に、SceneKitの機能について簡単に見ていきます。

1つの画面を構成するSCNScene

 SceneKitでは「SCNScene」が1つ1つの画面に相当します。こちらはSpriteKitにおけるSKSceneに相当します。この上に飛行機などのオブジェクト(SCNNode)を配置することでゲームを作っていきます。

 SCNSceneはUIViewControllerの「SCNView」にセットすることで画面に表示されます。サンプルアプリでは、下記のように「ship.scn」からSCNSceneを読み込んでSCNViewにセットしています。

class GameViewController: UIViewController {
    override func viewDidLoad() {
        let scene = SCNScene(named: "art.scnassets/ship.scn")!
 
        // 省略
 
        let scnView = self.view as! SCNView
        scnView.scene = scene
 
        // 省略
    }
 
    // 省略
}

画面タップの検知

 画面タップの検知はSpriteKitと少し違うので、注意が必要です。SpriteKitのSKSceneはUIResponderのサブクラスのため、以下のようにタップを検知できました。

// SpriteKitでは以下のようにタップを検知
class MyScene: SKScene {
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    }
 
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    }
}

 SCNSceneはUIResponderのサブクラスではないため、SCNViewにUITapGestureRecognizerを追加する必要があります。

 サンプルでは、以下のように実装しています。

class GameViewController: UIViewController {
    override func viewDidLoad() {
        // 省略
 
        let scnView = self.view as! SCNView
 
        // 省略
 
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
        scnView.addGestureRecognizer(tapGesture)
    }
 
    func handleTap(_ gestureRecognize: UIGestureRecognizer) {
        // 省略
    }
 
    // 省略
}

毎フレーム呼ばれるメソッド

 毎フレーム呼ばれるメソッドもSpriteKitと違いがあります。SpriteKitではSKSceneのupdateメソッドが毎フレーム呼ばれていました。しかしSceneKitのSCNSceneにはupdateメソッドがないため、他の方法を採る必要があります。

class MyScene: SKScene {
    override func update(_ currentTime: TimeInterval) {
    }
}

 方法としては、「SCNSceneRendererDelegate」を使うものがあります。以下のようにSCNSceneRendererDelegateの「renderer」を使うと、毎フレーム呼ばれるメソッドを実装できます。

class GameViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
 
        let scnView = view as? SCNView
        scnView?.delegate = self
    }
}
 
extension GameViewController: SCNSceneRendererDelegate {
    func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
        // 1フレームごとに呼ばれるメソッド
    }
}

オブジェクトのアニメーション「SCNAction」

 オブジェクトのアニメーションには「SCNAction」を使います。

 サンプルでは、以下のように飛行機に回転アニメーションを追加しています。こちらはSpriteKitの「SKAction」とほぼ同じですが、扱う位置情報が2次元から3次元になっています。

let ship = scene.rootNode.childNode(withName: "ship", recursively: true)!
ship.runAction(SCNAction.repeatForever(SCNAction.rotateBy(x: 0, y: 2, z: 0, duration: 1)))
       1|2 次のページへ

Copyright© 2017 ITmedia, Inc. All Rights Reserved.

@IT Special

- PR -

TechTargetジャパン

この記事に関連するホワイトペーパー

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。