Code:
Type
tItem =
Record
Item,X : Word;
End;
pItem = ^tItem;
tOrder = Array[0..300] of tItem;
Const
ItemSize = SizeOf(tItem);
Var
// OrderHeap : Array[0..GroundSizeY] of ^tOrder;//tHeapArray;
OrderHeap : Array[0..GroundSizeY] of ^tOrder;
pHeap : Pointer;
// DrawOrder : Array[0..GroundSizeY] of PWordArray;// absolute OrderHeap;//Array[0..GroundSizeY] of Pointer;
Items : Array[0..GroundSizeY] of LongInt;
Dummy : pItem;
Procedure InitHeap;
Var
y : longword;
Begin
For y := 0 to GroundSizeY do
Begin
GetMem(OrderHeap[y],SizeOf(tOrder));
FillChar(OrderHeap[y]^[0],SizeOf(tOrder),00);
Items[y] := 0;
End;
End;
Procedure AddItem(y : LongWord; Data : tItem);
Var
b : longword;
Begin
OrderHeap[y]^[Items[y]] := data;
// writeln(y);
Inc(Items[y]);
End;
Function ReadItem(y,x : LongWord) : tItem;
Begin
ReadItem := OrderHeap[y]^[x];
End;
Procedure MoveItem(y : LongWord; Src,Dest : Word);
Var
Dummy2 : pItem;
Begin
OrderHeap[y]^[Dest] := OrderHeap[y]^[Src];
OrderHeap[y]^[Src] := OrderHeap[y]^[Items[y]-1];
Dec(Items[y]);
End;
Procedure MoveItemToY(y1 : word; Src : byte; y2 : word);
Var
xxx : LongWord;
Begin
OrderHeap[y2]^[Items[y2]] := OrderHeap[y1]^[Src];
OrderHeap[y1]^[Src] := OrderHeap[y1]^[Items[y1]-1];
Dec(Items[y1]);
Inc(Items[y2]);
End;
There are a few things to mind here.
"OrderHeap" is actually just one long chain of bytes. Memory allocation is silly,
but i want to switch this to actual pointers each pointing to the beginning of their
line in one huge chunk of heap. ^_^
GroundSizeY currently is ... 8192*2 = 16384, times 4 Bytes, times 300 items per Y ...
making OrderHeap 19 MByte big ... which isn't even a lot.
Please note that OrderHeap's height equals the depth of the drawn, visual city. (aka top to bottom of whole rendered map)
I have "Blocks" of 512x512, which i plot at 256x256 to have more details when zoomed in.
Now how does it work ?
First, I'm scanning through a 128x128 bitmap.
If a pixel is set, i calculate the y-position of the tile on the image
and add an item to it's corresponding y-line in DrawOrder.
Code:
For y := 0 to 127 do
For x := 0 to 127 do
Begin
If (CityMap[x,y] <> 0) then
Begin
m := x;
v := (y*64); // v is the line we have our tile set at.
// writeln(m,' : ',v);
xxx.Item := MaxHumans;
xxx.X := m;
AddItem(v,xxx);
End;
End;
MaxHumans. That's a constant limiting the amount of NPC humans walking around on the map.
With MaxHumans, the first building-tile starts. It's not relevant to this thread.
After this went through, i had my OrderHeap filled.
f = Y of the top most visible line on screen
g = Y of the bottom most ...
Code:
for y := f to g do
begin
if (Items[y] > 0) then
for x := 0 to Items[y] - 1 do
begin
xxx := ReadItem(y, x);
m := xxx.X * (BlockSize div 2);
v := y;
DropSprite(0, m, v - (BlockSize div 2), BlockSize, BlockSize);
end;
end;
Now this is a bit tricky. Obviously i have no idea how you made your tiles
and how you plan on dropping them onto screen.
All this basically does is go through a whole line and draw everything onto the backbuffer.
Sorting on X is completely unnecessary, so we can just weeze through it all at once,
enjoying the fact that we're making the cache happy too.
This way ... buildings stay behind people ... or in front of them.
There's something else i have to add, although i'm not sure if it will affect you.
(v - (BlockSize div 2)) shows that i am dropping the Sprite actually ABOVE the current OrderHeap[y].
This makes sense to me, because it pushes the tiles center line to y. Isometric tiles are basically blocks,
starting with a tight top, extending into center and tightening again towards the bottom.
Having it's center line at y will prevent sprites from wrongly overlapping with it.
Bookmarks