DEADSOFTWARE

`atPoint` grid enumerator (for .. in)
authorKetmar Dark <ketmar@ketmar.no-ip.org>
Wed, 30 Aug 2017 10:42:57 +0000 (13:42 +0300)
committerKetmar Dark <ketmar@ketmar.no-ip.org>
Wed, 30 Aug 2017 11:14:40 +0000 (14:14 +0300)
src/game/g_grid.pas

index 346770246cfd96eb4bb196e9471360ef95763d13..442a776ea831b8fc1a103001c51331cecf7e4a3b 100644 (file)
@@ -71,6 +71,7 @@ type
         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
@@ -81,20 +82,36 @@ type
         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;
@@ -161,6 +178,8 @@ type
     // 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 atPoint (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
@@ -420,6 +439,40 @@ begin
 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
@@ -1108,6 +1161,18 @@ begin
 end;
 
 
+// ////////////////////////////////////////////////////////////////////////// //
+function TBodyGridBase.atPoint (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;