最後に鬼の動きを「Agents, Goals, and Behaviors」を使った形に置き換えてみようと思います。「GameScene.swift」を下のように修正します。
import SpriteKit
import GameplayKit
class GameScene: SKScene {
let player = SKShapeNode(circleOfRadius: 10)
var enemies = [SKShapeNode]()
var timer: Timer?
var prevTime: TimeInterval = 0
var startTime: TimeInterval = 0
var isGameFinished = false
// ここから今回追加分
let playerAgent = GKAgent2D()
let agentSystem = GKComponentSystem(componentClass: GKAgent2D.self)
var enemyAgents = [GKAgent2D]()
// ここまで今回追加分
// 省略
func createEnemy() {
let enemy = SKShapeNode(circleOfRadius: 10)
enemy.position.x = size.width / 2
enemy.fillColor = UIColor(red: 0.94, green: 0.14, blue: 0.08, alpha: 1.0)
enemy.physicsBody = SKPhysicsBody(circleOfRadius: enemy.frame.width / 2)
addChild(enemy)
enemies.append(enemy)
// ここから今回追加分
let anemyAgent = GKAgent2D()
anemyAgent.maxAcceleration = 30
anemyAgent.maxSpeed = 70
anemyAgent.position = vector_float2(x: Float(enemy.position.x), y: Float(enemy.position.y))
anemyAgent.delegate = self
anemyAgent.behavior = GKBehavior(goals: [
GKGoal(toSeekAgent: playerAgent),
])
agentSystem.addComponent(anemyAgent)
enemyAgents.append(anemyAgent)
// ここまで今回追加分
}
override func update(_ currentTime: TimeInterval) {
if prevTime == 0 {
prevTime = currentTime
startTime = currentTime
}
// ここから今回追加分
agentSystem.update(deltaTime: currentTime - prevTime)
playerAgent.position = vector_float2(x: Float(player.position.x), y: Float(player.position.y))
// ここまで今回追加分
// 下は今回で削除
// if Int(currentTime) != Int(prevTime) {
// enemies.forEach { enemy, _ in
// enemy.removeAllActions()
//
// let path = CGMutablePath()
// path.move(to: CGPoint())
// path.addLine(to: CGPoint(x: player.position.x - enemy.position.x, y: player.position.y - enemy.position.y))
// enemy.run(SKAction.follow(path, speed: 50.0))
// }
// }
if !isGameFinished {
for enemy in enemies {
let dx = enemy.position.x - player.position.x
let dy = enemy.position.y - player.position.y
if sqrt(dx*dx + dy*dy) < player.frame.width / 2 + enemy.frame.width / 2 {
isGameFinished = true
timer?.invalidate()
let label = SKLabelNode(text: "記録:\(Int(currentTime - startTime))秒")
label.fontSize = 80
label.position = CGPoint(x: 0, y: -100)
addChild(label)
break
}
}
}
prevTime = currentTime
}
}
// ここから今回追加分
extension GameScene: GKAgentDelegate {
func agentDidUpdate(_ agent: GKAgent) {
if let agent = agent as? GKAgent2D, let index = enemyAgents.index(where: { $0 == agent }) {
let enemy = enemies[index]
enemy.position = CGPoint(x: CGFloat(agent.position.x), y: CGFloat(agent.position.y))
}
}
}
// ここまで今回追加分
アプリを起動すると、鬼がプレイヤーを追い掛けてくるのが分かります。
今回は「GKAgent2D」「GKGoal」「GKBehavior」という3つのクラスを使いました。名前の通り、この3つが「Agents, Goals, and Behaviors」の主な要素です。
GKGoalは1つ1つのルールを表現するクラスです。今回は「GKGoal(toSeekAgent: playerAgent)」というplayerAgentに向かって動くようなものでした。逆にplayerAgentから逃げたり、特定の障害物を避けたりするものなどを作ることもできます。
そしてGKGoalをまとめるのがGKBehaviorクラスです。GKBehaviorは1つ以上のGKGoalを重み付け込みで管理します。今回はGKGoalが1つでしたが、次回以降では複数のGKGoalを使っていこうと思います。
GKAgent2Dはルールに基づいて移動するクラスです。GKAgent2DにGKBehaviorインスタンスを渡すことで、ルールに基づいた行動をするようになります。
今回は「Agents, Goals, and Behaviors」を使ったAIを作ってみましたがいかがでしたか。次回は障害物や味方キャラクターを追加して、さらに複雑な条件で動くAIを作ってみようと思います。
今回作成したコードは、こちらからダウンロードできます。
田町のベンチャーで働くエンジニア。
仕事ではiPhoneアプリの開発やRailsを使ったWebサービス開発を行っている。最近のマイブームはUnityを使った3Dゲーム開発。
iOS 9の最新機能で自動ルート検索を簡単にゲームに組み込む
iOS 10 SDKの新機能SiriKit、音声認識、iMessage拡張を自作アプリに生かすには
スマホ世代でも分かるMacの基本的な使い方&Xcodeをインストールする手順Copyright © ITmedia, Inc. All Rights Reserved.