タワーディフェンスゲームで敵が歩ける道が常にあることを確認する方法は?


7

2Dタワーディフェンスゲームを作っています。これまでのところ、ゲームのグリッドとして機能する2D配列があります。私はそれにタワーを配置し、敵を走らせ、ドラッグしてタワーを発射することができます。

今、私はタワー配置ロジックの問題に直面しています。敵が歩ける道が常にあることを望みます。つまり、ユーザーが塔を設置することで完全に道を塞ぐことができないようにする必要があります。例えば。ユーザーがマップ上にタワーを垂直に配置する場合、アルゴリズムは、垂直線を完成させるタワーの配置を防止する必要があります。または、他の方法では、敵が脱出できるように、少なくとも1つの空き(歩行可能な)スペースが必要です。

私の現在のロジックは、タワーが設置されるたびにすべての方向をチェックします。上方にタワーがある場合は、壁にぶつかるまで、その上部タワーで同じ関数を再度呼び出します。上向きの壁の場合は1を返し、下向きの壁の場合は5を返し、タワーがある場合は関数(アップ/ダウンタワー)を返します。ここにコードがあります:

int checkCollision(tower)
{                           
    if( there is a  tower up) 
    return checkCollision(up tower);

    if(there is a tower down) 
    return checkCollision(down tower);                                      

            ......all directions.....       

    if( there is a wall on UP )     
        return 1;

    if( there is a wall DOWN ) 
        return 5;

        ....all walls......

    return 0;   
}   

今私が欲しいのは、北の壁と南の壁があるどうかを同時に確認するか、他の可能性(上下、斜め、斜め下など)で他の方向を確認して、ユーザーに許可しないことです敵のために残された場所が1つあるはずなので、タワーを配置します。

現在、自分のコードに不満があります。私のコードは壁が見つかったことを示していますが、壁が一方向で見つかり、壁が別の方向でも見つかったことを確認するにはどうすればよいですか?私は次のような可能性に行きたくありません:

if(checkCollision(tower) == 1 && checkCollision(tower) == 5) 
  "You cannot place"

私は次のようなものが欲しい:

    if( any combination of more than 2 wall found and there is entry/exit point in between)  //so it is wall to wall
    "You cant place"

また、2つの側面に壁がある場合(上下、斜めなど)、ユーザーがタワーを設置できないようにして、フラグを事前に計算してみましたが、それでも機能しません。


パスは常に同じ幅(つまり、2つのタイル幅)ですか?
リチャードマースケル-Drackir、2011年

回答:


23

AIがまだ明確なルートを持っているかどうかを確認するためにパスファインディングアルゴリズムを使用する方が簡単ではないでしょうか?おそらくあなたはすでに1つを使って敵を入口から出口までナビゲートさせるので、タワーを追加して実行するだけで、失敗した場合、タワーは許可されません。


タワーの防衛ゲームで通常使用されるそのようなアルゴの参考資料を教えてください。
Syed

タワーディフェンスに固有ではありませんが、A *の初心者向けの優れた紹介と、より詳細な処理を次に示します。エンジンを使用している場合は、おそらくA *実装が利用可能であり、使用できるかなりの数のパスファインディングライブラリがあります。タワーディフェンスに固有のこの質問への回答は、A *よりも優れたアルゴリズムがあると主張していますが、私はそれについて詳しくありません
SimonW

グリッドの配置を最初に行う必要があると思うので、敵を最初から最後まで実行するようにアルゴをまだコーディングしていません。壁の上/下/右/左の壁が見つかるまでタワーを追跡する必要があるので、上記のように壁と壁のチェックを試してみました。「フィールドランナー」のようにゲームを作りたいです。壁のチェックを続けたり、他のアルゴリズムに移行したりするとどうなりますか?私は本当に自分の仕事に行き詰まっています:| Unity3Dゲームエンジンを使用したem
Syed

1
ゲームを作るときの私の通常の計画は、すべての部分を最小限のプレイ可能な状態にして、そこから行くことです。つまり、プレイヤーがパスをブロックすることを禁止するなどの難しいことを無視し、代わりに最初から最後まで敵を送れるようにし、プレイヤーが敵を撃つことができるようにします。勝ったり負けたりできるゲームを手に入れたら、それが楽しくなるか壊れないようにするために何でもしてください。素晴らしいまで繰り返します。
SimonW 2011年

1
Unityへのパスファインディングを取得するには、この無料のプロジェクトをご覧ください。経験が浅い場合は、ライブラリは退屈なものに飽き飽きするのに費やす時間を短縮するための優れた方法です。どこからでもどこからでもコードを取得してゲームをプレイできるようにし、後で修正することを心配します。
SimonW 2011年

3

敵が目的地へのパスを見つけるためのコード(A *アルゴリズムのようなものを使用)がすでにあると思います。プレイヤーがタワーを配置しようとするたびに、タワーがある場所に一時的な障害物を置き、パスファインディングコードを実行して、敵のパスがまだあることを確認できます。

これはさまざまな方法で最適化できます。たとえば、新しく配置されたタワーが最大1つの既存の障害物にしか触れない場合、パスをブロックすることはできません。以前のチェックの結果を保存することもできます(少なくとも何かが変更されるまで)。これにより、プレーヤーが同じ場所を数回試行した場合に、毎回再確認する必要がなくなります。

