1

Situation

I am using GKObstacleGraph for pathfinding on the following map: enter image description here

The orange areas are obstacles (GKPolygonObstacle), while the purple dots and lines are custom placed nodes (GKGraphNode2D) and their respective connections, which the entity can use to teleport through the obstacles.

Everything works fine and the entity finds the correct path: enter image description here

Goal

What I thought would be methodologically correct is to set the cost between the purple nodes to 0 (since they are portals). With this in mind, I first subclass all purple nodes as DoorGraphNodes:

import SpriteKit
import GameplayKit

class DoorGraphNode: GraphNode {

    var id: String!
    var floor: Int!
    var complement: DoorGraphNode!

    init(position: CGPoint, id: String, floor: Int) {
        self.id = id
        self.floor = floor
        let point = vector_float2(Float(position.x), Float(position.y))
        super.init(point: point)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func setComplement(doorNode: DoorGraphNode) {
        self.complement = doorNode
    }
}

Then, I subclass all GKGraphNode2D nodes to be added to the GKObstaclesGraph as GraphNode:

import SpriteKit
import GameplayKit

class GraphNode: GKGraphNode2D {

    override func cost(to node: GKGraphNode) -> Float {
        if let fromNode = self as? DoorGraphNode {
            if let toNode = node as? DoorGraphNode {
                if fromNode.complement == toNode {
                    return 0.0
                }
            }
        }
        return self.cost(to: node)
    }
}

This way, when I call obstacleGraph.findPath(from: startNode, to: targetNode) then GameplayKit should theoretically receive 0.0 when it calls the costToNode: method between two connected (complement) purple (DoorGraphNode) nodes.

Problem

In practice though, I get an EXC_BAD_ACCESS error with no details in the console: enter image description here

I don't think I am doing something wrong logic-wise. Do you have any idea why this happens?

Mark Brownsword
  • 2,287
  • 2
  • 14
  • 23
Filip Juncu
  • 352
  • 2
  • 10

1 Answers1

0

The line 22 in class GraphNode is calling itself. It should be calling its parent.

return super.cost(to: node)
Mark Brownsword
  • 2,287
  • 2
  • 14
  • 23
  • Thanks for your answer! I forgot to mention though that I have previously tried "super.cost(to: node)" as well as "self.cost(to: node)" with the same resulting error. Do you know what would be the problem? – Filip Juncu Jan 07 '17 at 13:44
  • You definitely should be using`super.cost(to: node)`. Also, it's odd to be casting the `GraphNode` as `DoorGraphNode`. It would be better to add another override of cost(to: node) in the `DoorGraphNode` class. – Mark Brownsword Jan 07 '17 at 20:46
  • Overridden `cost(to: node)` in the `DoorGraphNode` class never gets called. I think it's because not all nodes in the graph are of type `DoorGraphNode` (i.e. start and target points are `GraphNode` while other obstacle avoiding nodes are supposedly `GKGraphNode2D`). It sucks that there is so little available about GameplayKit so far. – Filip Juncu Jan 08 '17 at 01:11
  • This is not really a `GameplayKit` problem, is more OOP Design I think! The nodes in the graph should all be the same type. If you look at e.g. `GKGridGraph` you'll see it expects all nodes to be of type `GKGridGraphNode`. – Mark Brownsword Jan 08 '17 at 01:23
  • That's true, but according to Apple you are still able to subclass them and override the cost to other nodes. And that works, when I just return (unconditionally) a random float value. However, sometimes I need to return conditionally the default value by doing `super.cost(to: node)`. This doesn't work though, and sends everything in a infinite loop just as `self.cost(to: node)` does. That loop eventually crashes in the error I showed above. I find it very odd and it's unfortunately beyond my understanding of how things work. – Filip Juncu Jan 08 '17 at 09:36
  • 1
    Check out this [SO](http://stackoverflow.com/questions/32317628/subclass-of-gkgraphnode-costtonode-method-never-getting-called) post about subclassing `GKGraphNode2D` – Mark Brownsword Jan 08 '17 at 09:45
  • Also this [SO](http://stackoverflow.com/questions/31975084/costtonode-not-sent-to-gkgraphnode2d-subclass-in-gameplaykit) post is similar. Note that the bug discussed has been fixed. Point is more about how `GKGraphNode2D` is used. – Mark Brownsword Jan 08 '17 at 09:50
  • Thank you! I've referred previously to those topics as well. But even when I'm subclassing all nodes to `DoorGraphNode` so that it's all consistent, I still get an EXC_BAD_ACCESS. It seems to me like a bug that Apple hasn't yet fixed for all subclasses of `GKGraph` (I'm using `GKObstacleGraph`). I will try to come up with a different solution or just wait for it to get fixed. It's not that urgent anyway. – Filip Juncu Jan 08 '17 at 15:19