Simone Pistecchia
Simone Pistecchia

Reputation: 2840

In Gameplaykit, how can I add a delay GKGoal time in GKAgent2D behavior?

I have a GKEntity that has a GKAgent2D component. Its behaviors are GKGoal, toWander: and toStayOnPath:maxPredictionTime:. The entity wanders continuously in the scene; however, I would like it to stop wandering for a while. For example, if the entity is a sheep that wanders about, I would like it to stop periodically to eat and, after a delay, start wandering again.

UPDATE:

In the Entity:

addComponent(MoveIdleComponent(maxSpeed: 60, maxAcceleration: 6, radius: Float(node.texture!.size().width * 0.3), entityManager: entityManager))

MoveIdleComponent

class MoveIdleComponent : GKAgent2D, GKAgentDelegate {

let entityManager: EntityManager

init(maxSpeed: Float, maxAcceleration: Float, radius: Float, entityManager: EntityManager) {
    self.entityManager = entityManager
    super.init()
    delegate = self
    self.maxSpeed = maxSpeed
    self.maxAcceleration = maxAcceleration
    self.radius = radius
    print(self.mass)
    self.mass = 0.01
}


func agentWillUpdate(agent: GKAgent) {
    guard let spriteComponent = entity?.componentForClass(SpriteComponent.self) else {
        return
    }

    self.position = float2(spriteComponent.node.position)
}

func agentDidUpdate(agent: GKAgent) {
    guard let spriteComponent = entity?.componentForClass(SpriteComponent.self) else {
        return
    }

    spriteComponent.node.position = CGPoint(position)
}



override func updateWithDeltaTime(seconds: NSTimeInterval) {

    super.updateWithDeltaTime(seconds)

    behavior = WanderBehavoir(targetSpeed: maxSpeed)
}
}

WanderBehavoir:

class WanderBehavoir: GKBehavior {

  init(targetSpeed: Float) {
    super.init()

    if targetSpeed > 0 {
        setWeight(0.5, forGoal: GKGoal(toWander: targetSpeed))
    }
}
}

How can I do this?

Thanks in advance

Upvotes: 2

Views: 644

Answers (2)

Simone Pistecchia
Simone Pistecchia

Reputation: 2840

Ok, i found a solution with @rickster suggestion. I post it if can help someone. I've added pause value. if pause is true, the weight of speed change to 1, with GKGoal(toReachTargetSpeed: 0)

in WanderBehavoir class:

class WanderBehavoir: GKBehavior {

init(targetSpeed: Float, entityManager: EntityManager, pause: Bool) {

    super.init()

    var weightWander : Float = 1.0
    var weightSpeed  : Float = 0.0

    if pause {
        weightWander = 0
        weightSpeed = 1
    }

    //   |  |
    // --A--B--
    //   |  |

    if targetSpeed > 0 {
        let lato = Float(500.0)
        let pts = [vector_float2(-lato,0),vector_float2(+lato,0)]

        let path = GKPath(points: UnsafeMutablePointer(pts), count: pts.count, radius: 980, cyclical: true)

        let obstacleNode = entityManager.nodesWithUnitType(Tree)
        let obstacles = SKNode.obstaclesFromNodePhysicsBodies(obstacleNode)

            setWeight(0.5,          forGoal: GKGoal(toAvoidObstacles: obstacles, maxPredictionTime: 0.5))
            setWeight(0.2,          forGoal: GKGoal(toStayOnPath: path, maxPredictionTime: 0.5))
            setWeight(weightWander, forGoal: GKGoal(toWander: targetSpeed))
            setWeight(weightSpeed,  forGoal: GKGoal(toReachTargetSpeed: 0))
        }
    }
}

In class class MoveIdleComponent : GKAgent2D, GKAgentDelegate pause switch true and false after delta time randomly

private var lastUpdateInterval: NSTimeInterval = 0
var setPause = true
var randomTimeStop = NSTimeInterval(Int(5...8))
var randomTimeMove = NSTimeInterval(Int(10...20))

override func updateWithDeltaTime(seconds: NSTimeInterval) { 
    super.updateWithDeltaTime(seconds)        

    lastUpdateInterval += seconds

    if setPause {
        if lastUpdateInterval > randomTimeStop {
            setPause = !setPause
            lastUpdateInterval = 0
            randomTimeMove = NSTimeInterval(Int(10...20))
        }
    }
    else {
        if lastUpdateInterval > randomTimeMove {
            setPause = !setPause
            lastUpdateInterval = 0
            randomTimeStop = NSTimeInterval(Int(5...8))
        }

    }
    print("randomTimeMove \(randomTimeMove)")

    behavior = WanderBehavoir(targetSpeed: maxSpeed, entityManager: entityManager, pause: setPause)
}

Upvotes: 0

rickster
rickster

Reputation: 126177

There doesn't seem to be a GKGoal(toEatFood:withFrequency:) API, so you'll have to step back a bit toandthink about how to set the agent's goals to achieve your goals.

If you want the agent to stop wandering, or stop following a path, for some period of time, what you want is for those to no longer be its goals. (And furthermore, you want it to stop, not continue with whatever direction and speed when you took away its goals, so you'll want to introduce a toReachTargetSpeed: goal for a speed of zero.)

There are two general ways to do this:

  • Have your behavior include wander, follow-path, and speed (of zero) goals, with weights set such that wander and follow-path outweigh speed. When you want to switch between wander+path behavior and stopping behavior, use setWeight(_:forGoal:) to make the speed goal outweigh the others.

  • Have one behavior that includes wander and follow-path goals, and another with a speed (of zero) goal, and set the agent's behavior property when you want to switch between them.

Upvotes: 1

Related Questions