GameplayKit > Scene Editor Navigation Graph > How to use it for pathfinding?

对着背影说爱祢 提交于 2019-12-23 19:25:15

问题


Not long ago, Apple introduced GameplayKit elements to Xcode's Scene Editor, which is great. However, I seem to have issues with the Navigation Graph element:

What I try to achieve is to draw a GKGraph from the Scene Editor, retrieve it in code, and use it as a base for pathfinding.

So I draw a GKGraph first:

Then I retrieve it in GameScene.swift like this:

graph = self.graphs.values.first

where graphs is a predefined array by Apple to store the GKGraphs from the Scene Editor. So far so good.

Then I want for the player to find the path to the tap location on screen. For this, I use UITapGestureRecognizer with the following callback method:

var moving = false
func moveToLocation(recognizer: UITapGestureRecognizer) {
    var tapLocation = recognizer.location(in: recognizer.view!)
    tapLocation = self.convertPoint(fromView: tapLocation)

    guard (!moving) else { return }
    moving = true

    let startNode = GKGraphNode2D(point: vector_float2(Float(player.visualComponent.node.position.x), Float(player.visualComponent.node.position.y)))
    let endNode = GKGraphNode2D(point: vector_float2(Float(tapLocation.x), Float(tapLocation.y)))

    NSLog(graph.nodes.debugDescription)

    graph.connectToLowestCostNode(node: startNode, bidirectional: true)
    graph.connectToLowestCostNode(node: endNode, bidirectional: true)

    NSLog(graph.nodes.debugDescription)

    let path: [GKGraphNode] = graph.findPath(from: startNode, to: endNode)
    guard path.count > 0 else { moving = false; return }

    var actions = [SKAction]()

    for node: GKGraphNode in path {
        if let point2d = node as? GKGraphNode2D {
            let point = CGPoint(x: CGFloat(point2d.position.x), y: CGFloat(point2d.position.y))
            let action = SKAction.move(to: point, duration: 1.0)
            actions.append(action)
        }
    }

    graph.remove([startNode, endNode])

    // Convert those actions into a sequence action, then run it on the player node.
    let sequence = SKAction.sequence(actions)
    player.visualComponent.node.run(sequence, completion: { () -> Void in
        // When the action completes, allow the player to move again.
        self.moving = false
    })
}

Using this method, I get the player to go to the tap location. The problem is that the path returned by GameplayKit only includes the startNode and the endNode, meaning that the player does not walk on the the pre-drawn GKGraph at all but walks straight to the endNode.

Note: When I'm first running NSLog(graph.nodes.debugDescription) it lists all 10 pre-drawn nodes. When I'm then running it again after graph.connectToLowestCostNode, I get all 12 nodes. So my graph seems to contain everything needed for pathfinding.

What do you think is the problem? Why is graph.findPath not using the pre-drawn 10 nodes to define the path? Your answers would be much appreciated.


回答1:


It seems like GameplayKit's .findPath method does not work properly when called on a GKGraph created from Scene Editor. What I did is, I cloned the nodes from the pre-drawn GKGraph to a programmatically created GKGraph:

let newGraph = GKGraph()
for drawnNode in graph.nodes! {
    newGraph.add([drawnNode])
}

Then, .findPath on it works just fine:

newGraph.connectToLowestCostNode(node: startNode, bidirectional: true)
newGraph.connectToLowestCostNode(node: endNode, bidirectional: true)
let path: [GKGraphNode] = newGraph.findPath(from: startNode, to: endNode)

Variable path contains now a path generated considering all 10 + 2 nodes.

Wrap-up: You cannot directly use a Navigation Graph created in Scene Editor for pathfinding. My solution was to first clone its nodes to a programmatically created GKGraph and then use the latest to do the rest.



来源:https://stackoverflow.com/questions/41207550/gameplaykit-scene-editor-navigation-graph-how-to-use-it-for-pathfinding

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!