連載
» 2017年04月03日 05時00分 公開

SwiftのGameplayKitでAIに追いかける、避ける、逃げる処理を追加するにはゲームの「敵」キャラで分かる「人工知能」の作り方(2)(4/4 ページ)

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

鬼が味方から逃げる処理(GameplayKitを使わない場合)

 鬼が味方から逃げる処理についても、もしGameplayKitを使わない場合にどのような実装になるか考えてみます。下のような配置を想定して考えます。

 今回は「障害物を避ける」「味方キャラから逃げる」という複数のルールがあるため、障害物を避ける時とは別のルールが必要になります。

実装としては下のようなものが考えられます。

  1. フィールドを格子状に区切る
  2. プレイヤーに近いフィールドにプラスの点数を付与する
  3. 味方キャラに近いフィールドにマイナスの点数を付与する
  4. 鬼は隣接するフィールドの中で、一番点数の高い箇所に移動する


・1. フィールドを格子状に区切る

 まずはフィールドを下のように区切ります。

・2. プレイヤーに近いフィールドを加点する

 次にフィールドに点数を付けます。点数はプレイヤーからの距離に応じたものを付けます。障害物がある場所だけは例外として0点とします。

・3. 味方キャラに近いフィールドを減点する

 今度は逆に味方キャラから近いフィールドにマイナス点を付けます。

 加点と減点を合計すると、以下のような点数になります。

・4. 隣接するフィールドの中で、一番点数の高い箇所に移動する

 最後に今までの結果を使って鬼を動かします。鬼は「隣接しているフィールドの中で一番点数の高いところへ移動する」というルールで動かします。

実行結果

 実際に動かすと以下のようになります。今回はフィールド5x5で区切っているので無駄が多いですが、さらに細かく区切ればより正確な最短ルートを出すことができます。

鬼の出現位置をランダムにする

 最後に、鬼の出現位置を、右端でなく画面上のランダムな位置にします。ランダムな位置の生成はGameplayKitの「Randomization」機能を使ってみようと思います。

 Randomizationはランダムな数字や真偽値を出力する機能です。arc4random_uniform関数に近いのですが、乱数の上限下限の設定やガウス分布に従う乱数の生成などさまざまな機能を備えています。

 今回はこの機能を使って鬼の出現位置をランダムにしてみます。GameSceneのcreateEnemyメソッドを以下のように修正してください。

class GameScene: SKScene {
    // 省略
 
    func createEnemy() {
        // ここから今回追加
        guard let viewFrame = view?.frame else {
            return
        }
        let xDistribution = GKShuffledDistribution(lowestValue: -Int(viewFrame.width / 2), highestValue: Int(viewFrame.width / 2))
        let yDistribution = GKShuffledDistribution(lowestValue: -Int(viewFrame.height / 2), highestValue: Int(viewFrame.height / 2))
        // ここまで今回追加
 
        let enemy = SKShapeNode(circleOfRadius: 10)
        enemy.position.x = CGFloat(xDistribution.nextInt()) // 今回修正
        enemy.position.y = CGFloat(yDistribution.nextInt()) // 今回修正
        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 = 200
        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)])
    }
 
    // 省略
}

 これで鬼が画面上のランダムな位置に出現するようになりました。

次回は、3Dゲームにおける「Agents, Goals, and Behaviors」の使い方

 今回は「Agents, Goals, and Behaviors」を使った複雑なAIを作ってみましたが如何でしたか。

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

 次回は鬼ごっこから離れて3Dゲームにおける「Agents, Goals, and Behaviors」の使い方を紹介します。

筆者紹介

杉本裕樹

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

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


前のページへ 1|2|3|4       

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

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

メールマガジン登録

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