2021-03-22 记录一个以前的2D网格地图寻路算法

#include "moveline.h"

void CreateNewDrectionByClockCycle(int baseDrectionX,int baseDrectionY,int * px,int* py, int clockCycleDrection) {

if(baseDrectionX<0&& baseDrectionY<0 ) { //左上

if(clockCycleDrection ) {

* px=0;

* py=-1;

} else {

* px=-1;

* py=0;

}

} else if( baseDrectionX==0&& baseDrectionY<0 ) { //上

if(clockCycleDrection ) {

* px=1;

* py=-1;

} else {

* px=-1;

* py=-1;

}

} else if( baseDrectionX>0&& baseDrectionY<0 ) { //右上

if(clockCycleDrection ) {

* px=1;

* py=0;

} else {

* px=0;

* py=-1;

}

} else if( baseDrectionX>0&& baseDrectionY==0 ) { //右

if(clockCycleDrection ) {

* px=1;

* py=1;

} else {

* px=1;

* py=-1;

}

} else if( baseDrectionX>0&& baseDrectionY>0 ) { //右下

if(clockCycleDrection ) {

* px=0;

* py=1;

} else {

* px=1;

* py=0;

}

} else if( baseDrectionX==0&& baseDrectionY>0 ) { //下

if(clockCycleDrection ) {

* px=-1;

* py=1;

} else {

* px=1;

* py=1;

}

} else if( baseDrectionX<0&& baseDrectionY>0 ) { //左下

if(clockCycleDrection ) {

* px=-1;

* py=0;

} else {

* px=0;

* py=1;

}

} else if( baseDrectionX<0&& baseDrectionY==0 ) { //左

if(clockCycleDrection ) {

* px=-1;

* py=-1;

} else {

* px=-1;

* py=1;

}

}

}

int TransToDrection(int x) {

if(x<0) {

return -1;

} else if(x>0) {

return 1;

} else return 0;

}

int CreateMoveLineByClockCycleDrection(int currentX  ,int currentY ,int destX,int destY ,int* buff ,int clockCycleDrection ) {

// MsgIntEx(destX,destY ) ;

// MsgIntEx(currentX,currentY ) ;

int backX,backY,nextX,nextY;

backX=currentX; //记录上一个坐标

backY=currentY;

int drectionX,drectionY,distanceX,distanceY;

int i=0;

while(1) {

distanceX=destX-backX;

distanceY=destY-backY;

// MsgInt( distanceX*distanceX +distanceY*distanceY  ,")<4 ");

if( ( distanceX*distanceX +distanceY*distanceY )<4) { //线路已经生成成功

return i; //返回线路坐标点个数;

}

if(i== ( MOVE_LINE_MAX_POINT_NUM-1 ) ) return 0; //生成的线路太长,失败

drectionX=TransToDrection(distanceX ) ; //生成方向

drectionY=TransToDrection(distanceY );

// MsgIntEx(backX  ,backY  ) ;

// MsgIntEx( drectionX ,  drectionY ) ;

if(IsPositionReachable(backX+drectionX, backY+ drectionY)) { //方向上的下一个坐标能否到达

backX=backX+drectionX; //能到达,记录此点,继续循环验证 IsPositionReachable

backY=backY+ drectionY;

*(buff+i )=Point2Int(backX,backY); //线路记录一个点

i++;

} else { //不能到达 则换方向

int backDrectionX,backDrectionY, newDrectionX, newDrectionY;

backDrectionX=drectionX;

backDrectionY=drectionY;

while(1) { //最好加变量 检测循环次数,万一转方向一直都不行,则到了一个四周都是墙壁的点位,但是好像不可能存在这种点位,至少可以原路返回

CreateNewDrectionByClockCycle(backDrectionX,backDrectionY,&newDrectionX,&newDrectionY ,clockCycleDrection); //转一下方向

if(IsPositionReachable(backX+newDrectionX, backY+ newDrectionY)) { //新方向 Reachable?

backX=backX+newDrectionX;

backY=backY+ newDrectionY;

*(buff+i )=Point2Int(backX,backY);

i++;

goto here;

} else {

backDrectionX= newDrectionX;

backDrectionY=newDrectionY;

}

}

here:

;

}

}

}

