Skip to content

Commit

Permalink
Avoid to iterate on inactive objects
Browse files Browse the repository at this point in the history
  • Loading branch information
D8H committed Nov 28, 2023
1 parent d34f1a6 commit 166b31d
Show file tree
Hide file tree
Showing 19 changed files with 975 additions and 743 deletions.
8 changes: 8 additions & 0 deletions Extensions/3D/Model3DRuntimeObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ namespace gdjs {
);
}

if (this.isNeedingLifecycleFunctions()) {
this.getLifecycleSleepState().wakeUp();
}

// *ALWAYS* call `this.onCreated()` at the very end of your object constructor.
this.onCreated();
}
Expand Down Expand Up @@ -194,6 +198,10 @@ namespace gdjs {
}
}

isNeedingLifecycleFunctions(): boolean {
return super.isNeedingLifecycleFunctions() || this._animations.length > 0;
}

update(instanceContainer: gdjs.RuntimeInstanceContainer): void {
const elapsedTime = this.getElapsedTime() / 1000;
this._renderer.updateAnimation(elapsedTime * this._animationSpeedScale);
Expand Down
20 changes: 8 additions & 12 deletions Extensions/Lighting/lightobstacleruntimebehavior.ts
Original file line number Diff line number Diff line change
@@ -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>();
}

/**
Expand Down Expand Up @@ -41,6 +39,9 @@ namespace gdjs {
* added before.
*/
removeObstacle(obstacle: gdjs.LightObstacleRuntimeBehavior) {
if (!obstacle.currentRBushAABB) {
return;
}
this._obstacleRBush.remove(obstacle.currentRBushAABB);
}

