1. 程式人生 > >AI 讀書筆記:第二章:追逐和閃躲 關於視線追逐

AI 讀書筆記:第二章:追逐和閃躲 關於視線追逐

    今天上午研究了書中第二章,關於追逐和閃躲的技術.  頭一個比較好懂, 既基本的追逐演算法,就是NPC的座標值和target的座標值做比較,如果是追逐的話,那麼就向著靠近target的方向移動就可以了.

  實現程式碼如下:

    if (predatorX >preyX)

        predatorX--;

  else if (predatorX<preyX)

     predatorX++;

    if (predatorY >preyY)

        predatorY--;

  else if (predatorY<preyY)

     predatorY++;

  這種演算法雖然簡單,但問題是追逐的時候過於死板,感覺不自然,因為NPC會先移動到和target相同的座標軸,之後直線前進. 因此這裡面又引入了視線追逐法.  用的是Bresenham方法. 這個方法是用來畫線段的,雖然以前計算機圖形學也學過,不過早就還給老師了.加上書中寫的實在比較簡略,可能作者高手覺得這個問題實在簡單,不需要詳細的寫出,導致我看了好久都沒看懂. 晚上上網搜了一下,發現了一哥們,恰好寫了次程式碼的分析,寫的很詳細.我看後,有種豁然開朗的感覺.先和大家進行一下分享.

(參考網址為:http://blog.csdn.net/Eric77/archive/2006/08/10/1043851.aspx)

其實,Bresenham 的精髓就是把向X移動和向Y移動分散開來.不會造成像如上的,X方向已經和target一致了,而Y方向還差了很多.走直線就顯得不自然

 程式碼如下:

  //初始化開始路徑  

void ai_Entity::BuildPathToTarget(void) {

//這個col在畫面上就是x

int nextCol = col; 

 //這個row在畫面上就是y

 int nextRow = row; 

//算出delta值(計算NPC 在row和col上和target的差值)

 int deltaRow = endRow - row;

int deltaCol = endCol - col;

//路徑的陣列的初始化,預設為-1,其中kMaxPathLength表示NPC最大的活動範圍,超出此範圍就不予計算

 for(currentStep = 0; currentStep < kMaxPathLength; currentStep++)

{    

   pathRow[currentStep] = -1;     pathCol[currentStep] = -1;

}

currentStep = 0;

//設定目標位置

pathRowTarget = endRow;

 pathColTarget = endCol;

//判斷走的步長的方向

if(deltaRow < 0)

     stepRow = -1;

 else

     stepRow = 1;

if(deltaCol < 0)    stepCol = -1;

  else

     stepCol = 1;

//取絕對值後同乘以2,  絕對值倒是明白,為什麼需要*2? 這個不是很懂

 deltaRow = abs(deltaRow * 2); deltaCol = abs(deltaCol * 2);

//記錄開始路徑

  pathRow[currentStep] = nextRow; pathCol[currentStep] = nextCol;

currentStep++ ;

/* 下面開始 Bresenham algorithm 的主體部分 */

//這個變數是一個關鍵點,可以看作是某種權. 因為deltaX和deltaY長度不同,因此,權不一樣. 使用fraction來標記權值. 假如說deltaX=10, deltaY=5,那麼,就意味著X軸的距離是Y軸距離的2倍,既向y移動1次後,要向X移動2次 int fraction = 0;

//如果x要走的部分比y要長

if(deltaCol > deltaRow)

   {

  //此處標記為deltaRow * 2 - deltaCol,其實算是一個優化,因為上述條件已經判斷deltaCol > deltaRow, 

  //那麼,deltaRow - deltaCol必然小於0. 既第一個點為(0,1), 設定為deltaRow * 2 - deltaCol為的是做下優化

  //在deltaRow*2 > deltaCol的情況下, 第一個點變為(1,1),可以少移動一步     fraction = deltaRow * 2 - deltaCol;

    while(nextCol!=endCol)         {        

         //此處為fraction即為權的值       

        if(fraction >= 0)      

       {        

              nexRow = nextRow + stepRow;        

              //按比例削弱權值        

            fraction = fration - deltaCol;      

          }//if

  //因此Col方向是比較長的,所以,每次必然增加Col的值

        nextCol = nextCol + stepCol;

 //增加權值,做權值的累計(累計到了一定的值,X方向才會變化)  

      fraction = fraction + deltaRow;

//把得到的值存入路徑陣列種

        pathRow[currentStep] = nextRow;

        pathCol[currentStep] = nextCol;

         currentStep ++;     }//while

      }

            //此下部分與上面原理相同,故略掉了啊

      else

            {   

               fraction = deltaCol*2 - deltaRow;    

               while(nextRow!=endRow)    

              {     

                    if(fraction>=0)     

               {     

                 nextCol = nextCol + stepCol;     

                 fraction = fraction -deltaRow;       

           }

              nextRow = nextRow + stepRow;

               fraction = fraction + deltaCol;  

               pathRow[currentStep] = nextRow;  

               pathCol[currentStep] = nextCol;

              currentStep++;

             }//while

}//else

}//ai_Entity