鬼が味方から逃げる処理についても、もしGameplayKitを使わない場合にどのような実装になるか考えてみます。下のような配置を想定して考えます。
今回は「障害物を避ける」「味方キャラから逃げる」という複数のルールがあるため、障害物を避ける時とは別のルールが必要になります。
実装としては下のようなものが考えられます。
・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)]) } // 省略 }
これで鬼が画面上のランダムな位置に出現するようになりました。
今回は「Agents, Goals, and Behaviors」を使った複雑なAIを作ってみましたが如何でしたか。
次回は鬼ごっこから離れて3Dゲームにおける「Agents, Goals, and Behaviors」の使い方を紹介します。
田町のベンチャーで働くエンジニア。
仕事ではiPhoneアプリの開発やRailsを使ったWebサービス開発を行っている。最近のマイブームはUnityを使った3Dゲーム開発。
Copyright © ITmedia, Inc. All Rights Reserved.