Apple の新しい GameplayKit について、おそらくばかげた質問があります。
ゲーム用に 2D グリッドベースのノード レイアウトを作成しています。私は主に の機能が気に入っていますがGKGraphNode2D
、1 つの方法で微調整したいと考えています。特定の種類のノード ペアをトラバースするときに、条件付きでペナルティを追加したいと考えています。言い換えれば、いくつかのノードを単純な方法で接続し、いくつかのノードを接続して、それらの通過距離がアプリによって変更されるようにしたいと考えています。
GKGraphNode2D
サブクラス化とオーバーライドは完璧に機能する-costToNode:
と思いました! -estimatedCostToNode:
によって提供された値を返すsuper
こともあれば、ゲームに合わせて微調整することもあります。これら 2 つのメソッドはGKGraphNode
、 のスーパークラスである のメソッドですGKGraphdNode2D
。
残念ながら、これを実行しようとすると、サブクラスで呼び出されないように-costToNode:
見えます-estimatedCostToNode:
。これらのメソッドは、一連のサブクラス オブジェクトを含むオブジェクトを呼び出したGKGraphNode2D
ときに呼び出されることを期待しています。-findPathFromNode:toNode:
GKGraph
GKGraphNode2D
私は何を間違っていますか?
編集:
以下は私のコードです。
次のように、のサブクラスであるCheapNode
との2 つのクラスを作成します。ExpensiveNode
GKGraphNode2D
@import UIKit;
@import GameplayKit;
@interface CheapNode : GKGraphNode2D
@end
@implementation CheapNode
- (float)estimatedCostToNode:(GKGraphNode *)node {
return 1;
}
- (float)costToNode:(GKGraphNode *)node {
return 1;
}
@end
と
@import UIKit;
@import GameplayKit;
@interface ExpensiveNode : GKGraphNode2D
@end
@implementation ExpensiveNode
- (float)estimatedCostToNode:(GKGraphNode *)node {
return 100;
}
- (float)costToNode:(GKGraphNode *)node {
return 100;
}
@end
次に、テストで、いくつかのノードを作成して接続し、グラフに追加して、findPathFromNode:toNode:
メッセージをグラフに送信しました。次に、グラフが見つけたパスを確認しましたが、期待したものは見つかりませんでした。
- (void)testNodeCostsUsed {
/*
This is the graph we are creating:
A---B---C
| |
F---E---D
where all of the nodes are `CheapNode` objects, except 'B', which is an
`ExpensiveNode` object.
This test finds a path from node A to node C.
If the cost methods in the `CheapNode` and `ExpensiveNode` subclasses
are used, the route going from A to C around B (down, then right, then up)
should be used, since the cost of going from B to C is 100, and the cost of
going from any other node to any other node is 1
(see implementation of these classes).
Instead, we see `GKGraph` choosing the "shortest" route in terms of number
of nodes, from the top left immediately to the right to the top right.
*/
CheapNode *nodeA = [[CheapNode alloc] initWithPoint:(vector_float2){0, 0}];
ExpensiveNode *nodeB = [[ExpensiveNode alloc] initWithPoint:(vector_float2){1, 0}];
CheapNode *nodeC = [[CheapNode alloc] initWithPoint:(vector_float2){2, 0}];
CheapNode *nodeD = [[CheapNode alloc] initWithPoint:(vector_float2){2, 1}];
CheapNode *nodeE = [[CheapNode alloc] initWithPoint:(vector_float2){1, 1}];
CheapNode *nodeF = [[CheapNode alloc] initWithPoint:(vector_float2){0, 1}];
[nodeA addConnectionsToNodes:@[ nodeB, nodeF ] bidirectional:YES];
[nodeC addConnectionsToNodes:@[ nodeB, nodeD ] bidirectional:YES];
[nodeE addConnectionsToNodes:@[ nodeF, nodeD ] bidirectional:YES];
NSArray *allNodes = @[ nodeA, nodeB, nodeC, nodeD, nodeE, nodeF ];
GKGraph *graph = [GKGraph graphWithNodes:allNodes];
NSArray *nodes = [graph findPathFromNode:nodeA toNode:nodeC];
NSArray *expectedPath = @[ nodeA, nodeF, nodeE, nodeD, nodeC ];
NSArray *prohibitedPath = @[ nodeA, nodeB, nodeC ];
XCTAssert([nodes isEqualToArray:expectedPath], @"");
XCTAssertFalse([nodes isEqualToArray:prohibitedPath], @"");
}
このテスト ケースは失敗します。estimatedCostToNode:
また、 andがサブクラスcostToNode:
に送信されないことにも気付きましたGKGraphNode2D
(ログ ステートメントとブレークポイントで確認)。
この問題を示すサンプル プロジェクトを次に示します。Xcode の最新の開発者ベータ版 (2015 年 8 月 31 日現在、Xcode ベータ 6) でビルドおよび実行する必要があります。
編集2:
誰かが複製に興味がある場合は、この StackOverflow の質問のサンプル コードと説明をバグ ( http://www.openradar.me/22524760 ) として提出しました。iOS 9 がリリースされた後もバグが続く場合は、開発者サポート チケットを使用してこの問題の解決を試みます。
編集3:
Apple は、Developer Support Ticket で私に返事をくれました。彼らはこれがバグであることを認めており、(私が知る限り) iOS 9.2 ベータ 2 (7C46t) で修正されているようです。
編集4:
このフレームワークの別のバグを説明するために、サンプル プロジェクトを更新しました。