寻路/决定方向

时间:2010-10-22 20:22:31

标签: iphone objective-c cocos2d-iphone pathfinder

我正在使用cocos2d-iphone制作简单的iPhone游戏。我有一系列的恶魔,“fiendSet”,它必须在一个充满障碍的场地周围航行。我花了最后三个晚上试图让我的A *寻路工作。我在stackoverflow上找到了实际的A *实现,它的工作非常出色。然而,一旦我试图移动我的恶魔我遇到了麻烦。

我的每个恶魔都有一个名为motionTarget的CGPoint,它包含了魔鬼必须去的地方的x和y值。如果仅将位置x和y设置为每秒一次绝对值,则可以这样工作:

-(void) updateFiendPositions:(ccTime)dt {
    for (MSWFiend *currFiend in fiendSet) {
         currFiend.position = ccp(currFiend.motionTarget.x,currFiend.motionTarget.y);
    }
}

然而,这看起来并不是很好,恶魔只是每秒“跳跃”20px,而不是很好地制作动画。我只将其实现为占位符方法来验证路径查找。现在我想要流畅的动画。这就是我所做的:

-(void) updatePositions:(ccTime) dt {
    for (MSWFiend *currFiend in fiendSet) {
        if (currFiend.motionTarget.x != -1 && currFiend.motionTarget.y != -1) {
            float x,y;      

            if ((int)floor(currFiend.position.x) < (int)floor(currFiend.motionTarget.x)) {
                x = currFiend.position.x+(currFiend.speed*dt);
            }
            if ((int)floor(currFiend.position.x) > (int)floor(currFiend.motionTarget.x)) {
                x = currFiend.position.x-(currFiend.speed*dt);
            }
            if (abs((int)floor(currFiend.position.x)-(int)floor(currFiend.motionTarget.x)) < 2) {
                x = currFiend.motionTarget.x;
            }

            if ((int)floor(currFiend.position.y) < (int)floor(currFiend.motionTarget.y)) {
                y = currFiend.position.y+(currFiend.speed*dt);
            }
            if ((int)floor(currFiend.position.y) > (int)floor(currFiend.motionTarget.y)) {
                y = currFiend.position.y-(currFiend.speed*dt);
            }
            if (abs((int)floor(currFiend.position.y)-(int)floor(currFiend.motionTarget.y)) < 2) {
                y = currFiend.motionTarget.y;
            }

            currFiend.position = ccp(x,y);
        }
    }
}

这对于向一个方向移动的恶魔来说非常有用。一旦恶魔绕过弯道,麻烦就开始了。而不是例如先上升,然后是正确,然后下来;我的恶魔将把上/右动作合二为一,他们是“偷工减料”。我只希望我的恶魔在每个位置更新中向东/向南移动 OR ,而不是两者。换句话说,我不想同时为x和y设置动画。我希望这个解释很清楚......

我很确定我在某个地方有一个逻辑错误..我在工作后的最后三个不眠之夜里找不到它..帮助!

2 个答案:

答案 0 :(得分:1)

您必须跟踪目标路径中的每个节点。这样,您只需将动画设置为下一个节点的动画。此外,您可以使用CCMoveTo操作代替自己动画。

答案 1 :(得分:0)

@Aleph感谢你的建议。我发现是代码确定何时分配新的motionTarget,这是错误的,而不是我开始发布的代码。当你提到跟踪每个节点的位置时,我想到了我的motionTarget确定代码,并在2-3小时后发现错误。我最终这样做了:

-(void) updatePositions:(ccTime) dt {
for (MSWFiend *currFiend in fiendSet) {
    int fiendGX,fiendGY,targetGX,targetGY,dGX,dGY;
    float x,y,snappedX,snappedY;
    BOOL snappedIntoPosition = FALSE;

    fiendGX = (int)round(100.0f*(currFiend.position.x/20));
    fiendGY = (int)round(100.0f*(currFiend.position.y/20));
    targetGX = (int)round(100.0f*(currFiend.motionTarget.x/20));
    targetGY = (int)round(100.0f*(currFiend.motionTarget.y/20));

    snappedX = currFiend.position.x;
    snappedY = currFiend.position.y;

    dGX = abs(fiendGX-targetGX);
    dGY = abs(fiendGY-targetGY);

    float snappingThreshold; //1 = snap when 0.1 from motionTarget.
    snappingThreshold = currFiend.speed/10;

    if (dGX < snappingThreshold && dGY < snappingThreshold) {
        snappingThreshold = currFiend.motionTarget.x;
        snappingThreshold = currFiend.motionTarget.y;
        int newPathStep;
        newPathStep = currFiend.pathStep + 1;
        currFiend.pathStep = newPathStep;
    }

    int gX,gY; 
    gX = [[currFiend.path objectAtIndex:currFiend.pathStep] nodeX];
    gY = (tileMap.mapSize.height-[[currFiend.path objectAtIndex:currFiend.pathStep] nodeY])-1;

    currFiend.motionTarget = ccp(gX*20,gY*20);          //Assign motion target to the next A* node. This is later used by the position updater.

    if (currFiend.motionTarget.x != -1 && currFiend.motionTarget.y != -1) {
        x = currFiend.motionTarget.x;
        y = currFiend.motionTarget.y;

        if ((int)floor(currFiend.position.x) < (int)floor(currFiend.motionTarget.x)) {
            //Move right
            x = snappedX+(currFiend.speed*dt);
            if (x > currFiend.motionTarget.x) {
                x = currFiend.motionTarget.x;
            }
            y = snappedY;
        }
        if ((int)floor(currFiend.position.x) > (int)floor(currFiend.motionTarget.x)) {
            //Move left
            x = snappedX-(currFiend.speed*dt);
            if (x < currFiend.motionTarget.x) {
                x = currFiend.motionTarget.x;
            }
            y = snappedY;
        }

        if ((int)floor(currFiend.position.y) < (int)floor(currFiend.motionTarget.y)) {
            //Move up
            y = snappedY+(currFiend.speed*dt);
            if (y > currFiend.motionTarget.y) {
                y = currFiend.motionTarget.y;
            }
            x = snappedX;
        }
        if ((int)floor(currFiend.position.y) > (int)floor(currFiend.motionTarget.y)) {
            //Move down
            y = snappedY-(currFiend.speed*dt);
            if (y < currFiend.motionTarget.y) {
                y = currFiend.motionTarget.y;
            }
            x = snappedX;
        }
    }
    currFiend.position = ccp(x,y);
}
}