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を起動してみましょう。



