1

我已经为此奋斗了一段时间,我的菜鸟大脑无法完全解决它。我有一个标准的瓷砖地图,目前使用以下代码在地图上移动我的敌人精灵

-(void) movePlayer:(ccTime)deltaTime {

    if (CGPointEqualToPoint(self.position, requestedPosition))
        return;


    float step = kPlayerSpeed * deltaTime;
    float dist = ccpDistance(self.position, requestedPosition);
    CGPoint vectorBetweenAB = ccpSub(self.position, requestedPosition);

    if (dist <= step) {
        self.position = requestedPosition;
        [self popPosition];
    } else {
        CGPoint normVectorBetweenAB = ccpNormalize(vectorBetweenAB);
        CGPoint movementVectorForThisFrame = ccpMult(normVectorBetweenAB, step);

        if (abs(vectorBetweenAB.x) > abs(vectorBetweenAB.y)) {
            if (vectorBetweenAB.x > 0) {
                [self runAnimation:walkLeft];
            } else {
                [self runAnimation:walkRight];
            }
        } else {
            if (vectorBetweenAB.y > 0) {
                [self runAnimation:walkDown];
            } else {
                [self runAnimation:walkUp];
            }
        }

        if (self.position.x > movementVectorForThisFrame.x) {
            movementVectorForThisFrame.x = -movementVectorForThisFrame.x;
        }
        if (self.position.y > movementVectorForThisFrame.y) {
            movementVectorForThisFrame.y = -movementVectorForThisFrame.y;
        }
        self.position = ccpAdd(self.position, movementVectorForThisFrame);
    }

}

movePlayer: 由类 updateWithDeltaTime: 方法调用。ivar requestedPosition 也在 updateWithDeltaTime 方法中设置,它基本上从队列中获取下一个要移动到的点。这些点可以在地图上的任何位置,因此如果它们与敌人成对角线方向,则敌人精灵将直接移动到该点。但是我如何更改上面的代码以将运动限制为仅垂直和水平运动,以便敌人的运动沿着对角线路径“楼梯”,走曼哈顿距离(我认为它被称为)。如下图所示... S 是起点 F 是终点,数字是沿其路径的每个中间点,以创建楼梯式对角线运动。最后,我打算能够打开和关闭此行为,

 | | | | | | | | | |
 | | | | | | | | | |
 | |F| | | | | | | |
 | |5|4| | | | | | |
 | | |3|2| | | | | |
 | | | |1|S| | | | |
 | | | | | | | | | |
 | | | | | | | | | |
 | | | | | | | | | |
 | | | | | | | | | |
4

2 回答 2

1

所以,我不确定是否有任何非常简单的方法可以做到这一点。我建议您计算距离终点有多远。然后得到y差和x差。然后,如果 y 差异大于 x,则将精灵向上移动设定的量。如果 x 差异更大,则将精灵向左移动设定的量。这样,精灵将继续向上和向左移动,因为它会慢慢减小与终点的差异。这就是我推荐的逻辑。本质上:

CGPoint difference = ccpSub(finishPoint, startPoint);
//Be aware that this if statement will not work for negative distances. Only for the example you gave!
if(difference.y>difference.x) {
     sprite.position = ccp(sprite.position.x, sprite.position.y+tileSize);
} else {
     sprite.position = ccp(sprite.position.x+tileSize, sprite.position.y);
}
于 2012-09-26T12:54:40.187 回答
0

所以我找到的当前解决方案如下......

