Files
GDevelop/Extensions/DestroyOutsideBehavior/destroyoutsideruntimebehavior.ts

132 lines
4.9 KiB
TypeScript

/*
GDevelop - DestroyOutside Behavior Extension
Copyright (c) 2013-2016 Florian Rival (Florian.Rival@gmail.com)
*/
namespace gdjs {
/**
* The DestroyOutsideRuntimeBehavior represents a behavior that destroys the object when it leaves the screen.
*/
export class DestroyOutsideRuntimeBehavior extends gdjs.RuntimeBehavior {
_extraBorder: float;
_unseenGraceDistance: float;
_hasBeenOnScreen: boolean;
constructor(
instanceContainer: gdjs.RuntimeInstanceContainer,
behaviorData,
owner
) {
super(instanceContainer, behaviorData, owner);
this._extraBorder = behaviorData.extraBorder || 0;
this._unseenGraceDistance = behaviorData.unseenGraceDistance || 0;
this._hasBeenOnScreen = false;
}
updateFromBehaviorData(oldBehaviorData, newBehaviorData): boolean {
if (oldBehaviorData.extraBorder !== newBehaviorData.extraBorder) {
this._extraBorder = newBehaviorData.extraBorder;
}
if (
oldBehaviorData.unseenGraceDistance !==
newBehaviorData.unseenGraceDistance
) {
this._unseenGraceDistance = newBehaviorData.unseenGraceDistance;
}
return true;
}
doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {
// TODO: This would better be done using the object AABB (getAABB), as (`getCenterX`;`getCenterY`) point
// is not necessarily in the middle of the object (for sprites for example).
const ow = this.owner.getWidth();
const oh = this.owner.getHeight();
const ocx = this.owner.getDrawableX() + this.owner.getCenterX();
const ocy = this.owner.getDrawableY() + this.owner.getCenterY();
const layer = instanceContainer.getLayer(this.owner.getLayer());
const boundingCircleRadius = Math.sqrt(ow * ow + oh * oh) / 2.0;
const cameraLeft = layer.getCameraX() - layer.getCameraWidth() / 2;
const cameraRight = layer.getCameraX() + layer.getCameraWidth() / 2;
const cameraTop = layer.getCameraY() - layer.getCameraHeight() / 2;
const cameraBottom = layer.getCameraY() + layer.getCameraHeight() / 2;
if (
ocx + boundingCircleRadius + this._extraBorder < cameraLeft ||
ocx - boundingCircleRadius - this._extraBorder > cameraRight ||
ocy + boundingCircleRadius + this._extraBorder < cameraTop ||
ocy - boundingCircleRadius - this._extraBorder > cameraBottom
) {
if (this._hasBeenOnScreen) {
// Object is outside the camera area and object was previously seen inside it:
// delete it now.
this.owner.deleteFromScene();
} else if (
ocx + boundingCircleRadius + this._unseenGraceDistance < cameraLeft ||
ocx - boundingCircleRadius - this._unseenGraceDistance >
cameraRight ||
ocy + boundingCircleRadius + this._unseenGraceDistance < cameraTop ||
ocy - boundingCircleRadius - this._unseenGraceDistance > cameraBottom
) {
// Object is outside the camera area and also outside the grace distance:
// force deletion.
this.owner.deleteFromScene();
} else {
// Object is outside the camera area but inside the grace distance
// and was never seen inside the camera area: don't delete it yet.
}
} else {
this._hasBeenOnScreen = true;
}
}
/**
* Set the additional border outside the camera area.
*
* If the object goes beyond the camera area and this border, it will be deleted (unless it was
* never seen inside the camera area and this border before, in which case it will be deleted
* according to the grace distance).
* @param val Border in pixels.
*/
setExtraBorder(val: number): void {
this._extraBorder = val;
}
/**
* Get the additional border outside the camera area.
* @return The additional border around the camera viewport in pixels
*/
getExtraBorder(): number {
return this._extraBorder;
}
/**
* Change the grace distance before an object is deleted if it's outside the camera area
* and was never seen inside the camera area. Typically useful to avoid objects being deleted
* before they are visible when they spawn.
*/
setUnseenGraceDistance(val: number): void {
this._unseenGraceDistance = val;
}
/**
* Get the grace distance before an object is deleted if it's outside the camera area
* and was never seen inside the camera area.
*/
getUnseenGraceDistance(): number {
return this._unseenGraceDistance;
}
/**
* Check if this object has been visible on screen (precisely: inside the camera area *including* the extra border).
*/
hasBeenOnScreen(): boolean {
return this._hasBeenOnScreen;
}
}
gdjs.registerBehavior(
'DestroyOutsideBehavior::DestroyOutside',
gdjs.DestroyOutsideRuntimeBehavior
);
}