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