次は、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(味方キャラ)を渡すことで、鬼に「味方キャラから逃げる」という振る舞いを追加しました。
Copyright © ITmedia, Inc. All Rights Reserved.