#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; }