關於SLG中人物可到達範圍計算的想法(轉)

post0發表於2007-08-12
關於SLG中人物可到達範圍計算的想法(轉)[@more@]

  簡介:

  在標準的SLG遊戲中,當在一個人物處按下滑鼠時,會以人物為中心,向四周生成一個菱形的可移動區範圍,如下:

   0

   000

  00s00

   000

   0

  這個圖形在剛開始學習PASCAL時就應該寫過一個畫圖的程式(是否有人懷念?)。那個圖形和SLG的擴充套件路徑一樣。

  一、如何生成路徑:

  從人物所在的位置開始,向四周的四個方向擴充套件,之後的點再進行擴充套件。即從人物所在的位置從近到遠進行擴充套件(類似廣寬優先)。

  二、擴充套件時會遇到的問題:

  1、當擴充套件到一個點時,人物的移動力沒有了。

  2、當擴充套件的時候遇到了一個障礙點。

  3、當擴充套件的時候這個結點出了地圖。

  4、擴充套件的時候遇到了一個人物正好站在這個點(與2同?)。

  5、擴充套件的點已經被擴充套件過了。當擴充套件節點的時候,每個節點都是向四周擴充套件,因此會產生重複的節點。

  當遇到這些問題的時候,我們就不對這些節點處理了。在程式中使用ALLPATH[]陣列記錄下每一個等擴充套件的節點,不處理這些問題節點的意思就是不把它們加入到ALLPATH[]陣列中。我們如何去擴充套件一個結點周圍的四個結點,使用這個結點的座標加上一個偏移量就可以了,方向如下:

   3

  0 2

   1

  偏移量定義如下:

  int offx[4] = { -1, 0, 1, 0 };

  int offy[4] = { 0, 1, 0, -1 };

  擴充套件一個節點的相鄰的四個節點的座標為:

  for(int i=0; i<4; i )

  {

  temp.x = temp1.x offx[i];

  temp.y = temp1.y offy[i];

  }

  三、關於地圖的結構:

  1、地圖的二維座標,用於確定每個圖塊在地圖中的位置。

  2、SLG中還要引入一個變數decrease表示人物經過這個圖塊後他的移動力的減少值。例如,一個人物現在的移動力為CurMP=5,與之相領的圖塊的decrease=2;這時,如果人物移動到這裡,那它的移動力變成CurMP-decrease。

  3、Flag域:寬度優先中好像都有這個變數,有了它,每一個點保證只被擴充套件一次。防止一個點被擴充套件多次。(一個點只被擴充套件一次真的能得到正確的結果嗎?)

  4、一個地圖上的圖塊是否可以透過,我們使用了一個Block代表。1---不可以透過;0---可以透過。

  這樣,我們可以定義一個簡單的地圖結構陣列了:

  #define MAP_MAX_WIDTH 50

  #define MAP_MAX_HEIGHT 50

  typedef struct tagTILE{

  int x,y,decrease,flag,block;

  }TILE,*LPTILE;

  TILE pMap[MAP_MAX_WIDTH][MAP_MAX_HEIGHT];

  以上是順序陣列,是否使用動態的分配更好些?畢竟不能事先知道一個地圖的寬、高。

  四、關於路徑:

  SLG遊戲中的擴充套件路徑是一片區域(以人物為中心向四周擴充套件,當然,當人物移動時路徑只有一個)。這些擴充套件的路徑必須要儲存起來,所有要有一個好的結構。我定義了一個結構,不是很好:

  typedef struct tagNODE{

  int x,y;  //擴充套件路徑中的一個點在地圖中的座標。

  int curmp; //人物到了這個點以後的當前的移動力。

  }NODE,*LPNODE;

  上面的結構是定義擴充套件路徑中的一個點的結構。擴充套件路徑是點的集合,因此用如下的陣列進行定義:

  NODE AllPath[PATH_MAX_LENGTH];

  其中的PATH_MAX_LENGTH代表擴充套件路徑的點的個數,我們不知道這個擴充套件的路徑中包含多少個點,因此定義一個大一點的數字使這個陣列不會產生溢位:

  #define PATH_MAX_LENGTH 200

  上面的這個陣列很有用處,以後的擴充套件就靠它來實現,它應該帶有兩個變數nodecount 代表當前的陣列中有多少個點。當然,陣列中的點分成兩大部分,一部分是已經擴充套件的結點,存放在陣列的前面;另一部分是等擴充套件的節點,放在陣列的後面為什麼會出現已擴充套件節點和待擴充套件節點?如下例子:

  當前的人物座標為x,y;移動力為mp。將它存放到AllPath陣列中,這時的起始節點為等擴充套件的節點。這時我們擴充套件它的四個方向,對於合法的節點(如沒有出地圖,也沒有障礙......),我們將它們存放入AllPath陣列中,這時的新加入的節點(起始節點的子節點)就是等擴充套件結點,而起始節點就成了已擴充套件節點了。下一次再擴充套件節點的時候,我們不能再擴充套件起始節點,因為它是已經擴充套件的節點了。我們只擴充套件那幾個新加入的節點(待擴充套件節點),之後的情況以此類推。那麼我們如何知道哪些是已經擴充套件的結點,哪些是等擴充套件的節點?我們使用另一個變數cutflag,在這個變數所代表的下標以前的結點是已擴充套件節點,在它及它之後是待擴充套件結點。

  五、下面是基本框架(只擴充套件一個人物的可達範圍):

  int nodecount=0; //AllPath陣列中的點的個數(包含待擴充套件節點和已經擴充套件的節點

  int cutflag=0; //用於劃分已經擴充套件的節點和待擴充套件節點

  NODE temp; //路徑中的一個點(臨時)

  temp.x=pRole[cur]->x; //假設有一個關於人物的類,代表當前的人物

  temp.y=pRole[cur]->y;

  temp.curmp=pRole[cur]->MP; //人物的最大MP

  AllPath[nodecount ]=temp; //起始點入AllPath,此時的起始點為等擴充套件的節點

  while(curflag  {

  int n=nodecount; //記錄下當前的陣列節點的個數。

  for(int i=cutflag;i  {

  for(int j=0;j<4;j ) //向待擴充套件節點的四周各走一步

  {

  //取得相鄰點的資料

  temp.x=AllPath[i].x offx[j];

  temp.y=AllPath[i].y offy[j];

  temp.curmp=AllPath[i].curmp-pMap[AllPath[i].x][AllPath[i].y].decrease;

  //以下為檢測是否為問題點的過程,如果是問題點,不加入AllPath陣列,繼續處理其它的點

  if(pMap[temp.x][temp.y].block)

  continue; //有障礙,處理下一個節點

  if(temp.curmp<0)

  continue; //沒有移動力了

  if(temp.x<0||temp.x>=MAP_MAX_WIDTH|| temp.y<0||temp.y>=MAP_MAX_HEIGHT)

  continue; //出了地圖的範圍

  if(pMap[temp.x][temp.y].flag)

  continue; //已經擴充套件了的結點

  //經過了上面幾層的檢測,沒有問題的節點過濾出來,可以加入AllPath

  AllPath[nodecount]=temp;

  }

  pMap[AllPath[i].x][AllPath[i].y].flag=1; //將已經擴充套件的節點標記為已擴充套件節點

  }

  cutflag=n; //將已擴充套件節點和待擴充套件節點的分界線下標值移動到新的分界線

  }

  for(int i=0;i  pMap[AllPath[i].x][AllPath[i].y].bFlag=0; //標記為已擴充套件節點的標記設回為待擴充套件節點

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/8225414/viewspace-952007/,如需轉載,請註明出處,否則將追究法律責任。

相關文章