mirror of
https://github.com/Heretek-AI/GDevelop.git
synced 2026-07-21 17:45:25 -04:00
deb802cfec
* For now, this is limited to instances inside custom objects. This will be made available in the future for all instances in scenes if this works well.
218 lines
6.6 KiB
TypeScript
218 lines
6.6 KiB
TypeScript
/*
|
|
GDevelop - Pathfinding Behavior Extension
|
|
Copyright (c) 2013-2016 Florian Rival (Florian.Rival@gmail.com)
|
|
*/
|
|
|
|
namespace gdjs {
|
|
export interface RuntimeInstanceContainer {
|
|
pathfindingObstaclesManager: gdjs.PathfindingObstaclesManager;
|
|
}
|
|
declare var rbush: any;
|
|
|
|
/**
|
|
* PathfindingObstaclesManager manages the common objects shared by objects
|
|
* having a pathfinding behavior: In particular, the obstacles behaviors are
|
|
* required to declare themselves (see
|
|
* `PathfindingObstaclesManager.addObstacle`) to the manager of their
|
|
* associated container (see
|
|
* `gdjs.PathfindingRuntimeBehavior.obstaclesManagers`).
|
|
* @category Behaviors > 2D Pathfinding
|
|
*/
|
|
export class PathfindingObstaclesManager {
|
|
_obstaclesRBush: any;
|
|
|
|
constructor(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
|
this._obstaclesRBush = new rbush();
|
|
}
|
|
|
|
/**
|
|
* Get the obstacles manager of an instance container.
|
|
*/
|
|
static getManager(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
|
if (!instanceContainer.pathfindingObstaclesManager) {
|
|
//Create the shared manager if necessary.
|
|
instanceContainer.pathfindingObstaclesManager =
|
|
new gdjs.PathfindingObstaclesManager(instanceContainer);
|
|
}
|
|
return instanceContainer.pathfindingObstaclesManager;
|
|
}
|
|
|
|
/**
|
|
* Add a obstacle to the list of existing obstacles.
|
|
*/
|
|
addObstacle(
|
|
pathfindingObstacleBehavior: PathfindingObstacleRuntimeBehavior
|
|
) {
|
|
if (pathfindingObstacleBehavior.currentRBushAABB)
|
|
pathfindingObstacleBehavior.currentRBushAABB.updateAABBFromOwner();
|
|
else
|
|
pathfindingObstacleBehavior.currentRBushAABB =
|
|
new gdjs.BehaviorRBushAABB(pathfindingObstacleBehavior);
|
|
|
|
this._obstaclesRBush.insert(pathfindingObstacleBehavior.currentRBushAABB);
|
|
}
|
|
|
|
/**
|
|
* Remove a obstacle from the list of existing obstacles. Be sure that the obstacle was
|
|
* added before.
|
|
*/
|
|
removeObstacle(
|
|
pathfindingObstacleBehavior: PathfindingObstacleRuntimeBehavior
|
|
) {
|
|
this._obstaclesRBush.remove(pathfindingObstacleBehavior.currentRBushAABB);
|
|
}
|
|
|
|
/**
|
|
* Returns all the platforms around the specified object.
|
|
* @param x The center X of the area to search.
|
|
* @param y The center Y of the area to search.
|
|
* @param radius The maximum distance, in pixels, the object is going to do.
|
|
* @param result An array returned with all platforms near the object.
|
|
*/
|
|
getAllObstaclesAround(
|
|
x: float,
|
|
y: float,
|
|
radius: float,
|
|
result: gdjs.PathfindingObstacleRuntimeBehavior[]
|
|
): void {
|
|
const searchArea = gdjs.staticObject(
|
|
PathfindingObstaclesManager.prototype.getAllObstaclesAround
|
|
);
|
|
// @ts-ignore
|
|
searchArea.minX = x - radius;
|
|
// @ts-ignore
|
|
searchArea.minY = y - radius;
|
|
// @ts-ignore
|
|
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)
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* PathfindingObstacleRuntimeBehavior represents a behavior allowing objects to be
|
|
* considered as a obstacle by objects having Pathfinding Behavior.
|
|
* @category Behaviors > 2D Pathfinding
|
|
*/
|
|
export class PathfindingObstacleRuntimeBehavior extends gdjs.RuntimeBehavior {
|
|
_impassable: boolean;
|
|
_cost: float;
|
|
_oldX: float = 0;
|
|
_oldY: float = 0;
|
|
_oldWidth: float = 0;
|
|
_oldHeight: float = 0;
|
|
_manager: PathfindingObstaclesManager;
|
|
_registeredInManager: boolean = false;
|
|
currentRBushAABB: gdjs.BehaviorRBushAABB<PathfindingObstacleRuntimeBehavior> | null =
|
|
null;
|
|
|
|
constructor(
|
|
instanceContainer: gdjs.RuntimeInstanceContainer,
|
|
behaviorData,
|
|
owner: gdjs.RuntimeObject
|
|
) {
|
|
super(instanceContainer, behaviorData, owner);
|
|
this._impassable = behaviorData.impassable;
|
|
this._cost = behaviorData.cost;
|
|
this._manager = PathfindingObstaclesManager.getManager(instanceContainer);
|
|
|
|
//Note that we can't use getX(), getWidth()... of owner here:
|
|
//The owner is not yet fully constructed.
|
|
}
|
|
|
|
override applyBehaviorOverriding(behaviorData): boolean {
|
|
if (behaviorData.impassable !== undefined) {
|
|
this.setImpassable(behaviorData.impassable);
|
|
}
|
|
if (behaviorData.cost !== undefined) {
|
|
this.setCost(behaviorData.cost);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
onDestroy() {
|
|
if (this._manager && this._registeredInManager) {
|
|
this._manager.removeObstacle(this);
|
|
}
|
|
}
|
|
|
|
doStepPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
|
//Make sure the obstacle is or is not in the obstacles manager.
|
|
if (!this.activated() && this._registeredInManager) {
|
|
this._manager.removeObstacle(this);
|
|
this._registeredInManager = false;
|
|
} else {
|
|
if (this.activated() && !this._registeredInManager) {
|
|
this._manager.addObstacle(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()
|
|
) {
|
|
if (this._registeredInManager) {
|
|
this._manager.removeObstacle(this);
|
|
this._manager.addObstacle(this);
|
|
}
|
|
this._oldX = this.owner.getX();
|
|
this._oldY = this.owner.getY();
|
|
this._oldWidth = this.owner.getWidth();
|
|
this._oldHeight = this.owner.getHeight();
|
|
}
|
|
}
|
|
|
|
doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {}
|
|
|
|
getAABB() {
|
|
return this.owner.getAABB();
|
|
}
|
|
|
|
onActivate() {
|
|
if (this._registeredInManager) {
|
|
return;
|
|
}
|
|
this._manager.addObstacle(this);
|
|
this._registeredInManager = true;
|
|
}
|
|
|
|
onDeActivate() {
|
|
if (!this._registeredInManager) {
|
|
return;
|
|
}
|
|
this._manager.removeObstacle(this);
|
|
this._registeredInManager = false;
|
|
}
|
|
|
|
getCost() {
|
|
return this._cost;
|
|
}
|
|
|
|
setCost(cost: float): void {
|
|
this._cost = cost;
|
|
}
|
|
|
|
isImpassable(): boolean {
|
|
return this._impassable;
|
|
}
|
|
|
|
setImpassable(impassable: boolean): void {
|
|
this._impassable = impassable;
|
|
}
|
|
}
|
|
gdjs.registerBehavior(
|
|
'PathfindingBehavior::PathfindingObstacleBehavior',
|
|
gdjs.PathfindingObstacleRuntimeBehavior
|
|
);
|
|
}
|