//寻找达到目标的线路

int CreateMoveLine(int currentX  ,int currentY ,int destX,int destY ,int* buff  ) {

Logstr("CreateMoveLine.\r\n") ;

// int buff1[MOVE_LINE_MAX_POINT_NUM];

// int* buff2=(int*)malloc(sizeof(int)*MOVE_LINE_MAX_POINT_NUM )  ;

// int re1,re2;

return CreateMoveLineByClockCycleDrection(currentX,  currentY ,  destX,  destY ,  buff  , 0 ) ;

// MsgIntEx( IntPoint2X(  buff1[0] )  ,  IntPoint2Y(  buff1[0] ) ) ;

// re2=CreateMoveLineByClockCycleDrection(currentX,  currentY ,  destX,  destY ,  buff2 , 1 ) ;

// if ( ((re1

// int i;

// for(i=0; i

// *(buff+i) = buff1[i];

// }

// free(buff2);

// return re1;

// } else if( ((re2

// int i;

// for(i=0; i

// *(buff+i) = buff2[i];

// }

// free(buff2);

// return re2;

// }

}

int MarkMoveLine(HDC hdc,const int*  currentX, const int*  currentY,int* pMoveLine , int* buff ) {

int a,b;

for(a= *currentX -5; a<=  *currentX +5 ; a++  ) {

for(b= *currentY -5; b<=  *currentY +5 ; b++  ) {

if(!IsPositionReachable(a,b)) {

int i,j;

for(i=  -2; i<=    +2 ; i++  ) {

for(j= -2; b<=  2 ; j++  ) {

SetPixel( hdc, FOOT_POSITION_0X+48*(a-*currentX)+i,  FOOT_POSITION_0Y+32*(b-*currentY)+j  ,  0xffffff);

}

}

}

}

}

int baseX,baseY ,drectionX, drectionY ;

int i=0;

while( buff!=pMoveLine ) {

baseX=IntPoint2X(  *(buff  )  );

baseY=IntPoint2Y(  *(buff  )  );

drectionX=IntPoint2X(  *(buff -1 )  )-baseX;

drectionY=IntPoint2Y(  *(buff -1 )  )-baseY;

int j;

// Logstr("MarkMoveLine");

// SetPixel( hdc, FOOT_POSITION_0X+48*(baseX-*currentX)  , FOOT_POSITION_0Y+32*(baseY-*currentY)  ,0x00ff0000);

for(j=1; j<=16; j++) {

SetPixel( hdc, FOOT_POSITION_0X+48*(baseX-*currentX)+j*3*drectionX -1,  FOOT_POSITION_0Y+32*(baseY-*currentY)+j*2*drectionY-1 ,  0xF8D560);

SetPixel( hdc, FOOT_POSITION_0X+48*(baseX-*currentX)+j*3*drectionX , FOOT_POSITION_0Y+32*(baseY-*currentY)+j*2*drectionY ,0xF8D560);

SetPixel( hdc, FOOT_POSITION_0X+48*(baseX-*currentX)+j*3*drectionX +1, FOOT_POSITION_0Y+32*(baseY-*currentY)+j*2*drectionY +1,0xF8D560);

}

buff--;

}

return 1;

}

/*

水波算法:

解决2D网游两个坐标点之间寻路问题,实际游戏地图有很多角落,障碍物什么的,路很拐还有死角。如何在起点和终点间选一条最短路线?

举例说明我的想法:假如起点是200,200;终点是400,400,从起点扩大水波,假如没有障碍物,则必然会在终点有重合。

实际游戏中,两点往中间寻路,第一次,查询起点周围共计8个点是否可以到达 ,记录可以到达的点标记为第一波,第二次查询所有第一波可以到达的点的

临近可到达且未标记记录的点,标记为第二波,就这样像水波向前涌去,最终会到达终点,波数就是最短路径长度

道路会分叉?

编程思路:实际地图做大坐标范围是 800*800 ;最多点位是800*800;

先calloc 800*800*4,坐标值为0~800,用一个int的高低位存x y,

第0波 存入beginPoint,附加一个超限坐标1024|1024 作为波数分隔符;

下一波,查询上一波点位周围可以到达且未记录的点位,记录,,附上分隔符,循环,直到这个待记录点==终点时,

某一波找不到这样的待记录点,说明已经到达边界 ,说明终点不可到达,或者无路可通;

从终点往前选上一波的一个临近 ,再上上一波选一个临近点,最后必然会到达始点,寻线成功;

*/

/*

思路:

根据线路必然是连续的

得到一个起点 则把其坐标对应的位置 标记为波数0

查找周围8个点,可达标记为-2,不可达标记为-1;

*/

void CopyWave(int* buff_waveNow,int* buff_wavePre) {

while( * buff_waveNow!=NO_WAY_POSITION ) {

* buff_wavePre = * buff_waveNow;

* buff_waveNow = NO_WAY_POSITION;

buff_waveNow++;

buff_wavePre++;

}

*buff_wavePre=NO_WAY_POSITION;

}

void AddToWaveNowList(int* buff_waveNow,int data) {

while(  * buff_waveNow!=NO_WAY_POSITION ) {

if( * buff_waveNow==data) return;

buff_waveNow++;

}

* buff_waveNow=data;

buff_waveNow++;

* buff_waveNow=NO_WAY_POSITION;

}

int CreateOneWave(int * buff_position ,int*  buff_waveNow,int* buff_wavePre,int wave,int destX,int destY) {

while(*buff_wavePre!=NO_WAY_POSITION ) {

int x,  y;

for( x= IntPoint2X(*buff_wavePre)-1; x<= IntPoint2X(*buff_wavePre)+1; x++ ) { //循环检查周围8个点;.

for(y=IntPoint2Y(*buff_wavePre) -1; y<= IntPoint2Y(*buff_wavePre) +1; y++ ) {

if(( x>=0&&x<=800&&y>=0&&y<=800) && (Point2Int(x,y)!= (*buff_wavePre ) )) { //过滤掉地图超界点 和本点

if(  *( buff_position+800*y+ x  )  <-1  ) {

// if( IsPositionReachableTest(x,y)  ) {

if( IsPositionReachable (x,y)  ) {

*( buff_position+800*y+ x  ) = wave;

// SetPixel(hdc_map  ,x ,y ,0xff0000 );

// Sleep(10) ;

if( x==destX && y==destY ) return 1; //终点检测

AddToWaveNowList(buff_waveNow, Point2Int(x,y) );

} else {

*( buff_position+800*y+ x  )=-1;

}

}

}

}

}

buff_wavePre++;

}

// RefreshScreen();

if(  (* buff_waveNow)  == NO_WAY_POSITION) return -1; //无路可通了

return 0; //成功波动

}

int WaveFlow(int * buff_position , int* buff_waveNow,int* buff_wavePre,int wave,int destX,int destY ) {

//把 buff_waveNow copy 到 buff_wavePre

CopyWave(buff_waveNow, buff_wavePre);

//遍历 buff_wavePre的数据直到 NO_WAY_POSITION, 对于每个点位,检测其周围8个位置 >=0 是已标记波数的位置,跳过,<-1是未标记的,查询 是否可达,可达标记波数,把点位加入到 buff_waveNow,形成一波数据 不可达设为-1

return CreateOneWave(  buff_position , buff_waveNow,  buff_wavePre,  wave,  destX,  destY);

}

int FindNextPoint(int * buff_position ,int beginX  ,int beginY , int x,int y,int* pNextPoint ) {

int i,j,wave;

wave=*(buff_position+800*y+ x  );

for( i=x-1; i<= x+1; i++ ) { //循环检查周围8个点;.

for(j=y-1; j<= y+1; j++ ) {

if(( i>=0&&i<=800&&j>=0&&j<=800) && (Point2Int(i,j)!=Point2Int(x,y)) ) { //过滤掉地图超界点 和本点

if( ( *(buff_position+800*j+ i  ) ) == (wave-1 ) ) {

* pNextPoint=Point2Int(i,j);

if(i== beginX  && j==beginY  ) return 1; //起点

SetPixel(hdc_map_mem,i ,j ,0xffffff );

return 0;

}

}

}

}

return -1;

}

