下面的文字将叙述成都金点工作组所设计的RPG游戏《流星之舟》的地图遮挡算法,游戏地图采用斜45度的视角,屏幕分为了20*15个菱形图块,每个图块的大小为64*32(像素点)。
首先看一下这张图,我的算法是当扫描到物体编号点后,先画出物体,然后搜索左右两个修正区,如果修正区中有其他物体的编号,那么先画出该物体,然后搜索新找到物体的两个修正区,这样不断递归进行搜索,直到全部搜索完毕。

拒我的测试,这个算法的速度还是可以,但是还存在一定的缺陷,如:有可能掉入死循环(属于特殊情况,一般不会发生)、对于下小上大的物体(如:树冠很大的树)有可能出现错误遮挡。
下面的代码就是《流星之舟》中用到的场景遮挡算法,我把其中一些不必要的东西清除了,然后加上了详细的注释。
//显示一个场景中的所有物体,包括角色(我把角色当作景物进行处理)
void ShowMap()
{
//画景物(pm.SX,pm.SY)是当前屏幕相对于整张地图的坐标
for(j=pm.SY; j<pm.SY+16+10; j++)
{
//在地图Y轴范围之内(Height:地图高度)
if( j<Height )
{
//先画偶数行物体
for(i=pm.SX-6; i<pm.SX+21+6; i+=2)
{
//在地图X轴范围内(Width:地图宽度)
if( i>=0 && i<Width )
{
int Cover=Data[Width*j+i].CoverID; //取当前图块中的景物数据
if( Cover != 0 ) //显示物体(0:无物体)
{
Cover-=16; //这是我做的一个变换,无实际意义
Blt(lpDDSBack, ((i-pm.SX)<<5)-pm.DX - Objects[Cover].x, ((j-pm.SY)<<5)-pm.DY - Objects[Cover].y +32 ,lpDDSObj[ Objects[Cover].Surf ], Objects[Cover].rect, TRUE); //画出物体
FixMap(i,j,Cover); //修正大物体的遮挡关系(最重要的部分)
}
}
}
//后画奇数行物体
for(i=pm.SX+1-6; i<pm.SX+21+6; i+=2)
{
//在地图X轴范围内
if( i>=0 && i<Width )
{
int Cover=Data[Width*j+i].CoverID;
if( Cover != 0 ) //显示物体
{
Cover-=16;
Blt(lpDDSBack, ((i-pm.SX)<<5)-pm.DX - Objects[Cover].x, ((j-pm.SY)<<5)-pm.DY - Objects[Cover].y + 48 ,lpDDSObj[ Objects[Cover].Surf ], Objects[Cover].rect, TRUE);
FixMap(i,j,Cover);
}
}
}
}
}
}
//****************************
//修正物体的阻挡(这个函数中用到了很多其他东西,所以可能很难读懂,不过只要你理解了我的方法,我想你可以写出更好代码来)
void FixMap(int x, int y, int Cover)
{
int Ox, Oy, Vx, Vy;
int tx, ty; //临时变量
//左边
if( Objects[Cover].Lx>0 )
{
//转化成斜坐标系
Ver2Oblique(x, y, Ox, Oy);
//求三角型顶点
Ox-=Objects[Cover].Lx;
Oy+=1;
for( int i=0; i<Objects[Cover].Lx; i++)
for( int j=0; j<=i; j++)
{
tx=Ox+j;
ty=Oy+i-j;
//转化成直坐标系
Oblique2Ver(tx,ty, Vx, Vy);
int ID=Data[Width*Vy+Vx].CoverID;
if( NpcData[ Width*Vy+Vx ] != 0 )
{
ShowRoles(NpcData[ Width*Vy+Vx] );
}
if( ID != 0 )
{
ID-=16;
if( Vx%2==0 )
Blt(lpDDSBack, ((Vx-pm.SX)<<5)-pm.DX - Objects[ID].x, ((Vy-pm.SY)<<5)-pm.DY - Objects[ID].y +32 ,lpDDSObj[ Objects[ID].Surf ], Objects[ID].rect, TRUE);
else
Blt(lpDDSBack, ((Vx-pm.SX)<<5)-pm.DX - Objects[ID].x, ((Vy-pm.SY)<<5)-pm.DY - Objects[ID].y +48 ,lpDDSObj[ Objects[ID].Surf ], Objects[ID].rect, TRUE);
FixMap(Vx, Vy, ID); //递归
}
}
}
//右边
if( Objects[Cover].Ly>0 )
{
//转化成斜坐标系
Ver2Oblique(x, y, Ox, Oy);
//求三角型顶点
Oy-=Objects[Cover].Ly;
Ox+=1;
for( int i=0; i<Objects[Cover].Ly; i++)
for( int j=0; j<=i; j++)
{
tx=Ox+j;
ty=Oy+i-j;
//转化成直坐标系
Oblique2Ver(tx,ty, Vx, Vy);
int ID=Data[Width*Vy+Vx].CoverID;
if( NpcData[ Width*Vy+Vx ] != 0 )
{
ShowRoles( NpcData[ Width*Vy+Vx ] );
}
if( ID != 0 )
{
ID-=16;
if( Vx%2==0 )
Blt(lpDDSBack, ((Vx-pm.SX)<<5)-pm.DX - Objects[ID].x, ((Vy-pm.SY)<<5)-pm.DY - Objects[ID].y +32 ,lpDDSObj[ Objects[ID].Surf ], Objects[ID].rect, TRUE);
else
Blt(lpDDSBack, ((Vx-pm.SX)<<5)-pm.DX - Objects[ID].x, ((Vy-pm.SY)<<5)-pm.DY - Objects[ID].y +48 ,lpDDSObj[ Objects[ID].Surf ], Objects[ID].rect, TRUE);
FixMap(Vx, Vy, ID); //递归
}
}
}
}
上面的代码仅仅是想帮助你更好的理解算法,但是如果你很难看懂的话,就请不要再继续浪费时间,因为它本来就太乱了,如果大家对这个算法感兴趣的话,我可以把上面的代码规范化。但我并不能保证这种方法是正确、高效的,因为这仅仅是我个人凭空想出来的(《流星之舟》是它的唯一一个实例,你可以到http://www.gpgame.com下载范例)。