📄 isoengine.pas
字号:
procedure TIsoMap.SetImageString(ImageIndex: integer; const Value: string);
begin
if (ImageIndex>=0) then
begin
if (length(fImageStrings)<=ImageIndex) then setlength(FIMageSTrings,ImageIndex+1);
FImagestrings[ImageIndex] := value;
end;
end;
function TIsoMap.GetImageString(ImageIndex: integer): string;
begin
if (ImageIndex<0) then Result := ''
else
begin
if (length(fImageStrings)<=ImageIndex) then setlength(FIMageSTrings,ImageIndex+1);
result := FImageStrings[ImageIndex];
end;
end;
function TIsoMap._GetCoordCell(c: TCellsCoord): TIsoCell;
begin
result := IsoMap[c.x,c.y];
end;
function TIsoMap.AddComment(s: string): Integer;
var i,l : integer;
begin
l :=length(fcomments);
for i := 0 to l-1 do
begin
if (Fcomments[i]=s) then
begin
result := i;
exit;
end;
end;
setlength(fcomments,l+1);
FComments[l] := s;
Result := l;
end;
function TIsoMap.GetComment(i: Integer): string;
begin
if (i<0) then Result := ''
else
Result := fcomments[i];
end;
function TIsoMap.GetCellComment(x, y: TGridInt): string;
begin
result := GetComment(Cell[x,y].CommentID);
end;
procedure TIsoMap.SetCellComment(x, y: TGridInt; s: string);
begin
if (s='') then IsoMap[x,y].CommentID := -1
else
IsoMap[x,y].CommentID := AddComment(s);
end;
procedure TIsoMap.GetVisibleCorners(var MinX, MinY, MaxX, MaxY: Integer);
begin
MinX := MaxInt(0, XOffset div CellWidth - 1); // first visible left
MinY := MaxInt(0, YOffset div (fCellHeightdiv2) - 1); // first visible top
// MaxX := MinInt(MapWidth, MinX + (GetSurfaceWidth div CellWidth) + CellWidth);
MaxX := MinInt(MapWidth,MinX + (GetSurfaceWidth div CellWidth) + 2);
// MaxY := MinInt(MapHeight,MinY + GetSurfaceHeight div (FCellHeightdiv2) + 5);
MaxY := MinInt(MapHeight,MinY + GetSurfaceHeight div (FCellHeightdiv2) + 1);
end;
procedure TIsoMap.SetAllState(state: TCellState);
var Cellx,Celly : TGridInt;
begin
for cellx := 0 to MapWidth-1 do
for celly := 0 to MapHeight-1 do
IsoMap[Cellx,CellY].State := state;
end;
procedure TIsoMap.UpdateArea(p1, p2: TPoint);
var x,y : integer;
c1,c2 : TCellsCoord;
begin
if (p1.x < p2.x) then
begin c1 := CellAt(p1); c2 := Cellat(p2); end
else
begin c1 := Cellat(p2); c2 := CellAt(p1); end;
for x:= c1.X to c2.X do
begin
if (c1.Y < c2.Y) then
begin
for y := c1.Y to c2.Y do
AddState(X,Y,[tsDirty]);
end
else
for y := c2.Y to c1.Y do
AddState(X,Y,[tsDirty]);
end;
end;
procedure TIsoMap.UpdateArea(x1, y1, x2, y2: integer);
var p1,p2 : Tpoint;
begin
p1.x := x1; p1.y := y1;
p2.x := x2; p2.y := y2;
UpdateArea(p1,p2);
end;
function TIsoMap.CellAt(x, y: integer): TCellsCoord;
var p : TPoint;
begin
p.x := x; p.y := y;
result := CellAt(p);
end;
// this set of procedures are the guts of the engine. It draws the map over and over and over...
procedure TIsoMap.CountDirtyCells; // this isn't neeed but is nice to have for stats sake
var x,y : integer;
begin
dirtyCount := 0;
for x:= 0 to MapWidth-1 do
for y := 0 to MapHeight -1 do
if (tsDirty in IsoMap[x,y].State) then
inc(dirtycount);
end;
procedure TIsoMap.MarkDirty(x,y : integer); // mark any cells that are overlapped from this image
var ic,x1,y1,ImageIndex,ImageHeight,ImageWidth,l,f,t : integer;
begin
ic := GetImageCount;
f := IsoMap[x,y].AlwaysDisplayFrom;
t := IsoMap[x,y].AlwaysDisplayTo;
ImageHeight := CellHeight;
ImageWidth := CellWidth;
for l := f to t+1 do
begin
gx := x;
gy := y;
gl := l;
if (l<=t) then
ImageIndex := IsoMap[x,y].imageindexes[l-1].ImageIndex
else
if ((IsoMap[x,y].AnimateNext-1)>=0) and
(IsoMap[x,y].animateNext< Length(IsoMap[x,y].ImageIndexes)) then
ImageIndex := IsoMap[x,y].ImageIndexes[IsoMap[x,y].AnimateNext-1].ImageIndex
else
ImageIndex := -1;
if (ImageIndex<0) or (ImageIndex>ic) then Continue;
x1 := GetImageHeight(ImageIndex);
y1 := GetImageWidth(ImageIndex);
if (x1>ImageHeight) then ImageHeight := x1;
if (y1>ImageWidth) then ImageWidth := y1;
end;
// we should now have the largest height and width of any image this cell will create
ImageHeight := ImageHeight div FCellHeight; // number of cells changed
ImageWidth := ImageWidth div FCellWidth;
for x1 := MaxInt(0,x - ImageWidth) to x do
for y1 := MaxInt(0,y - ImageHeight) to y do
if (not(isstate(x1,y1,[tsDirty]))) then
begin
Inc(DirtyCount);
IsoMap[x1,y1].State := IsoMap[x1,y1].State + [tsDirty];
end;
end;
function TIsoMap.CheckForDirtyOverlap(x,y,l : integer) : boolean; // check to see if we are overlapping any dirty cells
var x1,y1,ImageIndex,ImageHeight,ImageWidth : Integer;
begin
ImageIndex := IsoMap[x,y].ImageIndexes[l-1].ImageIndex;
Result := False;
if (ImageIndex<0) then Exit;
ImageHeight := GetImageHeight(ImageIndex);
ImageWidth := GetImageWidth(ImageIndex);
ImageHeight := ImageHeight div FCellHeight; // number of cells changed
ImageWidth := ImageWidth div FCellWidth;
if (ImageWidth=1) and (ImageHeight=1) then Exit; // this image doesn't cross cell boundries
Result := True;
for x1 := MaxInt(0,x-ImageWidth) to x do
for y1 := MaxInt(0,y-ImageHeight) to y do
if (isstate(x1,y1,[tsDirty])) then Exit;
Result := False;
end;
procedure TIsoMap.CheckForDirtyCells;
var x,y,MaxTo,l : integer;
Marked : Boolean;
begin
MaxTo := 0;
l := 0;
while(l<=MaxTo) do
begin
Inc(l);
// mark off the animation part first, it may affect other things
for x:= 0 to MapWidth-1 do
for y := 0 to MapHeight -1 do
begin
Marked := False;
if (IsoMap[x,y].AnimateFrom < IsoMap[x,y].AnimateTo) then
begin
if (IsoMap[x,y].AnimateCount=0) then
begin
Inc(IsoMap[x,y].AnimateNext);
if (IsoMap[x,y].AnimateNext > IsoMap[x,y].AnimateTo) then
IsoMap[x,y].AnimateNext := Isomap[x,y].AnimateFrom;
IsoMap[x,y].AnimateCount := Isomap[x,y].AnimateSpeed; // reset the counter
end
else Dec(IsoMap[x,y].AnimateCount);
if ((IsoMap[x,y].AnimateNext-1)>=0) and
(IsoMap[x,y].animateNext< Length(IsoMap[x,y].IMageIndexes)) then
Marked := -1 <> IsoMap[x,y].ImageIndexes[IsoMap[x,y].AnimateNext-1].ImageIndex;
end;
if (IsoMap[x,y].AlwaysDisplayTo > MaxTo) then
MaxTo := IsoMap[x,y].AlwaysDisplayTo;
if (l>=IsoMap[x,y].AlwaysDisplayFrom) and (l<=IsoMap[x,y].AlwaysDisplayTo) then
begin
Marked := (tsDirty in IsoMap[x,y].State); // found dirty cell
if (not Marked) then
begin // this cell's clean. How about cell's it may be overlapping?
Marked := (IsoMap[x,y].ImageIndexes[l-1].ImageIndex <= GetImageCount)
and CheckForDirtyOverlap(x,y,l) ;// eg a tree behind a building changed
// must update the building because the
// tree might be showing through a window
end;
end;
if (Marked) then
MarkDirty(x,y);
end;
end;
end;
procedure TIsoMap.DrawIsoMap;
var ix,iy,x,y,l,MinX,MinY,MaxX,MaxY : TGridInt;
MaxTo,ImageWidth,ImageHeight,ImageIndex : Integer;
procedure DrawBackground;
var x,y : integer;
begin
l := 0;
MaxTo := 0; // this is reset because the area displayed may be less then what was checked for dirtyness
// and may have fewer layers.
while(l<=MaxTo) do
begin
Inc(l);
if (not LayerVisible[l]) then Continue;
for y := MinY to MaxY-1 do
for x := MinX to MaxX-1 do
begin
gx := x;
gy := y;
gl := l;
if not(tsDirty in IsoMap[x,y].State) then continue; // skip any cells that havent changed!
ix := (x * CellWidth) + ((y mod 2) * (fCellWidthDiv2)) - XOffset; //offset x
iy := (y * (fCellHeightDiv2)+ CellHeight) - YOffset; // variable height
if (IsoMap[x,y].AlwaysDisplayTo > MaxTo) then
MaxTo := IsoMap[x,y].AlwaysDisplayTo;
if (l>=IsoMap[x,y].AlwaysDisplayFrom) and (l<=IsoMap[x,y].AlwaysDisplayTo) then
begin
ImageIndex := IsoMap[x,y].ImageIndexes[l-1].ImageIndex;
// if (ImageIndex >-1) then
begin
if (ImageIndex > GetImageCount) then
Continue;
if (ImageIndex>-1) then
ImageHeight := GetImageHeight(ImageIndex)
else
ImageHeight := CellHeight;
DrawImage(IsoMap[x,y],ImageIndex,x,y,ScrollXOffset+ix,ScrollYOffset + iy - ImageHeight
- 0, // level offset
l, //layer
0); // animation later
end;
end;
end;
end;
end;
procedure DrawAnimation;
var x,y : integer;
begin
for y := MinY to MaxY-1 do
for x := MinX to MaxX-1 do
begin
if not(tsDirty in IsoMap[x,y].State) then continue; // skip any cells that havent changed!
if (IsoMap[x,y].AnimateFrom < IsoMap[x,y].AnimateTo) then
begin
{ This has already been done while marking dirty cells
if (IsoMap[x,y].AnimateCount=0) then
begin
Inc(IsoMap[x,y].AnimateNext);
if (IsoMap[x,y].AnimateNext > IsoMap[x,y].AnimateTo) then
IsoMap[x,y].AnimateNext := Isomap[x,y].AnimateFrom;
IsoMap[x,y].AnimateCount := Isomap[x,y].AnimateSpeed; // reset the counter
end
else Dec(IsoMap[x,y].AnimateCount);
}
if ((IsoMap[x,y].AnimateNext-1)>=0) and
(IsoMap[x,y].animateNext< Length(IsoMap[x,y].ImageIndexes)) then
ImageIndex := IsoMap[x,y].ImageIndexes[IsoMap[x,y].AnimateNext-1].ImageIndex
else
Continue;
if (ImageIndex = -1) then continue;
ImageHeight := GetImageHeight(ImageIndex);
DrawImage(IsoMap[x,y],ImageIndex,x,y,
ScrollXOffset+(x * CellWidth) + ((y mod 2) * (fCellWidthDiv2)) - XOffset, //offset x
ScrollYOffset+(y * (fCellHeightDiv2) - ImageHeight + CellHeight) // variable height
- YOffset //offset y
- 0, // level offset
32767, // animations are always the highest layer
0); // animation later
end;
end;
end;
procedure DrawGrids;
var x,y : integer;
begin
for y := MinY to MaxY-1 do
for x := MinX to MaxX-1 do
if (ShowGrid or (tsSelected in IsoMap[x,y].State)) then
begin
ix := ScrollXOffset+(x * CellWidth) + ((y mod 2) * (fCellWidthDiv2)) - XOffset; //offset x
iy := ScrollYOffset+(y * (fCellHeightDiv2)+ CellHeight) - YOffset; // variable height
if (ShowGrid) then
DrawGrid(ix,iy,-1)
else
DrawGrid(ix,iy,DrawCount);
end;
end;
begin
if (not CanDRaw) then Exit;
if (CellWidth=0) then Exit;
if (CellHeight < 2) then Exit;
GetVisibleCorners(MinX,MinY,MaxX,MaxY);
try
if (FBruteForce) then
begin
AddAllState([tsDirty]);// let's clear the screen 1st time
end
else
begin
if (DrawCount=0) then
begin
AddAllState([tsDirty]);// let's clear the screen 1st time
cls;
end
else
begin
CheckForDirtyCells;
end;
CountDirtyCells;
end;
DrawBackground;
DrawAnimation;
DrawGrids;
Inc(DrawCount);
finally
Flip;
if (DrawCount and 1)=1 then // keep dirty cells, so back buffer is updated with current screens data
begin
SubAllState([tsDirty]); // clear all dirty cells
AddAllStateState([tsSelected],[tsDirty]); // selected cells are dirty
end;
end;
end;
procedure TIsoMap.SetXOffset(const Value: Integer);
begin
if (Value>0) and (Value < MapWidth*FCellWidthDiv2) then
FXOffset := Value;
end;
procedure TIsoMap.SetYOffset(const Value: Integer);
begin
if (value>0) and (value< MapHeight * FCellHEightDiv2) then
FYOffset := Value;
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -