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