Reputation: 663
I'm trying to get a GKActor
to position SKNodes
in a scene. I thought I had this working. However, when I add a GKBehavior
to the actor, I get very erratic position changes flicking all over the place and the actors behaviour isn't working.
I'm using an entity-component architecture in my project, which is a little too complicated to show an example here, so I've created a dramatically simplified playground to illustrate the issue I'm seeing.
//: A SpriteKit based Playground
import PlaygroundSupport
import SpriteKit
import GameplayKit
extension CGPoint {
init(point: vector_float2) {
self.init(
x: CGFloat(point.x),
y: CGFloat(point.y)
)
}
}
class GameScene: SKScene, GKAgentDelegate {
private let playerAgent = GKAgent2D()
private var player : SKShapeNode!
private let enemyAgent = GKAgent2D()
private var enemy : SKShapeNode!
override func didMove(to view: SKView) {
player = SKShapeNode(circleOfRadius: 40)
player.fillColor = .green
addChild(player)
playerAgent.position.x = .random(in: -(640/2)...640/2)
playerAgent.position.y = .random(in: -(480/2)...480/2)
playerAgent.delegate = self
enemy = SKShapeNode(circleOfRadius: 10)
enemy.fillColor = .red
addChild(enemy)
enemyAgent.position.x = .random(in: -(640/2)...640/2)
enemyAgent.position.y = .random(in: -(480/2)...480/2)
enemyAgent.delegate = self
enemyAgent.behavior = GKBehavior(
goals: [
//GKGoal(toSeekAgent: playerAgent)
]
)
}
override func update(_ currentTime: TimeInterval) {
super.update(currentTime)
playerAgent.update(deltaTime: currentTime)
enemyAgent.update(deltaTime: currentTime)
}
func agentDidUpdate(_ agent: GKAgent) {
if agent == enemyAgent {
enemy.position = CGPoint(point: enemyAgent.position)
print(enemy.position)
}
if agent == playerAgent {
player.position = CGPoint(point: playerAgent.position)
}
}
@objc static override var supportsSecureCoding: Bool {
get {
return true
}
}
}
let sceneView = SKView(frame: CGRect(x:0 , y:0, width: 640, height: 480))
if let scene = GameScene(fileNamed: "GameScene") {
scene.scaleMode = .aspectFill
sceneView.presentScene(scene)
}
PlaygroundSupport.PlaygroundPage.current.liveView = sceneView
This Playground shows the two nodes placed where their agents are positioned. It's working how I expet. However, once the GKGoal
is uncommented, the position of the enemyAgent
that is printed out wildly fluxuates and doesn't move toward the playerAgent
. This is not what I expeted to happen.
Clearly I'm doing somthing wrong but I can't see where i've made a mistake. I'd love some help from someone with more experince working with GameplayKit
. Thank You.
Upvotes: 0
Views: 66
Reputation: 663
I figured out the issue. The GKAgent
s update function takes a delta time, and the SKScene
s update function provides a current time. I didn't spot this mismatch as they are both TimeInterval
s and I was passing it directly with out converting it.
For anyone stumbling across this the way I converted the currentTime
to a deltaTime
was storing a lastUpdate
like this;
var lastUpdate: TimeInterval = 0
override func update(_ currentTime: TimeInterval) {
super.update(currentTime)
defer { lastUpdate = currentTime }
guard lastUpdate != 0 else {
return
}
let deltaTime = currentTime - lastUpdate
playerAgent.update(deltaTime: deltaTime)
enemyAgent.update(deltaTime: deltaTime)
}
I hope this helps someone, as it took me far too long to spot this. I think Apple could make this easy mistake more noticeable by printing an error if the delta time is too big or something.
Upvotes: 1