1

cocos2d-iphoneを使って簡単なiPhoneゲームを作っています。私は、障害物でいっぱいのフィールドをナビゲートしなければならない「fiendSet」という一連のフィーンドを持っています。私は最後の3泊を過ごして、A*パスファインディングを機能させようとしました。私はここで実際のA*実装をstackoverflowで見つけました、そしてそれは見事に機能します。しかし、フィーンドを動かそうとすると、問題が発生します。

私の各フィーンドには、モーションターゲットと呼ばれるCGPointがあり、フィーンドが移動する場所のx値とy値が含まれています。位置xとyを1秒に1回だけ絶対値に設定すると、次のように機能します。

-(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);
        }
    }
}

これは、一方向に移動するフィーンドに最適です。悪鬼が曲がり角を曲がるはずだとすぐに、トラブルが始まります。たとえば、最初に上に、次に右に、次に下に行く代わりに。私の悪鬼は上/右の動きを1つに結合します、彼らは「角を切ります」。位置が更新されるたびに、フィーンドを北/南または東/西のいずれかに移動させたいだけです。両方ではありません。つまり、xとyへの変更を同時にアニメートしたくありません。この説明が十分に明確であることを願っています。

私はどこかに論理エラーがあると確信しています..私は仕事の後の最後の3つの眠れない夜の間それを理解することができませんでした..助けて!

4

2 に答える 2

1

ターゲットへのパスにある各ノードを追跡する必要があります。そうすれば、次のノードへのモーションのみをアニメーション化できます。また、アニメーションを自分で行う代わりに CCMoveTo アクションを使用することもできます。

于 2010-10-22T20:30:44.083 に答える
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);
}
}
于 2010-10-23T20:29:22.463 に答える