3DゲームのAIをiOSのSceneKitとGameplayKitで作る基本:「人工知能」の作り方(終)(2/2 ページ)
ゲーム用フレームワークであるGameplayKitを使ったアプリ制作を通して人工知能(AI)について学んでいく連載。最終回は、3Dゲーム用のフレームワークSceneKitを使った簡単なアプリ制作を通して、3Dゲーム用のAIについて学ぶ。
●「Agents, Goals, and Behaviors」を利用したオブジェクトの移動 |
---|
続いて、サンプルの飛行機を「Agents, Goals, and Behaviors」を使って移動させるアプリを作ります。
GameViewControllerのコードを最小限に
まずはGameViewControllerのコードを最小限にします。GameViewController.swiftを下記のように修正してください。
import UIKit import QuartzCore import SceneKit class GameViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let scnView = view as? SCNView scnView?.delegate = self scnView?.isPlaying = true let scene = SCNScene(named: "art.scnassets/ship.scn") scnView?.scene = scene // 光源の設置 let lightNode = SCNNode() lightNode.light = SCNLight() lightNode.light?.type = .omni lightNode.position = SCNVector3(x: 0, y: 10, z: 10) scene?.rootNode.addChildNode(lightNode) let ambientLightNode = SCNNode() ambientLightNode.light = SCNLight() ambientLightNode.light?.type = .ambient ambientLightNode.light?.color = UIColor.darkGray scene?.rootNode.addChildNode(ambientLightNode) // 飛行機の角度調整 let ship = scene?.rootNode.childNode(withName: "ship", recursively: true) ship?.eulerAngles = SCNVector3(x: 0, y: Float.pi, z: 0) } override var prefersStatusBarHidden: Bool { return true } } extension GameViewController: SCNSceneRendererDelegate { // 1フレームごとに呼ばれるメソッド func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) { print(time) } }
これで飛行機が配置されているだけの状態になりました。
ルールを作成
次は、実際に「Agents, Goals, and Behaviors」を使って飛行機を移動させます。
まずはプロジェクト設定の下にあるボタンからGameplayKitを追加します。
続けてGameViewControllerを下記のように修正します。
import UIKit import QuartzCore import SceneKit import GameplayKit // 今回追加 class GameViewController: UIViewController { // 今回追加ここから let agentSystem = GKComponentSystem(componentClass: GKAgent3D.self) var prevTime: TimeInterval = 0 let shipAgent = GKAgent3D() // 今回追加ここまで override func viewDidLoad() { // 省略 // 飛行機の角度調整 let ship = scene?.rootNode.childNode(withName: "ship", recursively: true) ship?.eulerAngles = SCNVector3(x: 0, y: Float.pi, z: 0) // 今回追加ここから let targetAgent = GKAgent3D() targetAgent.position = float3(0, 0, -300) shipAgent.maxAcceleration = 1 shipAgent.maxSpeed = 1 shipAgent.delegate = self shipAgent.behavior = GKBehavior(goals: [ GKGoal(toSeekAgent: targetAgent), ]) agentSystem.addComponent(shipAgent) // 今回追加ここまで } override var prefersStatusBarHidden: Bool { return true } } // 省略
上記コードでは、飛行機のagent(shipAgent)が座標(x: 0, y: 0, z: -300)に向かうようなルールを作成しました。
ルールに沿って移動する処理を追加
次は、飛行機オブジェクトがそのルールに沿って移動する処理を追加します。
// 省略 extension GameViewController: SCNSceneRendererDelegate { // 1フレームごとに呼ばれるメソッド func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) { // 今回追加ここから if prevTime == 0 { prevTime = time } agentSystem.update(deltaTime: time - prevTime) // 今回追加ここまで } } // 今回追加ここから extension GameViewController: GKAgentDelegate { func agentDidUpdate(_ agent: GKAgent) { if let ship = (view as? SCNView)?.scene?.rootNode.childNode(withName: "ship", recursively: true), let agent = agent as? GKAgent3D { ship.position = SCNVector3(agent.position) } } } // 今回追加ここまで
これで飛行機が奥に向かって移動するようになりました。
2Dと3Dでの「Agents, Goals, and Behaviors」の利用方法の違い
前項では、3Dゲームへの「Agents, Goals, and Behaviors」適用を行いました。実は2Dでも3Dでも実装の流れとしては、ほとんど同じです。
どちらも大きな流れとしては「エージェント(GKAgent)インスタンスを作成して、そこにルール(GKRule)を追加する」というものになります。
変更点としては、扱う位置情報が2次元から3次元になるだけなので、2Dゲームと大きな違いはなく実装できると思います。
「Agents, Goals, and Behaviors」を利用した、障害物を回避するルールの追加
最後に障害物を設置したときの動きも見ていきます。
鬼ごっこアプリ同様に、GKObstacleを使って障害物を設置します。GameViewControllerのviewDidLoadを下記のように修正してください。
class GameViewController: UIViewController { // 省略 override func viewDidLoad() { // 省略 let targetAgent = GKAgent3D() targetAgent.position = float3(0, 0, -300) shipAgent.maxAcceleration = 1 shipAgent.maxSpeed = 1 shipAgent.delegate = self // 今回修正ここから let obstacle = GKSphereObstacle(radius: 100) obstacle.position = vector_float3(0, 0, -150) shipAgent.behavior = GKBehavior(goals: [ GKGoal(toSeekAgent: targetAgent), GKGoal(toAvoid: [obstacle], maxPredictionTime: 100.0) ], andWeights: [NSNumber(value: 1), NSNumber(value: 50)]) // 今回修正ここまで agentSystem.addComponent(shipAgent) } // 省略 }
今回追加したGKSphereObstacleは3Dゲーム用の障害物オブジェクトです。この障害物を避けるルール【GKGoal(toAvoid: [obstacle], maxPredictionTime: 100.0)】を追加することで、飛行機が斜めに移動するようになりました。
以上で、3Dゲームにおける「Agents, Goals, and Behaviors」の基本的な使い方は終了です。
GameplayKitでゲームAI開発の工数を削減しよう
今回のソースはkonkai.zipからダウンロードできます。
これまで4回にわたって「Agents, Goals, and Behaviors」の使い方を見てきましたがいかがでしょうか? GameplayKitは分かりにくいところもありますが、うまく使えば開発工数を大いに削減できます。
もし機会がありましたら、本連載を参考に試していただけると幸いです。
筆者紹介
杉本裕樹
田町のベンチャーで働くエンジニア。
仕事ではiPhoneアプリの開発やRailsを使ったWebサービス開発を行っている。最近のマイブームはUnityを使った3Dゲーム開発。
Copyright © ITmedia, Inc. All Rights Reserved.
関連記事
- iOS 9の最新機能で自動ルート検索を簡単にゲームに組み込む
iPhoneゲームをSwift言語で作成してみたいという初心者向けにiOSのゲームフレームワークを使った作り方を一から解説する入門連載。今回は、敵の動きを改善する。GameplayKitのPathfindingを使ったルートの自動探索の使い方についてSpriteKitのSKActionでの実装と比べて解説。 - iOS 10 SDKの新機能SiriKit、音声認識、iMessage拡張を自作アプリに生かすには
iOS 10で開発者にAPIが解放されたと話題の音声アシスタント「Siri」。その実態はどんなものなのか。SiriKit、Speech/Messages Frameworkの使い方と併せて、簡単なアプリを作りながら解説します。 - スマホ世代でも分かるMacの基本的な使い方&Xcodeをインストールする手順
本連載では、これからプログラミングやiPhoneアプリ開発を始めてみたい方を対象に、開発に必要な知識を基礎から解説していきます。今回は、プログラミングを学び始める前に、まずはMacの基本的な使い方を学び、Xcodeをインストールし、Playgroundを起動してみましょう。