diff --git a/src/game/g_grid.pas b/src/game/g_grid.pas
index b4b0e32795cddfaa38864fa8154c2f260e903328..06790755698dfce7e15d73241fdabd65b4cbe689 100644 (file)
--- a/src/game/g_grid.pas
+++ b/src/game/g_grid.pas
property height: Integer read mHeight;
property tag: Integer read getTag write setTag;
property enabled: Boolean read getEnabled write setEnabled;
+ property obj: ITP read mObj;
end;
private
next: Integer; // in this cell; index in mCells
end;
+ TCellArray = array of TGridCell;
+
TGridInternalCB = function (grida: Integer; bodyId: TBodyProxyId): Boolean of object; // return `true` to stop
private
//mTileSize: Integer;
const mTileSize = GridDefaultTileSize;
+ type TGetProxyFn = function (pxidx: Integer): PBodyProxyRec of object;
public
const tileSize = mTileSize;
+ type
+ TAtPointEnumerator = record
+ private
+ mCells: TCellArray;
+ curidx, curbki: Integer;
+ getpx: TGetProxyFn;
+ public
+ constructor Create (acells: TCellArray; aidx: Integer; agetpx: TGetProxyFn);
+ function MoveNext (): Boolean; inline;
+ function getCurrent (): PBodyProxyRec; inline;
+ property Current: PBodyProxyRec read getCurrent;
+ end;
+
private
mMinX, mMinY: Integer; // so grids can start at any origin
mWidth, mHeight: Integer; // in tiles
mGrid: array of Integer; // mWidth*mHeight, index in mCells
- mCells: array of TGridCell; // cell pool
+ mCells: TCellArray; // cell pool
mFreeCell: Integer; // first free cell index or -1
mLastQuery: LongWord;
mUsedCells: Integer;
mProxyFree: TBodyProxyId; // free
mProxyCount: Integer; // currently used
mProxyMaxCount: Integer;
+ mInQuery: Boolean;
public
dbgShowTraceLog: Boolean;
// no callback: return object on the first hit or nil
function forEachAtPoint (x, y: Integer; cb: TGridQueryCB; tagmask: Integer=-1; exittag: PInteger=nil): ITP;
+ function atCellInPoint (x, y: Integer): TAtPointEnumerator;
+
//WARNING: don't modify grid while any query is in progress (no checks are made!)
// you can set enabled/disabled flag, tho (but iterator can still return objects disabled inside it)
// cb with `(nil)` will be called before processing new tile
end;
+// ////////////////////////////////////////////////////////////////////////// //
+constructor TBodyGridBase.TAtPointEnumerator.Create (acells: TCellArray; aidx: Integer; agetpx: TGetProxyFn);
+begin
+ mCells := acells;
+ curidx := aidx;
+ curbki := -1;
+ getpx := agetpx;
+end;
+
+
+function TBodyGridBase.TAtPointEnumerator.MoveNext (): Boolean; inline;
+begin
+ while (curidx <> -1) do
+ begin
+ while (curbki < GridCellBucketSize) do
+ begin
+ Inc(curbki);
+ if (mCells[curidx].bodies[curbki] = -1) then break;
+ result := true;
+ exit;
+ end;
+ curidx := mCells[curidx].next;
+ curbki := -1;
+ end;
+ result := false;
+end;
+
+
+function TBodyGridBase.TAtPointEnumerator.getCurrent (): PBodyProxyRec; inline;
+begin
+ result := getpx(mCells[curidx].bodies[curbki]);
+end;
+
+
// ////////////////////////////////////////////////////////////////////////// //
constructor TBodyGridBase.Create (aMinPixX, aMinPixY, aPixWidth, aPixHeight: Integer{; aTileSize: Integer=GridDefaultTileSize});
var
end;
+// ////////////////////////////////////////////////////////////////////////// //
+function TBodyGridBase.atCellInPoint (x, y: Integer): TAtPointEnumerator;
+var
+ cidx: Integer = -1;
+begin
+ Dec(x, mMinX);
+ Dec(y, mMinY);
+ if (x >= 0) and (y >= 0) and (x < mWidth*mTileSize) and (y < mHeight*mTileSize) then cidx := mGrid[(y div mTileSize)*mWidth+(x div mTileSize)];
+ result := TAtPointEnumerator.Create(mCells, cidx, getProxyById);
+end;
+
+
// ////////////////////////////////////////////////////////////////////////// //
// no callback: return `true` on the first hit
function TBodyGridBase.forEachAtPoint (x, y: Integer; cb: TGridQueryCB; tagmask: Integer=-1; exittag: PInteger=nil): ITP;
if (x+w <= 0) or (y+h <= 0) then exit;
if (x >= gw*tsize) or (y >= mHeight*tsize) then exit;
+ if mInQuery then raise Exception.Create('recursive queries aren''t supported');
+ mInQuery := true;
+
// increase query counter
Inc(mLastQuery);
if (mLastQuery = 0) then
if (x0+w <= px.mX) or (y0+h <= px.mY) then continue;
if assigned(cb) then
begin
- if cb(px.mObj, ptag) then begin result := px.mObj; exit; end;
+ if cb(px.mObj, ptag) then begin result := px.mObj; mInQuery := false; exit; end;
end
else
begin
result := px.mObj;
+ mInQuery := false;
exit;
end;
end;
end;
end;
end;
+
+ mInQuery := false;
end;
//if (dbgShowTraceLog) then e_WriteLog(Format('raycast start: (%d,%d)-(%d,%d); xptr^=%d; yptr^=%d', [ax0, ay0, ax1, ay1, xptr^, yptr^]), MSG_NOTIFY);
+ if mInQuery then raise Exception.Create('recursive queries aren''t supported');
+ mInQuery := true;
+
// increase query counter
Inc(mLastQuery);
if (mLastQuery = 0) then
y := yptr^+miny;
//prevx := x;
//prevy := y;
- {$IF DEFINED(D2F_DEBUG)}
- if hopt then
- begin
- if (y <> ay0) then raise Exception.Create('htrace fatal internal error');
- end
- else
- begin
- if (x <> ax0) then raise Exception.Create('vtrace fatal internal error');
- end;
- {$ENDIF}
while (wklen > 0) do
begin
{$IF DEFINED(D2F_DEBUG)}
result := px.mObj;
ex := x;
ey := y;
+ mInQuery := false;
exit;
end;
end
ex := x;
ey := y;
result := px.mObj;
+ mInQuery := false;
exit;
end;
end;
result := px.mObj;
ex := prevx;
ey := prevy;
+ mInQuery := false;
exit;
end;
end
// next cell
ccidx := cc.next;
end;
- if wasHit and not assigned(cb) then begin result := lastObj; exit; end;
- if assigned(cb) and cb(nil, 0, x, y, x, y) then begin result := lastObj; exit; end;
+ if wasHit and not assigned(cb) then begin result := lastObj; mInQuery := false; exit; end;
+ if assigned(cb) and cb(nil, 0, x, y, x, y) then begin result := lastObj; mInQuery := false; exit; end;
end;
// skip to next tile
if hopt then
end;
// we can travel less than one cell
if wasHit and not assigned(cb) then result := lastObj else begin ex := ax1; ey := ay1; end;
+ mInQuery := false;
exit;
end;
{$ENDIF}
// signal cell completion
if assigned(cb) then
begin
- if cb(nil, 0, xptr^+minx, yptr^+miny, prevx, prevy) then begin result := lastObj; exit; end;
+ if cb(nil, 0, xptr^+minx, yptr^+miny, prevx, prevy) then begin result := lastObj; mInQuery := false; exit; end;
end
else if wasHit then
begin
result := lastObj;
+ mInQuery := false;
exit;
end;
end;
result := px.mObj;
ex := prevx;
ey := prevy;
+ mInQuery := false;
exit;
end;
end
ccidx := -1;
if assigned(cb) then
begin
- if cb(nil, 0, x, y, prevx, prevy) then begin result := lastObj; exit; end;
+ if cb(nil, 0, x, y, prevx, prevy) then begin result := lastObj; mInQuery := false; exit; end;
end
else if wasHit then
begin
result := lastObj;
+ mInQuery := false;
exit;
end;
end;
ex := ax1; // why not?
ey := ay1; // why not?
end;
+
+ mInQuery := false;
end;
temp: Integer;
ccidx, curci: Integer;
lastGA: Integer = -1;
- ga, x, y: Integer;
+ ga: Integer;
gw, gh, minx, miny, maxx, maxy: Integer;
cc: PGridCell;
px: PBodyProxyRec;
//lastGA := (yptr^ div tsize)*gw+(xptr^ div tsize);
//ccidx := mGrid[lastGA];
+ if mInQuery then raise Exception.Create('recursive queries aren''t supported');
+ mInQuery := true;
+
// increase query counter
Inc(mLastQuery);
if (mLastQuery = 0) then
if dbgShowTraceLog then e_LogWritefln('optimized htrace; wklen=%d', [wklen]);
{$ENDIF}
ga := (yptr^ div tsize)*gw+(xptr^ div tsize);
- // one of those will never change
- x := xptr^+minx;
- y := yptr^+miny;
- {$IF DEFINED(D2F_DEBUG)}
- if hopt then
- begin
- if (y <> ay0) then raise Exception.Create('htrace fatal internal error');
- end
- else
- begin
- if (x <> ax0) then raise Exception.Create('vtrace fatal internal error');
- end;
- {$ENDIF}
while (wklen > 0) do
begin
{$IF DEFINED(D2F_DEBUG)}
- if dbgShowTraceLog then e_LogWritefln(' htrace; ga=%d; x=%d, y=%d; y=%d; y=%d', [ga, xptr^+minx, yptr^+miny, y, ay0]);
+ if dbgShowTraceLog then e_LogWritefln(' htrace; ga=%d; x=%d, y=%d; ay0=%d', [ga, xptr^+minx, yptr^+miny, ay0]);
{$ENDIF}
// new tile?
if (ga <> lastGA) then
lastGA := ga;
ccidx := mGrid[lastGA];
// convert coords to map (to avoid ajdusting coords inside the loop)
- if hopt then x := xptr^+minx else y := yptr^+miny;
while (ccidx <> -1) do
begin
cc := @mCells[ccidx];
px.mQueryMark := lq; // mark as processed
if assigned(cb) then
begin
- if cb(px.mObj, ptag) then begin result := px.mObj; exit; end;
+ if cb(px.mObj, ptag) then begin result := px.mObj; mInQuery := false; exit; end;
end
else
begin
result := px.mObj;
+ mInQuery := false;
exit;
end;
end;
end;
Dec(wklen, wkstep);
end;
+ mInQuery := false;
exit;
end;
{$ENDIF}
begin
// process cell
curci := ccidx;
- // convert coords to map (to avoid ajdusting coords inside the loop)
- x := xptr^+minx;
- y := yptr^+miny;
// process cell list
while (curci <> -1) do
begin
px.mQueryMark := lq; // mark as processed
if assigned(cb) then
begin
- if cb(px.mObj, ptag) then begin result := px.mObj; exit; end;
+ if cb(px.mObj, ptag) then begin result := px.mObj; mInQuery := false; exit; end;
end
else
begin
result := px.mObj;
+ mInQuery := false;
exit;
end;
end;
if (e >= 0) then begin yd += sty; e -= dx2; end else e += dy2;
xd += stx;
end;
+
+ mInQuery := false;
end;