int CreateLineFromDest(int * buff_position ,int beginX  ,int beginY ,  int* pMoveLine  ,int** lineBegin ) {

// int wave=* (buff_position+800*(IntPoint2Y (* pMoveLine))+800%( IntPoint2X (* pMoveLine)) );

int re;

do {

re=FindNextPoint(  buff_position ,  beginX  ,  beginY , IntPoint2X (* pMoveLine) ,IntPoint2Y (* pMoveLine),  pMoveLine+1  );

pMoveLine++;

} while(re==0  );

if(re==1) {

* lineBegin=pMoveLine;

return 1;

}

return 0;

}

int CreateMoveLineLikeWaterWave2(int beginX  ,int beginY ,int destX,int destY ,int* pMoveLine  ,int** lineBegin  ) {

if(!IsPositionReachable ( beginX,beginY  )) return 0;

if(!IsPositionReachable ( destX,destY  )) return 0;

int *    buff_position=(int*) malloc(800*800*4);

int *  buff_waveNow=(int*) malloc(( 3200)*4);

int *  buff_wavePre=(int*) malloc(( 3200)*4);

// int *    buff_position=(int*) GlobalAlloc(GMEM_FIXED,800*800*4);

// int *  buff_waveNow=(int*) GlobalAlloc( GMEM_FIXED , ( 3200)*4);

// int *  buff_wavePre=(int*) GlobalAlloc(GMEM_FIXED , ( 3200)*4);

memset(buff_position,0b10000000,800*800*4) ;

memset(buff_waveNow,0b10000000,3200*4) ;

memset(buff_wavePre,0b10000000,3200*4) ;

*(buff_position+800*beginY + beginX ) =0;

*buff_waveNow=Point2Int(beginX,beginY);

* ( buff_waveNow +1 )= NO_WAY_POSITION ;

int x,y;

int wave=1;

// for( x= beginX-1; x<= beginX+1; x++ ) { //循环检查周围8个点;.

// for(y=beginY -1; y<= beginY +1; y++ ) {

// if(( x>=0&&x<=800&&y>=0&&y<=800) && (Point2Int(x,y)!=(Point2Int(beginX ,beginY )) )) { //过滤掉地图超界点 和本点

//

// }

// }

// }

//Msgstr("hhh","");

int re;

do {

re=WaveFlow(  buff_position ,  buff_waveNow,  buff_wavePre, wave,  destX,  destY );

wave++;

// MsgInt( re,"WaveFlow ");

} while( re==0  );

// MsgInt( re," while  WaveFlow ");

if(re==1) {

// Msgstr("hhh","");

*pMoveLine=Point2Int(destX,destY );

re= CreateLineFromDest(    buff_position ,  beginX  ,  beginY ,    pMoveLine  , lineBegin );

}

free(buff_position );

free(buff_waveNow );

free(buff_wavePre );

RefreshScreen();

return re;

}

