战棋类中实现的移动范围
下面的沒有經過實踐,因此很可能是錯誤的,覺得有用的初學朋友讀一讀吧:)
希望高人指點一二 :)
簡介:
在標準的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<nodecount) //數組中還有待擴展的節點
{
??? int n=nodecount; //記錄下當前的數組節點的個數。
??? for(int i=cutflag;i<nodecount;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<nodecount;i )
??? pMap[AllPath[i].x][AllPath[i].y].bFlag=0; //標記為已擴展節點的標記設回為待擴展節點。
總結
以上是生活随笔為你收集整理的战棋类中实现的移动范围的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JavaScript 获取客户端计算机硬
- 下一篇: 网络游戏的位置同步