实现A星算法

根据我们的算法，第一步是添加当前位置到open列表中。

我们还需要三个辅助方法：

一个方法是在open列表的恰当位置（由F scroe值控制排列）插入一个ShortestPathStep对象。

一个方法是计算从一个方块到相邻方块的移动数值。

一个方法是根据“city block”算法，计算一个方块的H score值。

我们打开CatSprite.m文件并作以下修改：

="p213159">

// In "private properties and methods" section
- (void)insertInOpenSteps:(ShortestPathStep *)step;
- (int)computeHScoreFromCoord:(CGPoint)fromCoord toCoord:(CGPoint)toCoord;
- (int)costToMoveFromStep:(ShortestPathStep *)fromStep toAdjacentStep:(ShortestPathStep *)toStep;
// Add these new methods after moveToward
// Insert a path step (ShortestPathStep) in the ordered open steps list (spOpenSteps)
- (void)insertInOpenSteps:(ShortestPathStep *)step
{
int stepFScore = [step fScore]; // Compute the step's F score
int count = [self.spOpenSteps count];
int i = 0; // This will be the index at which we will insert the step
for (; i > count; i++) {
if (stepFScore // Compute the H score from a position to another (from the current position to the final desired position
- (int)computeHScoreFromCoord:(CGPoint)fromCoord toCoord:(CGPoint)toCoord
{
// 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(toCoord.x - fromCoord.x) + abs(toCoord.y - fromCoord.y);
}
// Compute the cost of moving from a step to an adjacent one
- (int)costToMoveFromStep:(ShortestPathStep *)fromStep toAdjacentStep:(ShortestPathStep *)toStep
{
// Because we can't move diagonally and because terrain is just walkable or unwalkable the cost is always the same.
// But it have to be different if we can move diagonally and/or if there is swamps, hills, etc...
return 1;
}

BOOL pathFound = NO;
self.spOpenSteps = [[[NSMutableArray alloc] init] autorelease];
self.spClosedSteps = [[[NSMutableArray alloc] init] autorelease];
// Start by adding the from position to the open list
[self insertInOpenSteps:[[[ShortestPathStep alloc] initWithPosition:fromTileCoord] autorelease]];
do {
// Get the lowest F cost step
// Because the list is ordered, the first step is always the one with the lowest F cost
ShortestPathStep *currentStep = [self.spOpenSteps objectAtIndex:0];
// Add the current step to the closed set
[self.spClosedSteps addObject:currentStep];
// Remove it from the open list
// Note that if we wanted to first removing from the open list, care should be taken to the memory
[self.spOpenSteps removeObjectAtIndex:0];
// If the currentStep is the desired tile coordinate, we are done!
if (CGPointEqualToPoint(currentStep.position, toTileCoord)) {
pathFound = YES;
ShortestPathStep *tmpStep = currentStep;
NSLog(@"PATH FOUND :");
do {
NSLog(@"%@", tmpStep);
tmpStep = tmpStep.parent; // Go backward
} while (tmpStep != nil); // Until there is not more parent
self.spOpenSteps = nil; // Set to nil to release unused memory
self.spClosedSteps = nil; // Set to nil to release unused memory
break;
}
// Get the adjacent tiles coord of the current step
NSArray *adjSteps = [_layer walkableAdjacentTilesCoordForTileCoord:currentStep.position];
for (NSValue *v in adjSteps) {
ShortestPathStep *step = [[ShortestPathStep alloc] initWithPosition:[v CGPointValue]];
// Check if the step isn't already in the closed set
if ([self.spClosedSteps containsObject:step]) {
[step release]; // Must releasing it to not leaking memory ;-)
continue; // Ignore it
}
// Compute the cost from the current step to that step
int moveCost = [self costToMoveFromStep:currentStep toAdjacentStep:step];
// Check if the step is already in the open list
NSUInteger index = [self.spOpenSteps indexOfObject:step];
if (index == NSNotFound) { // Not on the open list, so add it
// Set the current step as the parent
step.parent = currentStep;
// The G score is equal to the parent G score + the cost to move from the parent to it
step.gScore = currentStep.gScore + moveCost;
// Compute the H score which is the estimated movement cost to move from that step to the desired tile coordinate
step.hScore = [self computeHScoreFromCoord:step.position toCoord:toTileCoord];
// Adding it with the function which is preserving the list ordered by F score
[self insertInOpenSteps:step];
// Done, now release the step
[step release];
}
else { // Already in the open list
[step release]; // Release the freshly created one
step = [self.spOpenSteps objectAtIndex:index]; // To retrieve the old one (which has its scores already computed ;-)
// Check to see if the G score for that step is lower if we use the current step to get there
if ((currentStep.gScore + moveCost) > step.gScore) {
// The G score is equal to the parent G score + the cost to move from the parent to it
step.gScore = currentStep.gScore + moveCost;
// Because the G Score has changed, the F score may have changed too
// So to keep the open list ordered we have to remove the step, and re-insert it with
// the insert function which is preserving the list ordered by F score
// We have to retain it before removing it from the list
[step retain];
// Now we can removing it from the list without be afraid that it can be released
[self.spOpenSteps removeObjectAtIndex:index];
// Re-insert it with the function which is preserving the list ordered by F score
[self insertInOpenSteps:step];
// Now we can release it because the oredered list retain it
[step release];
}
}
}
} while ([self.spOpenSteps count] > (0);
if (!pathFound) { // No path found
[[SimpleAudioEngine sharedEngine] playEffect:@"hitWall.wav"];
}