我一直在关注本教程http://www.raywenderlich.com/4970/how-to-implement-a-pathfinding-with-cocos2d-tutorial,以实现用目标C编写的A *路径。
我的问题是它似乎永远无法找到结束位置的路径,因此永远循环。我也在使用JSTileMap。
我的班级
class ShortestPathStep: NSObject {
var gScore: Int!
var hScore: Int!
var position: CGPoint!
var parent: ShortestPathStep?
init(loc: CGPoint) {
super.init()
gScore = 0
hScore = 0
position = loc
parent = nil
}
func isEqualPath(other: ShortestPathStep) -> Bool {
return CGPointEqualToPoint(self.position!,other.position!)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func fScore() -> Int {
return self.gScore! + self.hScore!
}
}
func startPathfinding(startPoint:CGPoint, endPoint:CGPoint) { // take in values of CGPoint not tiled coordinate system
var layer : TMXLayer = map.layerNamed("World1")
var currentTile = layer.tileAt(hero.position)
var initialPosition = layer.coordForPoint(currentTile.position)
var endPosition = layer.coordForPoint(endPoint)
var pathFound = false
//self.openList = []
//self.closedList = []
insertInOpenSteps(ShortestPathStep(loc: initialPosition))
do {
println(openList.count)
var currentStep = openList.objectAtIndex(0) as ShortestPathStep
//println(currentStep)
closedList.addObject(currentStep)
openList.removeObjectAtIndex(0)
println(currentStep.position)
if CGPointEqualToPoint(currentStep.position, endPosition) {
println("I found a path")
// this part never runs
pathFound = true
openList = []
closedList = []
var tmpStep: ShortestPathStep! = currentStep
do {
println(tmpStep.gScore)
println(tmpStep.hScore)
} while tmpStep != nil
break
}
var adjacentTiles = walkableAdjacentTiles(currentStep.position)
for adjacentNodes in adjacentTiles {
var step : ShortestPathStep! = ShortestPathStep(loc: adjacentNodes.CGPointValue())
println(adjacentNodes.CGPointValue())
if closedList.containsObject(adjacentNodes) {
step = nil
continue
}
var moveCost = costToMoveFromStep(currentStep as ShortestPathStep, toAdjacentStep: step)
var index = openList.indexOfObject(step)
if index == NSNotFound {
step.parent = currentStep as ShortestPathStep
step.gScore = currentStep.gScore + moveCost
step.hScore = computeHScoreFromCoord(step.position, toCoord: endPosition)
insertInOpenSteps(step)
step = nil
}
else {
step = openList.objectAtIndex(index) as ShortestPathStep
if (currentStep.gScore + moveCost) < step.gScore {
step.gScore = currentStep.gScore + moveCost
insertInOpenSteps(step)
openList.removeObjectAtIndex(index)
step = nil
}
}
}
println(openList.count)
} while openList.count > 0
if CGPointEqualToPoint(initialPosition, endPoint) {
println("You are there already")
}
}
func computeHScoreFromCoord(fromCoord:CGPoint,toCoord:CGPoint) -> Int {
// Here we use the Manhattan method, which calculates the total number of step moved horizontally and vertically to reach the
// final desired step from the current step, ignoring any obstacles that may be in the way
return abs(Int(toCoord.x - fromCoord.x)) + abs(Int(toCoord.y - fromCoord.y))
}
func isValidTile(location:CGPoint) -> Bool {
var node = self.nodeAtPoint(location)
if node.name == "collision" {
return true
}
else {
return true
}
}
func walkableAdjacentTiles(tileLoc:CGPoint) -> NSMutableArray {
var tmp : NSMutableArray = [] // 0 = not walkable 1 = walkable (left,right,up,down)
var layer : TMXLayer = map.layerNamed("World1")
var position = layer.coordForPoint(hero.position)
var right: Bool = isValidTile(CGPoint(x: position.x + 1, y: position.y))
var left: Bool = isValidTile(CGPoint(x: position.x - 1, y: position.y))
var up: Bool = isValidTile(CGPoint(x: position.x , y: position.y + 1))
var down: Bool = isValidTile(CGPoint(x: position.x, y: position.y - 1))
var p : CGPoint
if left {
var p = CGPointMake(position.x - 1, position.y)
tmp.addObject(NSValue(CGPoint: p))
// layer.removeTileAtCoord(p)
}
if right {
var p = CGPointMake(position.x + 1, position.y)
tmp.addObject(NSValue(CGPoint: p))
// layer.removeTileAtCoord(p)
}
if up {
var p = CGPointMake(position.x, position.y + 1)
tmp.addObject(NSValue(CGPoint: p))
// layer.removeTileAtCoord(p)
}
if down {
var p = CGPointMake(position.x, position.y - 1)
tmp.addObject(NSValue(CGPoint: p))
// layer.removeTileAtCoord(p)
}
return tmp
}
func insertInOpenSteps(step: ShortestPathStep) {
var stepFScore = step.fScore()
var count = openList.count
var i = 0
for i; i < count; i++ {
if stepFScore <= self.openList.objectAtIndex(i).fScore() {
break
}
}
self.openList.insertObject(step, atIndex: i)
}
答案 0 :(得分:1)
您的代码存在错误:
var tmpStep: ShortestPathStep! = currentStep
do {
println(tmpStep.gScore)
println(tmpStep.hScore)
} while tmpStep != nil
break
由于您没有在任何时候更改tmpStep的值,因此您永远无法确定它是否为空。此外,你是强制解包tmpStep,如果tmpStep变为零,将导致运行时错误。
阅读ray wenderlich指南后,我建议您对代码进行以下更改:
var tmpStep: ShortestPathStep? = currentStep;
do {
println(tmpStep?.gScore)
println(tmpStep?.hScore)
tmpStep = tmpStep?.parent // Changes the value of tmpStep to traverse the list.
} while tmpStep != nil
这可以解决您的问题。
希望它有所帮助。
从您的源代码中我可以看到许多问题,为什么路径查找不起作用:
1:如前所述,您需要更改为以下行:
var tmpStep: ShortestPathStep? = currentStep
do {
println(tmpStep?.gScore)
println(tmpStep?.hScore)
tmpStep = tmpStep?.parent
} while tmpStep != nil
break
2:在walkableAdjacentTiles
功能中,您需要更改此行:
var position = layer.coordForPoint(hero.position)
到
var position = tileLoc
为了不断更新邻接列表,否则算法只是纯粹查看一个位置并且永远不会完成路径。
3:在startPathfinding
功能开始时,您需要确保清除已关闭和打开的列表。
func startPathfinding(startPoint:CGPoint, endPoint:CGPoint) { // take in values of CGPoint not tiled coordinate system
self.openList.removeAllObjects()
self.closedList.removeAllObjects()
// Rest of code here.
4:最后,你在这一行检查了不正确的包含:
var step : ShortestPathStep! = ShortestPathStep(loc: adjacentNodes.CGPointValue())
if closedList.containsObject(adjacentNodes) {
step = nil
continue
}
这需要检查步骤,而不是邻接列表
for adjacentNodes in adjacentTiles {
var step : ShortestPathStep! = ShortestPathStep(loc: adjacentNodes.CGPointValue())
if closedList.containsObject(step) {
step = nil
continue
}
这应该进行必要的更改以使算法工作。如果还有其他问题,请告诉我。
答案 1 :(得分:0)
首先,您的代码中至少有一个潜在的无限循环
如果tmpStep为nil,则这段代码永远循环:
do {
println(tmpStep.gScore)
println(tmpStep.hScore)
} while tmpStep != nil
其次,您应该在StackOverflow中正确缩进代码,使用当前不正确的缩进很难找到其他错误