また、いくつかのケースでのみ機能するいくつかのテクニックがあります。例えば:

  • タワーの可能な場所が重ならない場合は、ブリッジ検索アルゴリズムを使用して、敵の進路をブロックする場所を正確に見つけることができます。
  • 競技場が2次元である場合、上から下に連続する壁が存在しない場合に限り、左側から右側への明確なパスが存在するという事実に基づく巧妙なトリックがあります。したがって、もしあれば、それが壁によって接続されている競技場のどちら側にあるかに応じて、各タワー(または他の障害物)にラベルを付けることができます。

    新しいタワーが追加されたときにこれらのラベルを維持することは簡単かつ迅速です。新しいタワーが2つの側面を一緒にリンクする場合、それは敵の進路をブロックします。もちろん、タワーが削除された場合でも、ラベルを再計算する必要がありますが、これは、プレイヤーが新しいタワーの潜在的な位置にカーソルを合わせるたびではなく、タワーが実際に破壊されたときに行う必要があります。


1

SimonWには、パスアルゴリズムを実行するだけでよいことに同意します。完全を期すために、Starcraft / Warcraft TDマップで使用されるトリックを以下に示します。これには、パスアルゴリズムが成功するか失敗するかを確認する方法がありません。

敵がビルド可能領域の最上部からどこにでも来ることができ、ビルド可能領域の下のどこかに移動する必要があるとしましょう。左/右に壁があります。やるフラッドフィルを左壁に触れるすべての塔のを。見つかった塔が右の壁に接触している場合、パスはブロックされます。


0

それはもっと似ているべきです

bool checkCollision(tower)
{
if(there is tower above)
  return checkCollision(tower above);
if(there is tower below)
  return checkCollision(tower below);
...
...
...
if(wall above)
  return 1;
if(wall below)
  return 5;
...
...
...
return 0;
}

その後、コードの中で、タワーの配置を許可するかどうかを確認したい場所で:

if(!checkCollision(tower above) && !checkCollision(tower below) && !checkCollision(tower left)...[check all sides]...)
  //You can place the tower
else
  //You cannot place the tower

また、アルゴリズムを変更して、塔の列に隣接して見つかった壁のタイルの座標を返す機能を追加します。同じ壁タイルが返されたかどうかを確認し、それを破棄すると、タワーのループも通過できるようになります。

タワーのループとは(アスキーアートを気にしないでください):

--------------------------
|                        |
|   TT                   |
|TTTTTTTTT               |
|       X T              |
|       T                |
|                        |
En                       Ex
|                        |
|                        |
|                        |
|________________________|

Xに塔を配置することはできません。上の塔、対角線上の塔、右側の塔、下の塔はすべて壁の衝突を報告しますが、壁タイルの座標は同じです。これはあなたが同様に選別する必要があるものです。


0

簡単です。今日、最初の経路探索プログラムを作成しました。2時間ちょっとかかりました。変数の宣言は別として、閉じ括弧を含むコードは27行だけです。

パスファインダーで実際のすべての壁の配列、およびすべての架空の壁の配列をプログラムします。プレーヤーがスペースにタワーを作成したい場合、選択されたスペースは仮想の壁です。パスファインダーを実行して仮想の壁を含めます。プログラムがパスを見つけて戻ってきた場合、タワーを構築できます。そうでない場合、タワーの構築は許可されません。

乾杯

これが私のコードです、

function PathFind(){

var keepgoing:Number=1;
var count:Number=1;
var smallcount:Number=0;
var keepgoing2:Boolean=false;
var startX:Array=[];
var startY:Array=[];
startX[0]=new Array();
startX[1]=new Array();
startY[0]=new Array();
startY[1]=new Array();
startX[0][1] = disc.loca;
startY[0][1] = disc.locb;
startX[1][1] = String(disc.loca)+"$";
startY[1][1] = String(disc.locb)+"$";


for(var c:Number=1; c<=keepgoing; c++){
    smallcount=0;
    for (var a:Number=1; a<=3; a++){
        for (var b:Number=1; b<=3; b++){
            if (a==2 || b==2){
                if(Space[startX[0][c]+(a-2)][startY[0][c]+(b-2)].valid==true && SpaceII[startX[0][c]+(a-2)][startY[0][c]+(b-2)]==true){
                    count++;
                    smallcount++;
                    SpaceII[startX[0][c]+(a-2)][startY[0][c]+(b-2)]=false;
                    startX[0][count]=Space[startX[0][c]+(a-2)][startY[0][c]+(b-2)].IDx;
                    startY[0][count]=Space[startX[0][c]+(a-2)][startY[0][c]+(b-2)].IDy;
                    startX[1][count]=startX[1][c]+String(Space[startX[0][c]+(a-2)][startY[0][c]+(b-2)].IDx)+"$";
                    startY[1][count]=startY[1][c]+String(Space[startX[0][c]+(a-2)][startY[0][c]+(b-2)].IDy)+"$";
                    if(Space[startX[0][c]+(a-2)][startY[0][c]+(b-2)].goal==true){
                        keepgoing2=true;
                        disc.stringA = startX[1][count].toString();
                        disc.stringB = startY[1][count].toString();
                        //thisText.text=startX[1][count] + "%" + startY[1][count] + "*";
                        success=true;
                    }                       
                }
            }
        }
    }
    if(keepgoing2==true){
        c = keepgoing;
    } else {
        keepgoing = keepgoing + smallcount;
    }
}

}

基本的に、私のコードはXおよびY文字列のペアリングの配列を作成します。その後、私の移動ユニットは最初に成功したペアリング文字列を継承し、次に一度に1つのセグメントだけを文字列を分析します。各座標は「$」で区切られています。

そして、上記のコードの美しいところは、「キープゴーイング」がグリッドサイズと同じ大きさになるだけであり、配置されるタワーが増えるほど効率が向上し、パスが1つしかないときに効率が最大化されることです。

私がここで得たものについて何か助けが必要な場合は、私に知らせてください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.