Поиск пути / Определение направления - PullRequest
1 голос
/ 23 октября 2010

Я делаю простую игру для iPhone, используя cocos2d-iphone.У меня есть множество злодеев, «fiendSet», который должен перемещаться по полю, полному препятствий.Я провел последние три ночи, пытаясь заставить свой A * найти дорогу к работе.Я нашел фактическую реализацию A * здесь на stackoverflow, и она работает блестяще.Однако, как только я пытаюсь перемещать своих извергов, у меня возникают проблемы.

У каждого из моих извергов есть CGPoint с именем motionTarget, который содержит значения 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);
        }
    }
}

Это прекрасно работает для извергов, движущихся в одном направлении.Как только злодей должен обойти поворот, начинаются неприятности.Вместо того, чтобы сначала идти вверх, потом направо, потом вниз;мои друзья будут объединять движение вверх / вправо в один, они «режут углы».Я хочу, чтобы мои друзья перемещались либо на север / юг ИЛИ на восток / запад для каждого обновления позиции, но не на оба.Другими словами, я не хочу анимировать изменения в x и y одновременно.Надеюсь, это объяснение достаточно ясное ..

Я почти уверен, что у меня где-то есть логическая ошибка ... Я просто не смог выяснить это за последние три бессонные ночи после работы .. Помощь!

Ответы [ 2 ]

1 голос
/ 23 октября 2010

Вы должны отслеживать каждый узел на пути к цели.Таким образом, вы только анимируете движение к следующему узлу.Кроме того, вместо анимации вы можете использовать действие CCMoveTo.

0 голосов
/ 24 октября 2010

@ Алеф спасибо за ваше предложение. Я обнаружил, что именно код определяет, когда назначать новый объект 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);
}
}
...