しめ鯖日記

swift, iPhoneアプリ開発, ruby on rails等のTipsや入門記事書いてます

複数のGKGoalを使って複雑なAIを作成する

昨日調べた事の続きです。
この記事では、GKGoalを使って特定のオブジェクトに向かって移動するAgentを作成しました。
今回は「特定のオブジェクトに向かって移動」「別のオブジェクトから逃げる」の複数を指定した場合を試してみます。

GKGoalとGKAgentで目的に向かって動くオブジェクトを作ってみる - しめ鯖日記

昨日同様に、Gameプロジェクトを作成します。

f:id:llcc:20161211185859p:plain

GameScene.swiftを以下のように置き換えます。
昨日の記事と違い、GKBehaviorに複数のGKGoalを与えています。
こうする事でagent3にagent2から遠ざかりつつagent1へ移動する動きをさせる事ができます。

import SpriteKit
import GameplayKit

class GameScene: SKScene {
    let agentSystem = GKComponentSystem(componentClass: GKAgent2D.self)
    let agent1 = GKAgent2D()
    let agent2 = GKAgent2D()
    let agent3 = GKAgent2D()
    let node1 = SKSpriteNode(color: UIColor.brown, size: CGSize(width: 10, height: 10))
    let node2 = SKSpriteNode(color: UIColor.green, size: CGSize(width: 10, height: 10))
    let node3 = SKSpriteNode(color: UIColor.red, size: CGSize(width: 10, height: 10))
    var prevTime: TimeInterval = 0
    
    override func didMove(to view: SKView) {
        agent1.position = vector_float2(x: 100, y: 100)
        agent2.position = vector_float2(x: 300, y: 100)
        node1.position = CGPoint(x: Double(agent1.position.x), y: Double(agent1.position.y))
        node2.position = CGPoint(x: Double(agent2.position.x), y: Double(agent2.position.y))
        
        agent3.position = vector_float2(x: 300, y: 500)
        agent3.maxAcceleration = 10
        agent3.maxSpeed = 10
        agent3.delegate = self
        agent3.behavior = GKBehavior(goals: [
            GKGoal(toSeekAgent: agent1),
            GKGoal(toFleeAgent: agent2)
            ], andWeights: [100, 10]
        )
        agentSystem.addComponent(agent3)
        
        addChild(node1)
        addChild(node2)
        addChild(node3)
    }
    
    override func update(_ currentTime: TimeInterval) {
        let deltaTime = prevTime == 0 ? 0 : currentTime - prevTime
        prevTime = currentTime
        agentSystem.update(deltaTime: deltaTime)
    }
}

extension GameScene: GKAgentDelegate {
    func agentDidUpdate(_ agent: GKAgent) {
        if let agent = agent as? GKAgent2D {
            node3.position = CGPoint(x: Double(agent.position.x), y: Double(agent.position.y))
            print(agent.position)
        }
    }
}

この状態で起動するとagent2を避けつつagent1に向かう動きをします。
下図の右上がagent3、右下がagent2、左下はagent1を表しています。

f:id:llcc:20161211190512p:plain

もしここでandWeightsを両方100にした場合は少し動きが変わってきます。

agent3.behavior = GKBehavior(goals: [
    GKGoal(toSeekAgent: agent1),
    GKGoal(toFleeAgent: agent2)
    ], andWeights: [100, 100]
)

agent1に近づく動きとagent2から遠ざかる動きが重なり、下図のように真っ直ぐ左側に移動する事になります。

f:id:llcc:20161211190810p:plain