Expand All @@ -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
Expand All @@ -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);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ namespace gdjs {
export interface RuntimeInstanceContainer {
pathfindingObstaclesManager: gdjs.PathfindingObstaclesManager;
}
declare var rbush: any;

/**
* PathfindingObstaclesManager manages the common objects shared by objects
Expand All @@ -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>();
}

/**
Expand Down Expand Up @@ -60,6 +59,9 @@ namespace gdjs {
removeObstacle(
pathfindingObstacleBehavior: PathfindingObstacleRuntimeBehavior
) {
if (!pathfindingObstacleBehavior.currentRBushAABB) {
return;
}
this._obstaclesRBush.remove(pathfindingObstacleBehavior.currentRBushAABB);
}

Expand All @@ -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
Expand All @@ -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);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,9 @@ namespace gdjs {
}

doStepPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {
// Update platforms locations.
this._manager.doStepPreEvents();

const LEFTKEY = 37;
const UPKEY = 38;
const RIGHTKEY = 39;
Expand Down
125 changes: 70 additions & 55 deletions Extensions/PlatformBehavior/platformruntimebehavior.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 };

/**
Expand All @@ -13,10 +12,12 @@ 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 = [];
}

/**
Expand All @@ -38,7 +39,7 @@ namespace gdjs {
/**
* Add a platform to the list of existing platforms.
*/
addPlatform(platformBehavior: gdjs.PlatformRuntimeBehavior) {
private addPlatform(platformBehavior: gdjs.PlatformRuntimeBehavior) {
if (platformBehavior.currentRBushAABB)
platformBehavior.currentRBushAABB.updateAABBFromOwner();
else
Expand All @@ -52,10 +53,39 @@ namespace gdjs {
* Remove a platform from the list of existing platforms. Be sure that the platform was
* added before.
*/
removePlatform(platformBehavior: gdjs.PlatformRuntimeBehavior) {
private removePlatform(platformBehavior: gdjs.PlatformRuntimeBehavior) {
if (!platformBehavior.currentRBushAABB) {
return;
}
this._platformRBush.remove(platformBehavior.currentRBushAABB);
}

invalidatePlatformHitbox(platformBehavior: gdjs.PlatformRuntimeBehavior) {
this.movedPlatforms.push(platformBehavior);
}

onDestroy(platformBehavior: gdjs.PlatformRuntimeBehavior): void {
if (!platformBehavior.activated()) {
return;
}
if (platformBehavior.isAABBInvalidated()) {
const index = this.movedPlatforms.indexOf(platformBehavior);
this.movedPlatforms.splice(index, 1);
}
this.removePlatform(platformBehavior);
}

doStepPreEvents() {
for (const platformBehavior of this.movedPlatforms) {
this.removePlatform(platformBehavior);
if (platformBehavior.activated()) {
this.addPlatform(platformBehavior);
}
platformBehavior.onHitboxUpdatedInTree();
}
this.movedPlatforms.length = 0;
}

/**
* Returns all the platforms around the specified object.
* @param maxMovementLength The maximum distance, in pixels, the object is going to do.
Expand All @@ -75,21 +105,19 @@ namespace gdjs {
const searchArea: SearchArea = gdjs.staticObject(
PlatformObjectsManager.prototype.getAllPlatformsAround
) as SearchArea;
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;
const nearbyPlatforms: gdjs.BehaviorRBushAABB<
PlatformRuntimeBehavior
>[] = this._platformRBush.search(searchArea);

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 &&
Expand All @@ -100,9 +128,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++;
}
}
result.length = writtenIndex;
}
}

Expand All @@ -127,6 +157,7 @@ namespace gdjs {
> | null = null;
_manager: gdjs.PlatformObjectsManager;
_registeredInManager: boolean = false;
_isAABBInvalidated = false;

constructor(
instanceContainer: gdjs.RuntimeInstanceContainer,
Expand All @@ -145,6 +176,10 @@ namespace gdjs {
this._canBeGrabbed = behaviorData.canBeGrabbed || false;
this._yGrabOffset = behaviorData.yGrabOffset || 0;
this._manager = PlatformObjectsManager.getManager(instanceContainer);
this.owner.registerHitboxChangedCallback((object) =>
this.onHitboxChanged()
);
this.onHitboxChanged();
}

updateFromBehaviorData(oldBehaviorData, newBehaviorData): boolean {
Expand All @@ -160,10 +195,12 @@ namespace gdjs {
return true;
}

onDestroy() {
if (this._manager && this._registeredInManager) {
this._manager.removePlatform(this);
}
onDestroy(): void {
this._manager.onDestroy(this);
}

usesLifecycleFunction(): boolean {
return false;
}

doStepPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {
Expand All @@ -176,54 +213,32 @@ namespace gdjs {
sceneManager = parentScene ? &ScenePlatformObjectsManager::managers[&scene] : NULL;
registeredInManager = false;
}*/

//Make sure the platform is or is not in the platforms manager.
if (!this.activated() && this._registeredInManager) {
this._manager.removePlatform(this);
this._registeredInManager = false;
} else {
if (this.activated() && !this._registeredInManager) {
this._manager.addPlatform(this);
this._registeredInManager = true;
}
}

//Track changes in size or position
if (
this._oldX !== this.owner.getX() ||
this._oldY !== this.owner.getY() ||
this._oldWidth !== this.owner.getWidth() ||
this._oldHeight !== this.owner.getHeight() ||
this._oldAngle !== this.owner.getAngle()
) {
if (this._registeredInManager) {
this._manager.removePlatform(this);
this._manager.addPlatform(this);
}
this._oldX = this.owner.getX();
this._oldY = this.owner.getY();
this._oldWidth = this.owner.getWidth();
this._oldHeight = this.owner.getHeight();
this._oldAngle = this.owner.getAngle();
}
}

doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {}

onActivate() {
if (this._registeredInManager) {
return;
}
this._manager.addPlatform(this);
this._registeredInManager = true;
this.onHitboxChanged();
}

onDeActivate() {
if (!this._registeredInManager) {
this.onHitboxChanged();
}

onHitboxChanged() {
if (this._isAABBInvalidated || !this.owner.isAlive()) {
return;
}
this._manager.removePlatform(this);
this._registeredInManager = false;
this._isAABBInvalidated = true;
this._manager.invalidatePlatformHitbox(this);
}

onHitboxUpdatedInTree() {
this._isAABBInvalidated = false;
}

isAABBInvalidated() {
return !this._isAABBInvalidated;
}

changePlatformType(platformType: string) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
const epsilon = 1 / (2 << 16);
describe('(falling)', function () {
/** @type {gdjs.RuntimeScene} */
let runtimeScene;
/** @type {gdjs.RuntimeObject} */
let object;
/** @type {gdjs.RuntimeObject} */
let platform;

beforeEach(function () {
Expand Down Expand Up @@ -114,7 +117,7 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
expect(object.getBehavior('auto1').isMoving()).to.be(false);

// Remove the platform
runtimeScene.markObjectForDeletion(platform);
platform.deleteFromScene(runtimeScene);
runtimeScene.renderAndStep(1000 / 60);
expect(object.getBehavior('auto1').isFalling()).to.be(true);
expect(object.getBehavior('auto1').isFallingWithoutJumping()).to.be(true);
Expand Down
Loading

0 comments on commit 166b31d

Please sign in to comment.