Avoid extra mapping of searched items.

This commit is contained in:
Davy Hélard
2023-11-09 11:42:08 +01:00
parent e45ba9465d
commit 7f7a13dee8
8 changed files with 624 additions and 660 deletions

View File

@@ -1,11 +1,9 @@
namespace gdjs {
declare var rbush: any;
export class LightObstaclesManager {
_obstacleRBush: any;
_obstacleRBush: RBush<LightObstacleRuntimeBehavior>;
constructor(instanceContainer: gdjs.RuntimeInstanceContainer) {
this._obstacleRBush = new rbush();
this._obstacleRBush = new RBush<LightObstacleRuntimeBehavior>();
}
/**
@@ -41,6 +39,9 @@ namespace gdjs {
* added before.
*/
removeObstacle(obstacle: gdjs.LightObstacleRuntimeBehavior) {
if (!obstacle.currentRBushAABB) {
return;
}
this._obstacleRBush.remove(obstacle.currentRBushAABB);
}
@@ -59,9 +60,9 @@ namespace gdjs {
// is not necessarily in the middle of the object (for sprites for example).
const x = object.getX();
const y = object.getY();
const searchArea = gdjs.staticObject(
const searchArea: SearchArea = gdjs.staticObject(
LightObstaclesManager.prototype.getAllObstaclesAround
);
) as SearchArea;
// @ts-ignore
searchArea.minX = x - radius;
// @ts-ignore
@@ -70,13 +71,8 @@ namespace gdjs {
searchArea.maxX = x + radius;
// @ts-ignore
searchArea.maxY = y + radius;
const nearbyObstacles: gdjs.BehaviorRBushAABB<
gdjs.LightObstacleRuntimeBehavior
>[] = this._obstacleRBush.search(searchArea);
result.length = 0;
nearbyObstacles.forEach((nearbyObstacle) =>
result.push(nearbyObstacle.behavior)
);
this._obstacleRBush.search(searchArea, result);
}
}

View File

@@ -7,7 +7,6 @@ namespace gdjs {
export interface RuntimeInstanceContainer {
pathfindingObstaclesManager: gdjs.PathfindingObstaclesManager;
}
declare var rbush: any;
/**
* PathfindingObstaclesManager manages the common objects shared by objects
@@ -18,10 +17,10 @@ namespace gdjs {
* `gdjs.PathfindingRuntimeBehavior.obstaclesManagers`).
*/
export class PathfindingObstaclesManager {
_obstaclesRBush: any;
_obstaclesRBush: RBush<PathfindingObstacleRuntimeBehavior>;
constructor(instanceContainer: gdjs.RuntimeInstanceContainer) {
this._obstaclesRBush = new rbush();
this._obstaclesRBush = new RBush<PathfindingObstacleRuntimeBehavior>();
}
/**
@@ -60,6 +59,9 @@ namespace gdjs {
removeObstacle(
pathfindingObstacleBehavior: PathfindingObstacleRuntimeBehavior
) {
if (!pathfindingObstacleBehavior.currentRBushAABB) {
return;
}
this._obstaclesRBush.remove(pathfindingObstacleBehavior.currentRBushAABB);
}
@@ -74,9 +76,9 @@ namespace gdjs {
radius: float,
result: gdjs.PathfindingObstacleRuntimeBehavior[]
): void {
const searchArea = gdjs.staticObject(
const searchArea: SearchArea = gdjs.staticObject(
PathfindingObstaclesManager.prototype.getAllObstaclesAround
);
) as SearchArea;
// @ts-ignore
searchArea.minX = x - radius;
// @ts-ignore
@@ -85,13 +87,8 @@ namespace gdjs {
searchArea.maxX = x + radius;
// @ts-ignore
searchArea.maxY = y + radius;
const nearbyObstacles: gdjs.BehaviorRBushAABB<
gdjs.PathfindingObstacleRuntimeBehavior
>[] = this._obstaclesRBush.search(searchArea);
result.length = 0;
nearbyObstacles.forEach((nearbyObstacle) =>
result.push(nearbyObstacle.behavior)
);
this._obstaclesRBush.search(searchArea, result);
}
}

View File

@@ -3,7 +3,6 @@ GDevelop - Platform Behavior Extension
Copyright (c) 2013-2016 Florian Rival (Florian.Rival@gmail.com)
*/
namespace gdjs {
declare var rbush: any;
type SearchArea = { minX: float; minY: float; maxX: float; maxY: float };
/**
@@ -13,11 +12,11 @@ namespace gdjs {
* of their associated container (see PlatformRuntimeBehavior.getManager).
*/
export class PlatformObjectsManager {
private _platformRBush: any;
private _platformRBush: RBush<PlatformRuntimeBehavior>;
private movedPlatforms: Array<gdjs.PlatformRuntimeBehavior>;
constructor(instanceContainer: gdjs.RuntimeInstanceContainer) {
this._platformRBush = new rbush();
this._platformRBush = new RBush<PlatformRuntimeBehavior>();
this.movedPlatforms = [];
gdjs.registerRuntimeScenePreEventsCallback(() => this.doStepPreEvents());
}
@@ -30,8 +29,9 @@ namespace gdjs {
if (!instanceContainer.platformsObjectsManager) {
//Create the shared manager if necessary.
// @ts-ignore
instanceContainer.platformsObjectsManager =
new gdjs.PlatformObjectsManager(instanceContainer);
instanceContainer.platformsObjectsManager = new gdjs.PlatformObjectsManager(
instanceContainer
);
}
// @ts-ignore
return instanceContainer.platformsObjectsManager;
@@ -55,6 +55,9 @@ namespace gdjs {
* added before.
*/
removePlatform(platformBehavior: gdjs.PlatformRuntimeBehavior) {
if (!platformBehavior.currentRBushAABB) {
return;
}
this._platformRBush.remove(platformBehavior.currentRBushAABB);
}
@@ -93,24 +96,19 @@ namespace gdjs {
const searchArea: SearchArea = gdjs.staticObject(
PlatformObjectsManager.prototype.getAllPlatformsAround
) as SearchArea;
const nearbyPlatforms: Array<BehaviorRBushAABB<PlatformRuntimeBehavior>> =
gdjs.staticArray(
PlatformObjectsManager.prototype.getAllPlatformsAround
);
nearbyPlatforms.length = 0;
result.length = 0;
searchArea.minX = x - ow / 2 - maxMovementLength;
searchArea.minY = y - oh / 2 - maxMovementLength;
searchArea.maxX = x + ow / 2 + maxMovementLength;
searchArea.maxY = y + oh / 2 + maxMovementLength;
this._platformRBush.search(searchArea, nearbyPlatforms);
result.length = 0;
this._platformRBush.search(searchArea, result);
// Extra check on the platform owner AABB
// TODO: PR https://github.com/4ian/GDevelop/pull/2602 should remove the need
// for this extra check once merged.
for (let i = 0; i < nearbyPlatforms.length; i++) {
const platform = nearbyPlatforms[i].behavior;
let writtenIndex = 0;
for (let readIndex = 0; readIndex < result.length; readIndex++) {
const platform = result[readIndex];
const platformAABB = platform.owner.getAABB();
const platformIsStillAround =
platformAABB.min[0] <= searchArea.maxX &&
@@ -121,10 +119,11 @@ namespace gdjs {
// This can happen because platforms are not updated in the RBush before that
// characters movement are being processed.
if (platformIsStillAround) {
result.push(platform);
result[writtenIndex] = platform;
writtenIndex++;
}
}
nearbyPlatforms.length = 0;
result.length = writtenIndex;
}
}
@@ -144,8 +143,9 @@ namespace gdjs {
_oldWidth: float = 0;
_oldHeight: float = 0;
_oldAngle: float = 0;
currentRBushAABB: gdjs.BehaviorRBushAABB<PlatformRuntimeBehavior> | null =
null;
currentRBushAABB: gdjs.BehaviorRBushAABB<
PlatformRuntimeBehavior
> | null = null;
_manager: gdjs.PlatformObjectsManager;
_registeredInManager: boolean = false;
_isAABBInvalidated = false;

View File

@@ -1,22 +1,19 @@
namespace gdjs {
declare var rbush: any;
type SearchArea = { minX: float; minY: float; maxX: float; maxY: float };
// TODO Do something like BehaviorRBushAABB
// TODO Allow to use getVisibilityAABB or getAABB
export class ObjectManager {
private _allInstances: Array<RuntimeObject> = [];
private _awakeInstances: Array<RuntimeObject> = [];
private _rbush: any;
private _rbush: RBush<RuntimeObject>;
constructor() {
this._rbush = new rbush();
this._rbush = new RBush<RuntimeObject>();
}
_destroy(): void {
this._allInstances = [];
this._awakeInstances = [];
this._rbush = null;
this._rbush.clear();
}
search(
@@ -35,7 +32,7 @@ namespace gdjs {
}
private _onWakingUp(object: RuntimeObject): void {
this._rbush.remove(object);
this._rbush.remove(object._rtreeAABB);
this._awakeInstances.push(object);
}
@@ -45,11 +42,11 @@ namespace gdjs {
(object: RuntimeObject) => object.getSpatialSearchSleepState(),
(object: RuntimeObject) => {
const objectAABB = object.getAABB();
object.minX = objectAABB.min[0];
object.minY = objectAABB.min[1];
object.maxX = objectAABB.max[0];
object.maxY = objectAABB.max[1];
this._rbush.insert(object);
object._rtreeAABB.minX = objectAABB.min[0];
object._rtreeAABB.minY = objectAABB.min[1];
object._rtreeAABB.maxX = objectAABB.max[0];
object._rtreeAABB.maxY = objectAABB.max[1];
this._rbush.insert(object._rtreeAABB);
}
);
}
@@ -98,7 +95,7 @@ namespace gdjs {
}
}
if (!isAwake) {
this._rbush.remove(object);
this._rbush.remove(object._rtreeAABB);
}
return isObjectDeleted;
}

File diff suppressed because it is too large Load Diff

View File

@@ -16,18 +16,18 @@ namespace gdjs {
minY: float = 0;
maxX: float = 0;
maxY: float = 0;
behavior: T;
source: T;
constructor(behavior: T) {
this.behavior = behavior;
this.source = behavior;
this.updateAABBFromOwner();
}
updateAABBFromOwner() {
this.minX = this.behavior.owner.getAABB().min[0];
this.minY = this.behavior.owner.getAABB().min[1];
this.maxX = this.behavior.owner.getAABB().max[0];
this.maxY = this.behavior.owner.getAABB().max[1];
this.minX = this.source.owner.getAABB().min[0];
this.minY = this.source.owner.getAABB().min[1];
this.maxX = this.source.owner.getAABB().max[0];
this.maxY = this.source.owner.getAABB().max[1];
}
}

View File

@@ -195,12 +195,7 @@ namespace gdjs {
protected hitBoxesDirty: boolean = true;
// TODO use a different AABB for collision mask and rendered image.
protected aabb: AABB = { min: [0, 0], max: [0, 0] };
// TODO
minX = 0;
minY = 0;
maxX = 0;
maxY = 0;
_rtreeAABB: SearchedItem<RuntimeObject>;
protected _isIncludedInParentCollisionMask = true;
@@ -261,6 +256,13 @@ namespace gdjs {
this._lifecycleSleepState = new gdjs.ObjectSleepState(this, () =>
this.isNeedingLifecycleFunctions()
);
this._rtreeAABB = {
source: this,
minX: 0,
minY: 0,
maxX: 0,
maxY: 0,
};
this._spatialSearchSleepState = new gdjs.ObjectSleepState(
this,
() => false

19
GDJS/Runtime/types/rbush.d.ts vendored Normal file
View File

@@ -0,0 +1,19 @@
type SearchArea = { minX: float; minY: float; maxX: float; maxY: float };
type SearchedItem<T> = {
source: T;
minX: float;
minY: float;
maxX: float;
maxY: float;
};
declare class RBush<T> {
constructor(maxEntries?: number);
search(bbox: SearchArea, result?: Array<T>): Array<T>;
insert(item: SearchedItem<T>): RBush<T>;
clear(): RBush<T>;
remove(
item: SearchedItem<T>,
equalsFn?: (item: SearchedItem<T>, otherItem: SearchedItem<T>) => boolean
): RBush<T>;
}