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<re2)&&(re1!=0) ) || ( re2==0 ) ) {

// int i;

// for(i=0; i<re1; i++) {

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

// }

// free(buff2);

// return re1;

// } else if( ((re2<re1)&&(re2!=0) ) || ( re1==0 ) ) {

// int i;

// for(i=0; i<re2; 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;

}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容