int CreateMoveLineLikeWaterWave(int beginX  ,int beginY ,int destX,int destY ,int* pMoveLine  ,int** lineBegin  ) {

// int* pMoveLine=pMoveLineBuff;

int k8=4*1024*1024;

int *  buf=(int*) malloc(k8);

// int * const buf=(int*) calloc(800*800,4);

int color=257;

int mem=1;

int* pData=buf;

*pData=NO_WAY_POSITION;

pData++;

*pData=Point2Int(beginX,beginY ) ;

pData++;

*pData=NO_WAY_POSITION;

pData++;

*pData=Point2Int(beginX,beginY ) ;

pData++;

*pData=NO_WAY_POSITION;

int x,y;

int flag_PreTwoWave=1;

int* pLastPreWaveData= pData-1; //记录上一波 最后一个数据的位置

int* pDataRecorded= pLastPreWaveData; //用来去取上2波的数据;

int* pPreWaveData=pLastPreWaveData; //用来去取上1波的数据;

pData++; //pData指向下一波数据记录起始位置

while(1) {

do { //从上一波第一个数据开始

for( x=IntPoint2X(*pPreWaveData)-1; x<= IntPoint2X(*pPreWaveData)+1; x++ ) { //循环检查周围8个点;.

for(y=IntPoint2Y(*pPreWaveData)-1; y<= IntPoint2Y(*pPreWaveData)+1; y++ ) {

if(( x>=0&&x<=800&&y>=0&&y<=800) && (Point2Int(x,y)!=*pPreWaveData) ) { //过滤掉地图超界点 和本点

// if(IsPositionReachable( x,y)) { //可达? 检查是否记录在上2波;

if(IsPositionReachableTest( x,y)) { //可达? 检查是否记录在上2波;

flag_PreTwoWave=3;

do {

if( *pDataRecorded !=Point2Int(x,y) ) { //要与上2波所有数据不等才能记录

pDataRecorded--;

} else { // 已记录在上2波,则打破循环进行下一个可达点的检测

pDataRecorded=pLastPreWaveData; //重置上2波数据起点进行下一个可达点的检测

goto NEXT_REACHABLE_POINT;

}

if(*pDataRecorded==NO_WAY_POSITION) {

flag_PreTwoWave=(flag_PreTwoWave+1)%2; //第二次找到分隔符触发结束,说明该点未记录在上2波,则记录在此波;

}

} while(flag_PreTwoWave!=1);

// if(  ( (int)pData-(int)buf)>=(k8*mem-400 ) ){

// mem++;

// buf=realloc(buf,k8*mem);

// }

//可以记录在此波;

*pData= Point2Int(x,y); // 记录并把记录数据指针前移; 检测是否==终点

// SetPixel(hdc_map_mem,x ,y ,color );

color++;

// SetPixel(hdc_map,x ,y ,0xff00 );

if( (*pData  ) ==Point2Int(destX,destY ) ) { //是否到终点?到终点的处理-------------------------------------

*pMoveLine=*pData; //最终线路第一个数据是终点,最后一个有效数据是起点;

pMoveLine++;

pPreWaveData=pData;

while(1) {

while( (*pPreWaveData) !=NO_WAY_POSITION ) {

pPreWaveData--;

}

pPreWaveData--; //取上一波的每一个数据和本点周围8个点,相等的则是路线的下一点

while( *pPreWaveData != NO_WAY_POSITION ) {

for( x=IntPoint2X(*pData)-1; x<= IntPoint2X(*pData)+1; x++ ) { //循环检查周围8个点;

for(y=IntPoint2Y(*pData)-1; y<= IntPoint2Y(*pData)+1; y++ ) {

if(( x>=0&&x<=800&&y>=0&&y<=800) && (Point2Int(x,y)!=*pData) ) { //过滤掉地图超界点 和本点

if( *pPreWaveData ==Point2Int(x,y)  ) { //找到线路点;

*pMoveLine=*pPreWaveData; //记录

SetPixel(hdc_map_mem,x ,y ,0xffffff );

if(pPreWaveData==(buf+3)) { //线路生成完毕 再用其他函数吧线路中的===========

*lineBegin=pMoveLine;

free(buf);

RefreshScreen();

return 1;

}

pMoveLine++;

pData= pPreWaveData; //又已此点为基础寻找上一波记录的 此点的临近点

goto HERE_PREWAVE;

}

}

}

}

pPreWaveData--;

}

HERE_PREWAVE:

;

}

}

pData++;

pDataRecorded=pLastPreWaveData; //打破循环去检测下一个可达点是否记录在上2波;

}

}

NEXT_REACHABLE_POINT:

;

}

}

pPreWaveData--; //下一次循环,检测上一波记录的数据的下一个数据的周围8个点是否可达,是否已被记录;

} while(*pPreWaveData!=NO_WAY_POSITION ); //上一波每一个数据都检测过了,形成此波数据;

*pData= NO_WAY_POSITION; //此波数据记录完,附上分割符。 pData-pLastPreWaveData-2 就是此波记录的点位的总数

if( (pData-pLastPreWaveData-2 )<=0) { //某一波找不到一个这样的待记录点,说明已经到达地图中可以到达边界 , 终点不可到达,或者无路可通;

free(buf);

return 0;

}

pLastPreWaveData= pData-1; // 重置3个指针,进行下一波

pDataRecorded= pLastPreWaveData;

pPreWaveData=pLastPreWaveData;

pData++; //pData指向下一波数据记录起始位置,最好检测是否超出malloc的存储区

//Sleep(2);

// RefreshScreen();

}

free(buf);

return 0;

}

你可能感兴趣的:(2021-03-22 记录一个以前的2D网格地图寻路算法)