本帖最后由 weyl 于 2012-12-25 01:24 编辑
本来我以为是绘图顺序有问题,今天在修改完贴图算法之后,发现仍然没有解决。检查地图文件之后,发现有一些明显不正确的贴图。即原版的数据文件中有很多长和宽都是1的白色像素,目前没有发现这些贴图有任何作用。因此解决方法就是在RLE8部分将长宽小于等于1的贴图屏蔽掉。我是将其中只要有一个为1的就屏蔽了。
主地图的正确绘图顺序代码如下,但是因为原版的建筑引用数据好像有些错误,效果并不及中点排序的方法,因此并未优化。
具体的内容就不解释了,说一下思路:
1. 找出可见部分的建筑并标记,暂定一个顺序。找出这些建筑的引用坐标,这表示该建筑占据了哪些地面。
2. 对所有发现的建筑,搜索其身后,游泳的鱼给的代码好像是只搜索一个坐标,这里是搜索其身后的两个方向,其实更严格和有效率的方法应是只搜索其身后能够出现遮挡的部分,即屏幕上两条垂线之间,见附图。令当前定位的建筑为A,如果发现身后有另一建筑B的引用,则说明B会被A遮挡,应该在A的前面画。这时,需将B在画图顺序中放到A的前面,同时,A到B之间(包括A不包括B)所有的建筑都后移一位。
这个计算可能涉及大量的内存操作,用解释语言会比较慢,可以增加一个序列标记和一个索引标记,索引保存的是序列中相应元素的位置。
例如5个建筑的序列为:
一四三五二
则索引为:
1 5 3 2 4
根据索引定位需要操作的元素,例如,在刚才这个序列中,我们发现建筑五应在建筑四前面,需要处理这个序列,通过索引我们知道建筑五现在第4位,建筑四现在第2位,那么第2到第4就是要操作的,把第4位的建筑五放到第2位,原来的第2位和第3位均后移1位,同时索引要重新编制。- procedure DrawMMap;
- var
- i1, i2, i, sum, x, y, k, j1, j2, BAmount, mini1, mini2, swaptemp, a, b, col: integer;
- temp, tempindex: array[0..479, 0..479] of smallint;
- width, height: smallint;
- pos: TPosition;
- List, ListIndex, BuildingPic: array[0..10000] of integer;
- BuildingPos: array[0..10000] of TPosition;
- begin
- if (SDL_MustLock(screen)) then
- begin
- if (SDL_LockSurface(screen) < 0) then
- begin
- MessageBox(0, PChar(Format('Can''t lock screen : %s', [SDL_GetError])), 'Error', MB_OK or MB_ICONHAND);
- exit;
- end;
- end;
- for i1 := 0 to 479 do
- for i2 := 0 to 479 do
- begin
- temp[i1, i2] := -1;
- tempindex[i1, i2] := -1;
- end;
- mini1 := Mx - 16 - 14;
- mini2 := My - 16 - 15;
- k := 0;
- for sum := -29 to 41 do
- for i := -16 to 16 do
- begin
- i1 := Mx + i + (sum div 2);
- i2 := My - i + (sum - sum div 2);
- Pos := GetPositionOnScreen(i1, i2, Mx, My);
- if (i1 >= 0) and (i1 < 480) and (i2 >= 0) and (i2 < 480) then
- begin
- if (sum >= -27) and (sum <= 28) and (i >= -9) and (i <= 9) then
- begin
- DrawMPic(earth[i1, i2] div 2, pos.x, pos.y);
- if surface[i1, i2] > 0 then
- DrawMPic(surface[i1, i2] div 2, pos.x, pos.y);
- end;
- end
- else
- DrawMPic(0, pos.x, pos.y);
- if building[i1, i2] > 0 then
- begin
- List[k] := k;
- ListIndex[k] := k;
- BuildingPos[k].x := i1;
- BuildingPos[k].y := i2;
- BuildingPic[k] := building[i1, i2] div 2;
- temp[i1, i2] := k;
- for j1 := i1 downto mini1 do
- begin
- for j2 := i2 downto mini2 do
- begin
- if j1 + j2 < Mx + My - 29 then
- continue;
- if (BuildX[j1, j2] = i2) and (BuildY[j1, j2] = i1) then
- begin
- tempindex[j1, j2] := k;
- end;
- end;
- end;
- k := k + 1;
- end;
- if (i1 = Mx) and (i2 = My) then
- begin
- List[k] := k;
- ListIndex[k] := k;
- BuildingPos[k].x := i1;
- BuildingPos[k].y := i2;
- temp[i1, i2] := k;
- tempindex[i1, i2] := k;
- if InShip = 0 then
- if still = 0 then
- BuildingPic[k] := 2500 + MFace * 7 + MStep
- else
- BuildingPic[k] := 2528 + Mface * 6 + MStep
- else
- BuildingPic[k] := 3714 + MFace * 4 + (MStep + 1) div 2;
- k := k + 1;
- end;
- end;
- BAmount := k;
- for sum := -29 to 41 do
- begin
- for i := -16 to 16 do
- begin
- i1 := Mx + i + (sum div 2);
- i2 := My - i + (sum - sum div 2);
- if temp[i1, i2] < 0 then
- begin
- continue;
- end;
- for j1 := i1 downto mini1 do
- begin
- for j2 := i2 downto mini2 do
- begin
- if j1 + j2 < Mx + My - 29 then
- continue;
- b := temp[i1, i2];
- a := tempindex[j1, j2];
- if (ListIndex[b] < ListIndex[a]) and (a < BAmount) then
- begin
- swaptemp := List[ListIndex[a]];
- for k := ListIndex[a] downto ListIndex[b] + 1 do
- List[k] := List[k - 1];
- List[ListIndex[b]] := swaptemp;
- for k := 0 to BAmount - 1 do
- begin
- ListIndex[List[k]] := k;
- end;
- end;
- end;
- end;
- end;
- end;
- for i := 0 to BAmount - 1 do
- begin
- x := BuildingPos[List[i]].x;
- y := BuildingPos[List[i]].y;
- Pos := GetPositionOnScreen(x, y, Mx, My);
- DrawMPic(BuildingPic[List[i]], pos.x, pos.y);
- end;
- DrawClouds;
- if (SDL_MustLock(screen)) then
- begin
- SDL_UnlockSurface(screen);
- end;
- //SDL_UpdateRect(screen, 0,0,screen.w,screen.h);
- end;
复制代码 |