連載
» 2017年01月30日 05時00分 UPDATE

ゲームの「敵」キャラで分かる「人工知能」の作り方(1):iOS GameplayKitの「Agents, Goals, and Behaviors」で作る、鬼ごっごの鬼AI (3/3)

[杉本裕樹,マネーフォワード]
前のページへ 1|2|3       

Agents, Goals, and Behaviorsを使う

 最後に鬼の動きを「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、GKGoals、GKBehaviorの役割

 今回は「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インスタンスを渡すことで、ルールに基づいた行動をするようになります。

次回は、さらに複雑な条件で動くAIを作る

 今回は「Agents, Goals, and Behaviors」を使ったAIを作ってみましたがいかがでしたか。次回は障害物や味方キャラクターを追加して、さらに複雑な条件で動くAIを作ってみようと思います。

 今回作成したコードは、こちらからダウンロードできます。

筆者紹介

杉本裕樹

田町のベンチャーで働くエンジニア。

仕事ではiPhoneアプリの開発やRailsを使ったWebサービス開発を行っている。最近のマイブームはUnityを使った3Dゲーム開発。


前のページへ 1|2|3       

Copyright© 2017 ITmedia, Inc. All Rights Reserved.

@IT Special

- PR -

TechTargetジャパン

この記事に関連するホワイトペーパー

Focus

- PR -

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。