mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 13:20:43 +00:00
Improve UnitGrid performances by grouping units by type (#1592)
## Description: Even with the internal grid, `UnitGrid::nearbyUnits` can consume a significant amount of CPU, where it can account for ~5% of the rendering thread. Most of this overhead comes from filtering units by type. This PR improves performance by storing units in type-specific sets, significantly reducing lookup time. It reduces the usage to ~1% with this change:  ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced - [x] I have read and accepted the CLA agreement (only required once). ## Please put your Discord username so you can be contacted if a bug or regression is found: IngloriousTom --------- Co-authored-by: Tom Rouillard <trouilla@mathworks.com> Co-authored-by: Scott Anderson <662325+scottanderson@users.noreply.github.com>
This commit is contained in:
+30
-18
@@ -3,7 +3,7 @@ import { GameMap, TileRef } from "./GameMap";
|
||||
import { UnitView } from "./GameView";
|
||||
|
||||
export class UnitGrid {
|
||||
private grid: Set<Unit | UnitView>[][];
|
||||
private grid: Map<UnitType, Set<Unit | UnitView>>[][];
|
||||
private readonly cellSize = 100;
|
||||
|
||||
constructor(private gm: GameMap) {
|
||||
@@ -12,7 +12,7 @@ export class UnitGrid {
|
||||
.map(() =>
|
||||
Array(Math.ceil(gm.width() / this.cellSize))
|
||||
.fill(null)
|
||||
.map(() => new Set<Unit | UnitView>()),
|
||||
.map(() => new Map<UnitType, Set<Unit | UnitView>>()),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,15 @@ export class UnitGrid {
|
||||
const [gridX, gridY] = this.getGridCoords(this.gm.x(tile), this.gm.y(tile));
|
||||
|
||||
if (this.isValidCell(gridX, gridY)) {
|
||||
this.grid[gridY][gridX].add(unit);
|
||||
const unitSet = this.grid[gridY][gridX].get(unit.type());
|
||||
if (unitSet !== undefined) {
|
||||
unitSet.add(unit);
|
||||
} else {
|
||||
this.grid[gridY][gridX].set(
|
||||
unit.type(),
|
||||
new Set<Unit | UnitView>([unit]),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +49,10 @@ export class UnitGrid {
|
||||
const [gridX, gridY] = this.getGridCoords(this.gm.x(tile), this.gm.y(tile));
|
||||
|
||||
if (this.isValidCell(gridX, gridY)) {
|
||||
this.grid[gridY][gridX].delete(unit);
|
||||
const unitSet = this.grid[gridY][gridX].get(unit.type());
|
||||
if (unitSet !== undefined) {
|
||||
unitSet.delete(unit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,14 +145,17 @@ export class UnitGrid {
|
||||
const typeSet = Array.isArray(types) ? new Set(types) : new Set([types]);
|
||||
for (let cy = startGridY; cy <= endGridY; cy++) {
|
||||
for (let cx = startGridX; cx <= endGridX; cx++) {
|
||||
for (const unit of this.grid[cy][cx]) {
|
||||
if (!typeSet.has(unit.type())) continue;
|
||||
if (!unit.isActive()) continue;
|
||||
const distSquared = this.squaredDistanceFromTile(unit, tile);
|
||||
if (distSquared > rangeSquared) continue;
|
||||
const value = { unit, distSquared };
|
||||
if (predicate !== undefined && !predicate(value)) continue;
|
||||
nearby.push(value);
|
||||
for (const type of typeSet) {
|
||||
const unitSet = this.grid[cy][cx].get(type);
|
||||
if (unitSet === undefined) continue;
|
||||
for (const unit of unitSet) {
|
||||
if (!unit.isActive()) continue;
|
||||
const distSquared = this.squaredDistanceFromTile(unit, tile);
|
||||
if (distSquared > rangeSquared) continue;
|
||||
const value = { unit, distSquared };
|
||||
if (predicate !== undefined && !predicate(value)) continue;
|
||||
nearby.push(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -162,12 +176,10 @@ export class UnitGrid {
|
||||
const rangeSquared = searchRange * searchRange;
|
||||
for (let cy = startGridY; cy <= endGridY; cy++) {
|
||||
for (let cx = startGridX; cx <= endGridX; cx++) {
|
||||
for (const unit of this.grid[cy][cx]) {
|
||||
if (
|
||||
unit.type() === type &&
|
||||
unit.owner().id() === playerId &&
|
||||
unit.isActive()
|
||||
) {
|
||||
const unitSet = this.grid[cy][cx].get(type);
|
||||
if (unitSet === undefined) continue;
|
||||
for (const unit of unitSet) {
|
||||
if (unit.owner().id() === playerId && unit.isActive()) {
|
||||
const distSquared = this.squaredDistanceFromTile(unit, tile);
|
||||
if (distSquared <= rangeSquared) {
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user