Softboy:
看了你的关于《流星之舟地图遮挡算法》及其系列文章,有一些看法。
不过首先要声明的是我没有编过什么大程序,对你和天眼的文章也看不太懂,这里只是抱着学习的态度。(我认为我对这一类算法问题比较强)
关于物体的相互遮挡问题很复杂,我想最完整的解决方案就是建立三维方位数组。
实际上目前流行的三维游戏都会采用这一类方法,而且它们的数据比《流星之舟》更复杂。对于《流星之舟》这一类游戏来说,速度和内存占用方面应没有问题。
不过,对于《流星之舟》来说,我们还可以简化这个问题:
1、没有物体的空间重合
2、没有物体的相互遮挡
例如,人站在大树前面,人挡住了树,树叶也可能挡住人。
人站在水池中,水池边挡住了人,人也挡住了水池(这里含有空间重合问题)
3、物体的遮挡部分不扩散到周围。
例如,人站在房屋旁边,但并不在房屋之后,也可能被屋檐遮挡。这会使我下面给出的例子出现问题。
4、没有其他穿透问题。
例如,桌子的腿可能露出人腿、栏杆露出后面的物体等。
窗户半透明等等。
那么,我想知道下面的方案是否可行?
1、首先,对每一种物体进行分析,建立struct GameObject的结构来描述各种物体。
2、把不可移动的物体事先处理,这样可以加快运行速度。
3、建立两张map图表,一张用于进行关于游戏的各种运算,一张专门用于显示,当然,也可合而为一。
4、关于用于显示的图表,我这里给出了一个简化的例子。这个例子要求每次都重新处理全部物体。实际上应该可以找到更加技术的方法只处理和变化有关的物体。
5、这里要求采用天眼所说的“静态分图”?
6、合成完显示图表后,再在分图的基础上画出全部图案。
7、对map和GameObject的复杂化可能可以处理互相遮挡等问题。
8、当然,也可按天眼的方法只把图形分成列,但不同之处在于这里采用的是覆盖,而不是搜索。
总之,中心思想是数据和图像分开处理,游戏只是在显示时才用到图像数据。当然,如果你不愿意分图,在没有互相遮挡等问题时,也可先计算出物体的显示顺序,再整块整块地画图。不过,在计算显示先后顺序时,不需要用递归,可先建立静止物体显示先后顺序链表,再把动态人物插入列表中。这种显示方法的好处是可部分解决穿透问题。
如有互相遮挡等问题,你一定要采用分图技术。
===================================================
struct GameObject包括Number表示该物体一共占有的方格数。
ShelteredNumber表示该物体阴影占的方格数。
data指向一一维列表,x、y分别表示该方格相对该物体的位置。
其中前Number个元素指向该物体根部占据的位置。
ID:该物体的ID。
mapstruct为地图结构,其中的主要元素为:
ID:地表元素ID
CoverID:物体元素ID
CoverObjectNumber:该处相对于该物体所在的位置
===============================================
A:指向GameObject结构的指针
ObjectID:A物体的ID。注意:可能有不同的ObjectID之相同一A
x、y是该物体所在的位置
对于每一个物体,进行如下处理:
int i;
for (i=0; i< A->Number+A->ShelteredNumber; i++)//对A物体的每一个区域进行处理
{
int mapx,mapy;
struct mapstruct *mapdeal;
mapx=x+A->data[i].x;
mapy=y+A->data[i].y;
mapdeal=&map[mapx][mapy]; //使用指针以避免重复的数组下标计算
// TempObject=GetObjectPtr(mapdeal->CoverID);//由ID获得GameObject指针
//如CoverID=0,则返回NULL
if (IsNotSheltered(A,mapdeal->CoverID))//A没有被TempObject遮挡
{ //则应当显示A物体
mapdeal->CoverID=ObjectID;
mapdeal->CoverObjectNumber=i;
}
}
====================================================
BOOL IsNotSheltered(GameObject *A,ObjectNumber ID)
{
BOOL judge=TRUE;
if (ID==0) return TRUE; //如果没有B物体则不被遮挡
ASSERT(没有互相遮挡,物体不能重叠);
for (int i=0; i< A->Number ; i++)
{
if (map[x+A->data[i].x][y+A->data[i].y].CoverID==ID)
//如果A物体根部所在的位置被物体ID遮挡,则A物体一定在
{ //物体ID之后-----参看ASSERT
judge=FALSE;
break;
}
}
return judge;
}