次は、AIに「逃げる」動きを実装します。通常の鬼ごっこのルールからは外れますが、鬼を倒すことのできる味方を追加しようと思います。鬼が味方から逃げる処理実装を通して、AIに「逃げる」動作を追加します。
最初に画面上に味方を配置します。GameSceneを以下のように修正してください。
class GameScene: SKScene {
// 省略
var sweeper = SKShapeNode(circleOfRadius: 10) // 今回追加
var sweeperAgent = GKAgent2D() // 今回追加
override func didMove(to view: SKView) {
player.fillColor = UIColor(red: 0.93, green: 0.96, blue: 0.00, alpha: 1.0)
player.physicsBody = SKPhysicsBody(circleOfRadius: 10)
addChild(player)
// ここから今回追加
sweeper.fillColor = UIColor(red: 255, green: 0.65, blue: 0.02, alpha: 1.0)
sweeper.physicsBody = SKPhysicsBody(circleOfRadius: 10)
addChild(sweeper)
sweeperAgent.maxAcceleration = 50
sweeperAgent.maxSpeed = 80
sweeperAgent.delegate = self
agentSystem.addComponent(sweeperAgent)
// ここまで今回追加
createObstacles()
setCreateEnemyTimer()
physicsWorld.gravity = CGVector()
}
// 省略
}
画面上に味方(緑の丸)を追加しました。
次は、「味方が鬼を追いかける処理」「味方と鬼が衝突したら鬼が消える処理」を実装します。GameSceneを以下のように修正してください。
class GameScene: SKScene {
// 省略
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),
GKGoal(toAvoid: obstacles, maxPredictionTime: 10)
], andWeights: [NSNumber(value: 1), NSNumber(value: 50)])
agentSystem.addComponent(anemyAgent)
enemyAgents.append(anemyAgent)
let goals = enemyAgents.map { GKGoal(toSeekAgent: $0) } // 今回追加
sweeperAgent.behavior = GKBehavior(goals: goals + [GKGoal(toAvoid: obstacles, maxPredictionTime: 10)]) // 今回追加
}
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 !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
}
}
// ここから今回追加
for (i, enemy) in enemies.enumerated() {
let dx = enemy.position.x - sweeper.position.x
let dy = enemy.position.y - sweeper.position.y
if sqrt(dx*dx + dy*dy) < enemy.frame.width / 2 + sweeper.frame.width / 2 + 5 {
enemy.removeFromParent()
enemies.remove(at: i)
agentSystem.removeComponent(enemyAgents[i])
enemyAgents.remove(at: i)
let goals = enemyAgents.map { GKGoal(toSeekAgent: $0) }
sweeperAgent.behavior = GKBehavior(goals: goals + [GKGoal(toAvoid: obstacles, maxPredictionTime: 10)])
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))
}
if let agent = agent as? GKAgent2D, agent == sweeperAgent {
sweeper.position = CGPoint(x: CGFloat(agent.position.x), y: CGFloat(agent.position.y)) // 今回追加
}
}
}
これで味方が鬼を追いかけるようになりました。
最後に、鬼が味方から逃げるようにします。GameSceneのcreateEnemyメソッドを以下のように修正します。
class GameScene: SKScene {
// 省略
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),
GKGoal(toAvoid: obstacles, maxPredictionTime: 10),
GKGoal(toFleeAgent: sweeperAgent) // 今回追加
], andWeights: [NSNumber(value: 5), NSNumber(value: 50), NSNumber(value: 1)]) // 今回修正
agentSystem.addComponent(anemyAgent)
enemyAgents.append(anemyAgent)
let goals = enemyAgents.map { GKGoal(toSeekAgent: $0) }
sweeperAgent.behavior = GKBehavior(goals: goals + [GKGoal(toAvoid: obstacles, maxPredictionTime: 10)])
}
// 省略
}
今回は下記の修正をすることで、鬼が味方キャラから逃げるようになりました。
anemyAgent.behavior = GKBehavior(goals: [
GKGoal(toSeekAgent: playerAgent),
GKGoal(toAvoid: obstacles, maxPredictionTime: 10),
GKGoal(toFleeAgent: sweeperAgent)
], andWeights: [NSNumber(value: 5), NSNumber(value: 50), NSNumber(value: 1)])
今回追加したのは4行目の「GKGoal(toFleeAgent: sweeperAgent)」という箇所です。このGKGoal(振る舞いのルール)は「特定のAgentから逃げる」というルールになります。引数にsweeperAgent(味方キャラ)を渡すことで、鬼に「味方キャラから逃げる」という振る舞いを追加しました。
iOS 9の最新機能で自動ルート検索を簡単にゲームに組み込む
iOS 10 SDKの新機能SiriKit、音声認識、iMessage拡張を自作アプリに生かすには
スマホ世代でも分かるMacの基本的な使い方&Xcodeをインストールする手順Copyright © ITmedia, Inc. All Rights Reserved.