Skip to content
This repository was archived by the owner on Apr 29, 2025. It is now read-only.

Commit 534b1ab

Browse files
committed
feat(grid): add a grid system
Based on mkafrin's grid used by PolyZone's ComboZones.
1 parent 9e7750b commit 534b1ab

File tree

1 file changed

+187
-0
lines changed

1 file changed

+187
-0
lines changed

imports/grid/shared.lua

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
--[[
2+
Based on PolyZone's grid system (https://github.com/mkafrin/PolyZone/blob/master/ComboZone.lua)
3+
4+
MIT License
5+
6+
Copyright (c) 2019-2021 Michael Afrin
7+
8+
Permission is hereby granted, free of charge, to any person obtaining a copy
9+
of this software and associated documentation files (the "Software"), to deal
10+
in the Software without restriction, including without limitation the rights
11+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
copies of the Software, and to permit persons to whom the Software is
13+
furnished to do so, subject to the following conditions:
14+
15+
The above copyright notice and this permission notice shall be included in all
16+
copies or substantial portions of the Software.
17+
18+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24+
SOFTWARE.
25+
]]
26+
27+
local mapMinX = -3700
28+
local mapMinY = -4400
29+
local mapMaxX = 4500
30+
local mapMaxY = 8000
31+
local xDelta = (mapMaxX - mapMinX) / 34
32+
local yDelta = (mapMaxY - mapMinY) / 50
33+
local grid = {}
34+
local lastCell = {}
35+
local lastNearbyEntries = {}
36+
local entrySet = {}
37+
38+
lib.grid = {}
39+
40+
---@class GridEntry
41+
---@field coords vector
42+
---@field length? number
43+
---@field width? number
44+
---@field radius? number
45+
---@field [string] any
46+
47+
---@param point vector
48+
---@param length number
49+
---@param width number
50+
---@return number, number, number, number
51+
local function getGridDimensions(point, length, width)
52+
local minX = (point.x - width - mapMinX) // xDelta
53+
local maxX = (point.x + width - mapMinX) // xDelta
54+
local minY = (point.y - length - mapMinY) // yDelta
55+
local maxY = (point.y + length - mapMinY) // yDelta
56+
57+
return minX, maxX, minY, maxY
58+
end
59+
60+
---@param point vector
61+
---@return number, number
62+
function lib.grid.getCellPosition(point)
63+
local x = (point.x - mapMinX) // xDelta
64+
local y = (point.y - mapMinY) // yDelta
65+
66+
return x, y
67+
end
68+
69+
---@param point vector
70+
---@return GridEntry[]
71+
function lib.grid.getCell(point)
72+
local x, y = lib.grid.getCellPosition(point)
73+
74+
if lastCell.x ~= x or lastCell.y ~= y then
75+
lastCell.x = x
76+
lastCell.y = y
77+
lastCell.cell = grid[y] and grid[y][x] or {}
78+
end
79+
80+
return lastCell.cell
81+
end
82+
83+
---@param point vector
84+
---@return GridEntry[]
85+
function lib.grid.getNearbyEntries(point)
86+
local minX, maxX, minY, maxY = getGridDimensions(point, xDelta, yDelta)
87+
88+
if lastNearbyEntries.minX == minX and
89+
lastNearbyEntries.maxX == maxX and
90+
lastNearbyEntries.minY == minY and
91+
lastNearbyEntries.maxY == maxY then
92+
return lastNearbyEntries.entries
93+
end
94+
95+
local entries = {}
96+
local n = 0
97+
98+
table.wipe(entrySet)
99+
100+
for y = minY, maxY do
101+
local row = grid[y]
102+
103+
for x = minX, maxX do
104+
local cell = row and row[x]
105+
106+
if cell then
107+
for j = 1, #cell do
108+
local entry = cell[j]
109+
110+
if not entrySet[entry] then
111+
n = n + 1
112+
entrySet[entry] = true
113+
entries[n] = entry
114+
end
115+
end
116+
end
117+
end
118+
end
119+
120+
lastNearbyEntries.minX = minX
121+
lastNearbyEntries.maxX = maxX
122+
lastNearbyEntries.minY = minY
123+
lastNearbyEntries.maxY = maxY
124+
lastNearbyEntries.entries = entries
125+
126+
return entries
127+
end
128+
129+
---@param entry { coords: vector, length?: number, width?: number, radius?: number, [string]: any }
130+
function lib.grid.addEntry(entry)
131+
entry.length = entry.length or entry.radius * 2
132+
entry.width = entry.width or entry.radius * 2
133+
local minX, maxX, minY, maxY = getGridDimensions(entry.coords, entry.length, entry.width)
134+
135+
for y = minY, maxY do
136+
local row = grid[y] or {}
137+
138+
for x = minX, maxX do
139+
local cell = row[x] or {}
140+
141+
cell[#cell + 1] = entry
142+
row[x] = cell
143+
end
144+
145+
grid[y] = row
146+
end
147+
end
148+
149+
---@param entry table A table that was added to the grid previously.
150+
function lib.grid.removeEntry(entry)
151+
local minX, maxX, minY, maxY = getGridDimensions(entry.coords, entry.length, entry.width)
152+
local success = false
153+
154+
for y = minY, maxY do
155+
local row = grid[y]
156+
157+
if not row then goto continue end
158+
159+
for x = minX, maxX do
160+
local cell = row[x]
161+
162+
if cell then
163+
for i = 1, #cell do
164+
if cell[i] == entry then
165+
table.remove(cell, i)
166+
success = true
167+
break
168+
end
169+
end
170+
171+
if #cell == 0 then
172+
row[x] = nil
173+
end
174+
end
175+
end
176+
177+
if not next(row) then
178+
grid[y] = nil
179+
end
180+
181+
::continue::
182+
end
183+
184+
return success
185+
end
186+
187+
return lib.grid

0 commit comments

Comments
 (0)