-(void)pathfind {
    //Get a reference to the tile map
    CCTMXTiledMap *tileMap = (CCTMXTiledMap *)[[[[CCDirector sharedDirector] runningScene] getChildByTag:kStartLayer] getChildByTag:kMapNode];
    NSAssert(tileMap != nil, @"No Tile map");

    //Convert self.position to tile coordinates and set to both vars. stepTileCoord so that we can add a tile in direction of travel.
    CGPoint selfTileCoord = [tileMap tileCoordFromLocation:self.position];
    CGPoint stepTileCoord = [tileMap tileCoordFromLocation:self.position];

    //Init this var to keep track of the last tile worked out so the next one can be worked out from it. We start at self.position.
    CGPoint lastTileCoord = selfTileCoord;

    //For loop, iterates over each orginal position in the requestedPositionQueue.
    for (int i=0; i < [requestedPositionQueue count]; i++) {

        //Get the current original path tile coordinate.
        CGPoint requestedTileCoord = [[requestedPositionQueue objectAtIndex:i] CGPointValue];
        NSMutableArray *tempPoints = [NSMutableArray array];

        //While loop interates until it has worked out every intermediate step to the original path tile.
        while (!CGPointEqualToPoint(requestedTileCoord, stepTileCoord)) {

            //FIXME: what happens if path takes us back over the orignal start point?
            if (CGPointEqualToPoint(selfTileCoord, requestedTileCoord)) {
                //Not sure if this will cause an issue.
                break;
            }

            CGPoint vectorToDest = ccpSub(lastTileCoord, requestedTileCoord);

            if (abs(vectorToDest.x) > abs(vectorToDest.y)) {
                if (vectorToDest.x > 0) {
                    stepTileCoord.x -= 1;
                } else {
                    stepTileCoord.x += 1;
                }
            } else {
                if (vectorToDest.y > 0) {
                    stepTileCoord.y -= 1;
                } else {
                    stepTileCoord.y += 1;

                }
            }

            //If the tile worked out is the requestedTileCoord then break, no need to add it to tempPoints as it will already be in the requestedPosition Queue.
            if (CGPointEqualToPoint(requestedTileCoord, stepTileCoord)) {
                break;
//                CCLOG(@"%@", [requestedPositionQueue description]);
            } else {
                //Save this tile to tempPoints arrway. And save it to lastTileCoord.
                [tempPoints addObject:[NSValue valueWithCGPoint:stepTileCoord]];
                lastTileCoord = stepTileCoord;
//                CCLOG(@"\n{%f, %f}", lastTileCoord.x, lastTileCoord.y);
            }
        }
        //As we have now got an array, tempPoints, with all the intermediate step points to current point out of requestedPositionQueue we shall add all objects in tempPoints to requestedPositionQueue. NSIndexSet will ensure its added at the correct location in array.
        NSIndexSet *indexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(i, [tempPoints count])];
        [requestedPositionQueue insertObjects:tempPoints atIndexes:indexes];
//        CCLOG(@"%@", [requestedPositionQueue description]);
        //i is updated so the next point pulled out of the array isn't one of the worked out intermediate steps.
        i += [tempPoints count];
    }
}

因此,首先,我将字符的平铺坐标路径保存在 ivar 数组中,例如...

requestedPositionQueue = [NSMutableArray arrayWithObjects:
                                      [NSValue valueWithCGPoint:CGPointMake(7, 18)],
                                      [NSValue valueWithCGPoint:CGPointMake(11, 18)],
                                      [NSValue valueWithCGPoint:CGPointMake(7, 22)],
                                      [NSValue valueWithCGPoint:CGPointMake(7, 18)],
                                      [NSValue valueWithCGPoint:CGPointMake(11, 22)],
                                      nil];

所以你可以看到这有一些点需要这种形式的对角线运动。然后我调用 pathfind 方法,它遍历 requestedPositionQueue 并添加所有中间图块坐标,确保它始终垂直或水平选择一个图块,但在完成整个路径之前从不与当前图块对角地相邻。

然后在 update: 方法中,我遍历 requestedPositionArray,从中获取下一个图块坐标,将其转换为像素位置,然后将其分配给我的 requestedPosition ivar,然后运行 ​​movePlayer: 方法(原始帖子中的代码)。

为了我自己的利益,我在寻路方法中添加了评论,因此可能不是那么全面,但它们可能有助于您理解我的想法。

最后,这是我想出的最好的方法,它允许我确保我可以将我的角色移动到一个像素位置而不受限制,或者如果我想将它们移动到那里但将它们限制为只能通过平铺中心垂直或水平移动。因此,如果您能找到改进和优化此代码的方法,请这样做,否则任何建设性的批评都会受到赞赏。

编辑:FIXME:在那里突出显示了一个我还没有时间查看的潜在错误。如果需要,我会在调查并修复后重新发布。

于 2012-09-27T03:35:00.267 回答