gdcore-tools 2.0.0-gd-v5.5.230-autobuild → 2.0.0-gd-v5.5.232-autobuild

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist/Runtime/CustomRuntimeObject.js +1 -1
  2. package/dist/Runtime/CustomRuntimeObject.js.map +2 -2
  3. package/dist/Runtime/CustomRuntimeObject2D.js +1 -1
  4. package/dist/Runtime/CustomRuntimeObject2D.js.map +2 -2
  5. package/dist/Runtime/CustomRuntimeObjectInstanceContainer.js +1 -1
  6. package/dist/Runtime/CustomRuntimeObjectInstanceContainer.js.map +2 -2
  7. package/dist/Runtime/Extensions/3D/CustomRuntimeObject3D.js +1 -1
  8. package/dist/Runtime/Extensions/3D/CustomRuntimeObject3D.js.map +2 -2
  9. package/dist/Runtime/Extensions/3D/CustomRuntimeObject3DRenderer.js +1 -1
  10. package/dist/Runtime/Extensions/3D/CustomRuntimeObject3DRenderer.js.map +2 -2
  11. package/dist/Runtime/Extensions/3D/JsExtension.js +6 -2
  12. package/dist/Runtime/Extensions/DestroyOutsideBehavior/destroyoutsideruntimebehavior.js +1 -1
  13. package/dist/Runtime/Extensions/DestroyOutsideBehavior/destroyoutsideruntimebehavior.js.map +2 -2
  14. package/dist/Runtime/Extensions/Multiplayer/messageManager.js +1 -1
  15. package/dist/Runtime/Extensions/Multiplayer/messageManager.js.map +2 -2
  16. package/dist/Runtime/Extensions/Multiplayer/multiplayerobjectruntimebehavior.js +1 -1
  17. package/dist/Runtime/Extensions/Multiplayer/multiplayerobjectruntimebehavior.js.map +2 -2
  18. package/dist/Runtime/Extensions/PanelSpriteObject/panelspriteruntimeobject-pixi-renderer.js +1 -1
  19. package/dist/Runtime/Extensions/PanelSpriteObject/panelspriteruntimeobject-pixi-renderer.js.map +2 -2
  20. package/dist/Runtime/Extensions/ParticleSystem/particleemitterobject.js +1 -1
  21. package/dist/Runtime/Extensions/ParticleSystem/particleemitterobject.js.map +2 -2
  22. package/dist/Runtime/Extensions/Physics3DBehavior/JsExtension.js +1047 -3
  23. package/dist/Runtime/Extensions/Physics3DBehavior/Physics3DRuntimeBehavior.js +1 -1
  24. package/dist/Runtime/Extensions/Physics3DBehavior/Physics3DRuntimeBehavior.js.map +2 -2
  25. package/dist/Runtime/Extensions/Physics3DBehavior/PhysicsCar3DRuntimeBehavior.js +2 -0
  26. package/dist/Runtime/Extensions/Physics3DBehavior/PhysicsCar3DRuntimeBehavior.js.map +7 -0
  27. package/dist/Runtime/Extensions/Physics3DBehavior/PhysicsCharacter3DRuntimeBehavior.js +1 -1
  28. package/dist/Runtime/Extensions/Physics3DBehavior/PhysicsCharacter3DRuntimeBehavior.js.map +2 -2
  29. package/dist/Runtime/Extensions/Physics3DBehavior/jolt-physics.d.ts +94 -9
  30. package/dist/Runtime/Extensions/Physics3DBehavior/jolt-physics.wasm.js +1 -1
  31. package/dist/Runtime/Extensions/Physics3DBehavior/jolt-physics.wasm.js.map +2 -2
  32. package/dist/Runtime/Extensions/Physics3DBehavior/jolt-physics.wasm.wasm +0 -0
  33. package/dist/Runtime/Extensions/PlatformBehavior/platformerobjectruntimebehavior.js +1 -1
  34. package/dist/Runtime/Extensions/PlatformBehavior/platformerobjectruntimebehavior.js.map +2 -2
  35. package/dist/Runtime/Extensions/TopDownMovementBehavior/topdownmovementruntimebehavior.js +1 -1
  36. package/dist/Runtime/Extensions/TopDownMovementBehavior/topdownmovementruntimebehavior.js.map +2 -2
  37. package/dist/Runtime/Extensions/TweenBehavior/JsExtension.js +1 -1
  38. package/dist/Runtime/Extensions/TweenBehavior/tweenruntimebehavior.js +1 -1
  39. package/dist/Runtime/Extensions/TweenBehavior/tweenruntimebehavior.js.map +2 -2
  40. package/dist/Runtime/RuntimeInstanceContainer.js +1 -1
  41. package/dist/Runtime/RuntimeInstanceContainer.js.map +2 -2
  42. package/dist/Runtime/debugger-client/hot-reloader.js +3 -2
  43. package/dist/Runtime/debugger-client/hot-reloader.js.map +2 -2
  44. package/dist/Runtime/events-tools/cameratools.js +1 -1
  45. package/dist/Runtime/events-tools/cameratools.js.map +2 -2
  46. package/dist/Runtime/howler-sound-manager/howler-sound-manager.js +1 -1
  47. package/dist/Runtime/howler-sound-manager/howler-sound-manager.js.map +2 -2
  48. package/dist/Runtime/pixi-renderers/CustomRuntimeObject2DPixiRenderer.js +1 -1
  49. package/dist/Runtime/pixi-renderers/CustomRuntimeObject2DPixiRenderer.js.map +2 -2
  50. package/dist/Runtime/runtimeobject.js +1 -1
  51. package/dist/Runtime/runtimeobject.js.map +2 -2
  52. package/dist/Runtime/runtimescene.js +1 -1
  53. package/dist/Runtime/runtimescene.js.map +2 -2
  54. package/dist/Runtime/spriteruntimeobject.js +1 -1
  55. package/dist/Runtime/spriteruntimeobject.js.map +2 -2
  56. package/dist/Runtime/types/project-data.d.ts +1 -1
  57. package/dist/lib/libGD.cjs +1 -1
  58. package/dist/lib/libGD.wasm +0 -0
  59. package/dist/loaders.cjs +3 -3
  60. package/gd.d.ts +7 -0
  61. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../GDevelop/Extensions/PlatformBehavior/platformerobjectruntimebehavior.ts"],
4
- "sourcesContent": ["/*\nGDevelop - Platform Behavior Extension\nCopyright (c) 2013-2016 Florian Rival (Florian.Rival@gmail.com)\n */\nnamespace gdjs {\n /**\n * Returned by _findHighestFloorAndMoveOnTop\n */\n type PlatformSearchResult = {\n highestGroundPlatform: gdjs.PlatformRuntimeBehavior | null;\n highestGroundPolygon: gdjs.Polygon | null;\n isCollidingAnyPlatform: boolean;\n };\n\n interface OnFloorStateNetworkSyncData {\n flx: number;\n fly: number;\n oh: number;\n }\n\n interface FallingStateNetworkSyncData {}\n\n interface JumpingStateNetworkSyncData {\n cjs: number;\n tscjs: number;\n jkhsjs: boolean;\n jfd: boolean;\n }\n\n interface GrabbingPlatformStateNetworkSyncData {\n gplx: float;\n gply: float;\n }\n\n interface OnLadderStateNetworkSyncData {}\n\n type StateNetworkSyncData =\n | OnFloorStateNetworkSyncData\n | FallingStateNetworkSyncData\n | JumpingStateNetworkSyncData\n | GrabbingPlatformStateNetworkSyncData\n | OnLadderStateNetworkSyncData;\n\n interface PlatformerObjectNetworkSyncDataType {\n cs: float;\n rdx: float;\n rdy: float;\n ldy: float;\n cfs: float;\n cj: boolean;\n ldl: boolean;\n lek: boolean;\n rik: boolean;\n lak: boolean;\n upk: boolean;\n dok: boolean;\n juk: boolean;\n rpk: boolean;\n rlk: boolean;\n sn: string;\n ssd: StateNetworkSyncData;\n }\n\n export interface PlatformerObjectNetworkSyncData\n extends BehaviorNetworkSyncData {\n props: PlatformerObjectNetworkSyncDataType;\n }\n\n /**\n * PlatformerObjectRuntimeBehavior represents a behavior allowing objects to be\n * considered as a platform by objects having PlatformerObject Behavior.\n */\n export class PlatformerObjectRuntimeBehavior extends gdjs.RuntimeBehavior {\n /**\n * Returned by _findHighestFloorAndMoveOnTop\n */\n private static readonly _platformSearchResult: PlatformSearchResult = {\n highestGroundPlatform: null,\n highestGroundPolygon: null,\n isCollidingAnyPlatform: false,\n };\n\n /**\n * A very small value compare to 1 pixel, yet very huge compare to rounding errors.\n */\n private static readonly epsilon = 2 ** -20;\n\n // Behavior configuration\n\n /** To achieve pixel-perfect precision when positioning object on platform or\n * handling collision with \"walls\", edges of the hitboxes must be ignored during\n * collision checks, so that two overlapping edges are not considered as colliding.\n *\n * For example, if a character is 10px width and is at position (0, 0), it must not be\n * considered as colliding with a platform which is at position (10, 0). Edges will\n * still be overlapping (because character hitbox right edge is at X position 10 and\n * platform hitbox left edge is also at X position 10).\n *\n * This parameter \"_ignoreTouchingEdges\" will be passed to all collision handling functions.\n */\n _ignoreTouchingEdges: boolean = true;\n\n private _acceleration: float;\n private _deceleration: float;\n private _maxSpeed: float;\n private _slopeMaxAngle: float;\n _slopeClimbingFactor: float = 1;\n\n _gravity: float;\n _maxFallingSpeed: float;\n _jumpSpeed: float;\n _jumpSustainTime: float;\n\n _ladderClimbingSpeed: float;\n\n _canGrabPlatforms: boolean;\n _canGrabWithoutMoving: boolean;\n private _yGrabOffset: any;\n private _xGrabTolerance: any;\n\n _useLegacyTrajectory: boolean;\n\n _canGoDownFromJumpthru: boolean = false;\n\n // Behavior state\n\n _currentSpeed: float = 0;\n _requestedDeltaX: float = 0;\n _requestedDeltaY: float = 0;\n _lastDeltaY: float = 0;\n _currentFallSpeed: float = 0;\n _canJump: boolean = false;\n _lastDirectionIsLeft: boolean = false;\n\n private _ignoreDefaultControls: boolean;\n private _leftKey: boolean = false;\n private _rightKey: boolean = false;\n private _ladderKey: boolean = false;\n _upKey: boolean = false;\n _downKey: boolean = false;\n _jumpKey: boolean = false;\n _releasePlatformKey: boolean = false;\n _releaseLadderKey: boolean = false;\n\n // This is useful when the object is synchronized by an external source\n // like in a multiplayer game, and we want to be able to predict the\n // movement of the object, even if the inputs are not updated every frame.\n _dontClearInputsBetweenFrames: boolean = false;\n // This is useful when the object is synchronized over the network,\n // object is controlled by the network and we want to ensure the current player\n // cannot control it.\n _ignoreDefaultControlsAsSyncedByNetwork: boolean = false;\n\n // This is useful for extensions that need to know\n // which keys were pressed and doesn't know the mapping\n // done by the scene events.\n private _wasLeftKeyPressed: boolean = false;\n private _wasRightKeyPressed: boolean = false;\n private _wasLadderKeyPressed: boolean = false;\n private _wasUpKeyPressed: boolean = false;\n private _wasDownKeyPressed: boolean = false;\n private _wasJumpKeyPressed: boolean = false;\n private _wasReleasePlatformKeyPressed: boolean = false;\n private _wasReleaseLadderKeyPressed: boolean = false;\n\n private _state: State;\n _falling: Falling;\n _onFloor: OnFloor;\n _jumping: Jumping;\n _grabbingPlatform: GrabbingPlatform;\n _onLadder: OnLadder;\n\n /** Platforms near the object, updated with `_updatePotentialCollidingObjects`. */\n _potentialCollidingObjects: Array<gdjs.PlatformRuntimeBehavior>;\n\n /** Overlapped jump-thru platforms, updated with `_updateOverlappedJumpThru`. */\n _overlappedJumpThru: Array<gdjs.PlatformRuntimeBehavior>;\n\n private _hasReallyMoved: boolean = false;\n /** @deprecated use _hasReallyMoved instead */\n private _hasMovedAtLeastOnePixel: boolean = false;\n private _manager: gdjs.PlatformObjectsManager;\n\n constructor(\n instanceContainer: gdjs.RuntimeInstanceContainer,\n behaviorData,\n owner: gdjs.RuntimeObject\n ) {\n super(instanceContainer, behaviorData, owner);\n this._gravity = behaviorData.gravity;\n this._maxFallingSpeed = behaviorData.maxFallingSpeed;\n this._ladderClimbingSpeed = behaviorData.ladderClimbingSpeed || 150;\n this._acceleration = behaviorData.acceleration;\n this._deceleration = behaviorData.deceleration;\n this._maxSpeed = behaviorData.maxSpeed;\n this._jumpSpeed = behaviorData.jumpSpeed;\n this._canGrabPlatforms = behaviorData.canGrabPlatforms || false;\n this._canGrabWithoutMoving = behaviorData.canGrabWithoutMoving;\n this._yGrabOffset = behaviorData.yGrabOffset || 0;\n this._xGrabTolerance = behaviorData.xGrabTolerance || 10;\n this._jumpSustainTime = behaviorData.jumpSustainTime || 0;\n this._ignoreDefaultControls = behaviorData.ignoreDefaultControls;\n this._useLegacyTrajectory =\n behaviorData.useLegacyTrajectory === undefined\n ? true\n : behaviorData.useLegacyTrajectory;\n this._canGoDownFromJumpthru = behaviorData.canGoDownFromJumpthru;\n this._slopeMaxAngle = 0;\n this.setSlopeMaxAngle(behaviorData.slopeMaxAngle);\n\n this._potentialCollidingObjects = [];\n this._overlappedJumpThru = [];\n\n this._manager = gdjs.PlatformObjectsManager.getManager(instanceContainer);\n\n this._falling = new Falling(this);\n this._onFloor = new OnFloor(this);\n this._jumping = new Jumping(this);\n this._grabbingPlatform = new GrabbingPlatform(this);\n this._onLadder = new OnLadder(this);\n this._state = this._falling;\n }\n\n getNetworkSyncData(): PlatformerObjectNetworkSyncData {\n // This method is called, so we are synchronizing this object.\n // Let's clear the inputs between frames as we control it.\n this._dontClearInputsBetweenFrames = false;\n this._ignoreDefaultControlsAsSyncedByNetwork = false;\n\n return {\n ...super.getNetworkSyncData(),\n props: {\n cs: this._currentSpeed,\n\n // TODO Try to remove these 3 fields from the synch\n // They are reset every frame and are not part of the state.\n rdx: this._requestedDeltaX,\n rdy: this._requestedDeltaY,\n ldy: this._lastDeltaY,\n\n cfs: this._currentFallSpeed,\n cj: this._canJump,\n ldl: this._lastDirectionIsLeft,\n lek: this._wasLeftKeyPressed,\n rik: this._wasRightKeyPressed,\n lak: this._wasLadderKeyPressed,\n upk: this._wasUpKeyPressed,\n dok: this._wasDownKeyPressed,\n juk: this._wasJumpKeyPressed,\n rpk: this._wasReleasePlatformKeyPressed,\n rlk: this._wasReleaseLadderKeyPressed,\n sn: this._state.toString(),\n ssd: this._state.getNetworkSyncData(),\n },\n };\n }\n\n updateFromNetworkSyncData(\n networkSyncData: PlatformerObjectNetworkSyncData\n ) {\n super.updateFromNetworkSyncData(networkSyncData);\n\n const behaviorSpecificProps = networkSyncData.props;\n if (behaviorSpecificProps.cs !== this._currentSpeed) {\n this._currentSpeed = behaviorSpecificProps.cs;\n }\n if (behaviorSpecificProps.rdx !== this._requestedDeltaX) {\n this._requestedDeltaX = behaviorSpecificProps.rdx;\n }\n if (behaviorSpecificProps.rdy !== this._requestedDeltaY) {\n this._requestedDeltaY = behaviorSpecificProps.rdy;\n }\n if (behaviorSpecificProps.ldy !== this._lastDeltaY) {\n this._lastDeltaY = behaviorSpecificProps.ldy;\n }\n if (behaviorSpecificProps.cfs !== this._currentFallSpeed) {\n this._currentFallSpeed = behaviorSpecificProps.cfs;\n }\n if (behaviorSpecificProps.cj !== this._canJump) {\n this._canJump = behaviorSpecificProps.cj;\n }\n if (behaviorSpecificProps.ldl !== this._lastDirectionIsLeft) {\n this._lastDirectionIsLeft = behaviorSpecificProps.ldl;\n }\n if (behaviorSpecificProps.lek !== this._leftKey) {\n this._leftKey = behaviorSpecificProps.lek;\n }\n if (behaviorSpecificProps.rik !== this._rightKey) {\n this._rightKey = behaviorSpecificProps.rik;\n }\n if (behaviorSpecificProps.lak !== this._ladderKey) {\n this._ladderKey = behaviorSpecificProps.lak;\n }\n if (behaviorSpecificProps.upk !== this._upKey) {\n this._upKey = behaviorSpecificProps.upk;\n }\n if (behaviorSpecificProps.dok !== this._downKey) {\n this._downKey = behaviorSpecificProps.dok;\n }\n if (behaviorSpecificProps.juk !== this._jumpKey) {\n this._jumpKey = behaviorSpecificProps.juk;\n }\n if (behaviorSpecificProps.rpk !== this._releasePlatformKey) {\n this._releasePlatformKey = behaviorSpecificProps.rpk;\n }\n if (behaviorSpecificProps.rlk !== this._releaseLadderKey) {\n this._releaseLadderKey = behaviorSpecificProps.rlk;\n }\n\n if (behaviorSpecificProps.sn !== this._state.toString()) {\n switch (behaviorSpecificProps.sn) {\n case 'Falling':\n this._setFalling();\n break;\n case 'OnFloor':\n // Let it handle automatically as we don't know which platform to land on.\n break;\n case 'Jumping':\n this._setJumping();\n break;\n case 'GrabbingPlatform':\n // Let it handle automatically as we don't know which platform to grab.\n break;\n case 'OnLadder':\n this._setOnLadder();\n break;\n default:\n console.error(\n 'Unknown state name: ' + behaviorSpecificProps.sn + '.'\n );\n break;\n }\n }\n\n if (behaviorSpecificProps.sn === this._state.toString()) {\n this._state.updateFromNetworkSyncData(behaviorSpecificProps.ssd);\n }\n\n // When the object is synchronized from the network, the inputs must not be cleared.\n this._dontClearInputsBetweenFrames = true;\n // And we are not using the default controls.\n this._ignoreDefaultControlsAsSyncedByNetwork = true;\n }\n\n updateFromBehaviorData(oldBehaviorData, newBehaviorData): boolean {\n if (oldBehaviorData.gravity !== newBehaviorData.gravity) {\n this.setGravity(newBehaviorData.gravity);\n }\n if (oldBehaviorData.maxFallingSpeed !== newBehaviorData.maxFallingSpeed) {\n this.setMaxFallingSpeed(newBehaviorData.maxFallingSpeed);\n }\n if (oldBehaviorData.acceleration !== newBehaviorData.acceleration) {\n this.setAcceleration(newBehaviorData.acceleration);\n }\n if (oldBehaviorData.deceleration !== newBehaviorData.deceleration) {\n this.setDeceleration(newBehaviorData.deceleration);\n }\n if (oldBehaviorData.maxSpeed !== newBehaviorData.maxSpeed) {\n this.setMaxSpeed(newBehaviorData.maxSpeed);\n }\n if (oldBehaviorData.jumpSpeed !== newBehaviorData.jumpSpeed) {\n this.setJumpSpeed(newBehaviorData.jumpSpeed);\n }\n if (\n oldBehaviorData.canGrabPlatforms !== newBehaviorData.canGrabPlatforms\n ) {\n this.setCanGrabPlatforms(newBehaviorData.canGrabPlatforms);\n }\n if (\n oldBehaviorData.canGrabWithoutMoving !==\n newBehaviorData.canGrabWithoutMoving\n ) {\n this._canGrabWithoutMoving = newBehaviorData.canGrabWithoutMoving;\n }\n if (oldBehaviorData.yGrabOffset !== newBehaviorData.yGrabOffset) {\n this._yGrabOffset = newBehaviorData.yGrabOffset;\n }\n if (oldBehaviorData.xGrabTolerance !== newBehaviorData.xGrabTolerance) {\n this._xGrabTolerance = newBehaviorData.xGrabTolerance;\n }\n if (oldBehaviorData.jumpSustainTime !== newBehaviorData.jumpSustainTime) {\n this.setJumpSustainTime(newBehaviorData.jumpSustainTime);\n }\n if (\n oldBehaviorData.useLegacyTrajectory !==\n newBehaviorData.useLegacyTrajectory\n ) {\n this._useLegacyTrajectory = newBehaviorData.useLegacyTrajectory;\n }\n if (\n oldBehaviorData.canGoDownFromJumpthru !==\n newBehaviorData.canGoDownFromJumpthru\n ) {\n this._canGoDownFromJumpthru = newBehaviorData.canGoDownFromJumpthru;\n }\n return true;\n }\n\n doStepPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {\n const LEFTKEY = 37;\n const UPKEY = 38;\n const RIGHTKEY = 39;\n const DOWNKEY = 40;\n const LSHIFTKEY = 1016;\n const RSHIFTKEY = 2016;\n const SPACEKEY = 32;\n const object = this.owner;\n const timeDelta = this.owner.getElapsedTime() / 1000;\n\n //0.1) Get the player input:\n this._requestedDeltaX = 0;\n this._requestedDeltaY = 0;\n\n const inputManager = instanceContainer.getGame().getInputManager();\n this._leftKey ||\n (this._leftKey =\n !this.shouldIgnoreDefaultControls() &&\n inputManager.isKeyPressed(LEFTKEY));\n this._rightKey ||\n (this._rightKey =\n !this.shouldIgnoreDefaultControls() &&\n inputManager.isKeyPressed(RIGHTKEY));\n\n this._jumpKey ||\n (this._jumpKey =\n !this.shouldIgnoreDefaultControls() &&\n (inputManager.isKeyPressed(LSHIFTKEY) ||\n inputManager.isKeyPressed(RSHIFTKEY) ||\n inputManager.isKeyPressed(SPACEKEY)));\n\n this._ladderKey ||\n (this._ladderKey =\n !this.shouldIgnoreDefaultControls() &&\n inputManager.isKeyPressed(UPKEY));\n\n this._upKey ||\n (this._upKey =\n !this.shouldIgnoreDefaultControls() &&\n inputManager.isKeyPressed(UPKEY));\n this._downKey ||\n (this._downKey =\n !this.shouldIgnoreDefaultControls() &&\n inputManager.isKeyPressed(DOWNKEY));\n\n this._releasePlatformKey ||\n (this._releasePlatformKey =\n !this.shouldIgnoreDefaultControls() &&\n inputManager.isKeyPressed(DOWNKEY));\n\n this._requestedDeltaX += this._updateSpeed(timeDelta);\n\n if (this._leftKey !== this._rightKey) {\n this._lastDirectionIsLeft = this._leftKey;\n }\n\n //0.2) Track changes in object size\n this._state.beforeUpdatingObstacles(timeDelta);\n this._onFloor._oldHeight = object.getHeight();\n\n //0.3) Update list of platforms around/related to the object\n\n //Compute the list of the objects that will be used\n this._updatePotentialCollidingObjects(\n Math.max(this._requestedDeltaX, this._maxFallingSpeed * timeDelta)\n );\n this._updateOverlappedJumpThru();\n\n //1) X axis:\n const beforeMovingXState = this._state;\n this._state.checkTransitionBeforeX();\n this._state.beforeMovingX();\n\n //Ensure the object is not stuck\n if (this._separateFromPlatforms(this._potentialCollidingObjects, true)) {\n //After being unstuck, the object must be able to jump again.\n this._canJump = true;\n }\n\n const oldX = object.getX();\n this._moveX();\n const mayCollideWall = object.getX() !== oldX + this._requestedDeltaX;\n\n //2) Y axis:\n const beforeMovingYState = this._state;\n this._state.checkTransitionBeforeY(timeDelta);\n this._state.beforeMovingY(timeDelta, oldX);\n\n const oldY = object.getY();\n this._moveY();\n\n //3) Update the current floor data for the next tick:\n const beforeLastTransitionYState = this._state;\n //TODO what about a moving platforms, remove this condition to do the same as for grabbing?\n if (this._state !== this._onLadder) {\n this._checkTransitionOnFloorOrFalling();\n }\n\n if (\n // When the character is against a wall and the player hold left or\n // right, the speed shouldn't stack because starting at full speed when\n // jumping over the wall would look strange.\n mayCollideWall &&\n // Whereas, when the state has change, the collision is probably a\n // landing or a collision from the floor when stating to jump. The\n // speed must not be lost in these cases.\n this._state === beforeMovingXState &&\n this._state === beforeMovingYState &&\n this._state === beforeLastTransitionYState &&\n // When the character is on the floor, it will try to walk on the\n // obstacles and already stop if necessary.\n this._state !== this._onFloor\n ) {\n this._currentSpeed = 0;\n }\n\n this._wasLeftKeyPressed = this._leftKey;\n this._wasRightKeyPressed = this._rightKey;\n this._wasLadderKeyPressed = this._ladderKey;\n this._wasUpKeyPressed = this._upKey;\n this._wasDownKeyPressed = this._downKey;\n this._wasJumpKeyPressed = this._jumpKey;\n this._wasReleasePlatformKeyPressed = this._releasePlatformKey;\n this._wasReleaseLadderKeyPressed = this._releaseLadderKey;\n //4) Do not forget to reset pressed keys\n if (!this._dontClearInputsBetweenFrames) {\n // Reset the keys only if the inputs are not supposed to survive between frames.\n // (Most of the time, except if this object is synchronized by an external source)\n this._leftKey = false;\n this._rightKey = false;\n this._ladderKey = false;\n this._upKey = false;\n this._downKey = false;\n this._jumpKey = false;\n this._releasePlatformKey = false;\n this._releaseLadderKey = false;\n }\n\n //5) Track the movement\n this._hasReallyMoved =\n Math.abs(object.getX() - oldX) >\n PlatformerObjectRuntimeBehavior.epsilon ||\n Math.abs(object.getY() - oldY) >\n PlatformerObjectRuntimeBehavior.epsilon;\n this._hasMovedAtLeastOnePixel =\n Math.abs(object.getX() - oldX) >= 1 ||\n Math.abs(object.getY() - oldY) >= 1;\n this._lastDeltaY = object.getY() - oldY;\n }\n\n doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {}\n\n private _updateSpeed(timeDelta: float): float {\n const previousSpeed = this._currentSpeed;\n // Change the speed according to the player's input.\n // TODO Give priority to the last key for faster reaction time.\n if (this._leftKey !== this._rightKey) {\n if (this._leftKey) {\n if (this._currentSpeed <= 0) {\n this._currentSpeed -= this._acceleration * timeDelta;\n } else {\n // Turn back at least as fast as it would stop.\n this._currentSpeed -=\n Math.max(this._acceleration, this._deceleration) * timeDelta;\n }\n } else if (this._rightKey) {\n if (this._currentSpeed >= 0) {\n this._currentSpeed += this._acceleration * timeDelta;\n } else {\n this._currentSpeed +=\n Math.max(this._acceleration, this._deceleration) * timeDelta;\n }\n }\n }\n\n //Take deceleration into account only if no key is pressed.\n if (this._leftKey === this._rightKey) {\n const wasPositive = this._currentSpeed > 0;\n this._currentSpeed -=\n this._deceleration * timeDelta * (wasPositive ? 1.0 : -1.0);\n\n //Set the speed to 0 if the speed was too low.\n if (wasPositive && this._currentSpeed < 0) {\n this._currentSpeed = 0;\n }\n if (!wasPositive && this._currentSpeed > 0) {\n this._currentSpeed = 0;\n }\n }\n if (this._currentSpeed > this._maxSpeed) {\n this._currentSpeed = this._maxSpeed;\n }\n if (this._currentSpeed < -this._maxSpeed) {\n this._currentSpeed = -this._maxSpeed;\n }\n // Use Verlet integration.\n return ((this._currentSpeed + previousSpeed) * timeDelta) / 2;\n }\n\n /**\n * Also see {@link ./README.md}\n */\n private _moveX() {\n const object = this.owner;\n //Move the object on x axis.\n const oldX = object.getX();\n if (this._requestedDeltaX !== 0) {\n let floorPlatformId =\n this._onFloor.getFloorPlatform() !== null\n ? this._onFloor.getFloorPlatform()!.owner.id\n : null;\n object.setX(object.getX() + this._requestedDeltaX);\n let tryRounding = true;\n\n //Colliding: Try to push out from the solid.\n //Note that jump thru are never obstacle on X axis.\n while (\n this._isCollidingWithOneOf(\n this._potentialCollidingObjects,\n floorPlatformId,\n /*excludeJumpthrus=*/\n true,\n this._onFloor.getFloorPolygon()\n )\n ) {\n if (\n (this._requestedDeltaX > 0 && object.getX() <= oldX) ||\n (this._requestedDeltaX < 0 && object.getX() >= oldX)\n ) {\n object.setX(\n //Unable to move the object without being stuck in an obstacle.\n oldX\n );\n break;\n }\n if (tryRounding) {\n // First try rounding the position as this might be sufficient to get the object\n // out of the wall.\n object.setX(Math.round(object.getX()));\n tryRounding = false;\n } else {\n object.setX(\n Math.round(object.getX()) + (this._requestedDeltaX > 0 ? -1 : 1)\n );\n }\n }\n }\n }\n\n private _moveY() {\n const object = this.owner;\n //Move the object on Y axis\n if (this._requestedDeltaY !== 0) {\n if (this._requestedDeltaY > 0) {\n // Use the same method as for following the floor.\n // This is to be consistent on all floor collision.\n // The object will land right on floor.\n\n const { highestGroundPlatform } = this._findHighestFloorAndMoveOnTop(\n this._potentialCollidingObjects,\n 0,\n this._requestedDeltaY\n );\n if (!highestGroundPlatform) {\n object.setY(object.getY() + this._requestedDeltaY);\n }\n } else {\n // The same logic could be applied going up one day.\n let oldY = object.getY();\n object.setY(object.getY() + this._requestedDeltaY);\n\n // Stop when colliding with an obstacle.\n while (\n // Jumpthru == obstacle <=> Never when going up.\n (this._requestedDeltaY < 0 &&\n this._isCollidingWithOneOf(\n this._potentialCollidingObjects,\n null,\n /*excludeJumpThrus=*/\n true\n )) ||\n // Jumpthru == obstacle <=> Only if not already overlapped when going down.\n (this._requestedDeltaY > 0 &&\n this._isCollidingWithOneOfExcluding(\n this._potentialCollidingObjects,\n this._overlappedJumpThru\n ))\n ) {\n if (this._state === this._jumping) {\n this._setFalling();\n }\n if (\n (this._requestedDeltaY > 0 && object.getY() <= oldY) ||\n (this._requestedDeltaY < 0 && object.getY() >= oldY)\n ) {\n object.setY(\n // Unable to move the object without being stuck in an obstacle.\n oldY\n );\n break;\n }\n object.setY(\n Math.floor(object.getY()) + (this._requestedDeltaY > 0 ? -1 : 1)\n );\n }\n }\n }\n }\n\n _setFalling() {\n this._state.leave();\n const from = this._state;\n this._state = this._falling;\n this._falling.enter(from);\n }\n\n _setOnFloor(\n collidingPlatform: gdjs.PlatformRuntimeBehavior,\n floorPolygon: gdjs.Polygon\n ) {\n this._state.leave();\n this._state = this._onFloor;\n this._onFloor.enter(collidingPlatform, floorPolygon);\n }\n\n private _setJumping() {\n this._state.leave();\n const from = this._state;\n this._state = this._jumping;\n this._jumping.enter(from);\n }\n\n private _setGrabbingPlatform(\n grabbedPlatform: gdjs.PlatformRuntimeBehavior\n ) {\n this._state.leave();\n this._state = this._grabbingPlatform;\n this._grabbingPlatform.enter(grabbedPlatform);\n }\n\n private _setOnLadder() {\n this._state.leave();\n this._state = this._onLadder;\n this._onLadder.enter();\n }\n\n _checkTransitionOnLadder() {\n if (this._ladderKey && this._isOverlappingLadder()) {\n this._setOnLadder();\n }\n }\n\n _checkTransitionJumping() {\n if (this._canJump && this._jumpKey) {\n this._setJumping();\n }\n }\n\n _checkGrabPlatform() {\n const object = this.owner;\n\n let oldX = object.getX();\n object.setX(\n object.getX() +\n (this._requestedDeltaX < 0 ||\n (this._requestedDeltaX === 0 && this._lastDirectionIsLeft)\n ? -this._xGrabTolerance\n : this._xGrabTolerance)\n );\n const collidingPlatforms: gdjs.PlatformRuntimeBehavior[] =\n gdjs.staticArray(\n PlatformerObjectRuntimeBehavior.prototype._checkGrabPlatform\n );\n collidingPlatforms.length = 0;\n for (const platform of this._potentialCollidingObjects) {\n if (this._isCollidingWith(platform) && this._canGrab(platform)) {\n collidingPlatforms.push(platform);\n }\n }\n object.setX(oldX);\n\n //Check if we can grab the collided platform\n let oldY = object.getY();\n for (const collidingPlatform of collidingPlatforms) {\n object.setY(\n collidingPlatform.owner.getY() +\n collidingPlatform.getYGrabOffset() -\n this._yGrabOffset\n );\n if (\n !this._isCollidingWithOneOf(\n this._potentialCollidingObjects,\n null,\n /*excludeJumpthrus=*/\n true\n )\n ) {\n this._setGrabbingPlatform(collidingPlatform);\n this._requestedDeltaY = 0;\n collidingPlatforms.length = 0;\n return;\n }\n object.setY(oldY);\n }\n collidingPlatforms.length = 0;\n }\n\n private _checkTransitionOnFloorOrFalling() {\n const object = this.owner;\n const oldY = object.getY();\n // Avoid landing on a platform if the object is not going down.\n // (which could happen for Jumpthru, when the object jump and pass just at the top\n // of a jumpthru, it could be considered as landing if not for this extra check).\n const canLand = this._requestedDeltaY >= 0;\n\n // The interval could be smaller.\n // It's just for rounding errors.\n const { highestGroundPlatform, highestGroundPolygon } =\n this._findHighestFloorAndMoveOnTop(\n this._potentialCollidingObjects,\n -1,\n 1\n );\n // don't fall if GrabbingPlatform or OnLadder\n if (this._state === this._onFloor) {\n if (!highestGroundPlatform || !highestGroundPolygon) {\n this._setFalling();\n } else if (\n highestGroundPlatform === this._onFloor.getFloorPlatform() &&\n highestGroundPolygon === this._onFloor.getFloorPolygon()\n ) {\n this._onFloor.updateFloorPosition();\n } else {\n this._setOnFloor(highestGroundPlatform, highestGroundPolygon);\n }\n } else if (highestGroundPlatform && highestGroundPolygon && canLand) {\n this._setOnFloor(highestGroundPlatform, highestGroundPolygon);\n } else {\n // The object can't land.\n object.setY(oldY);\n }\n }\n\n _fall(timeDelta: float) {\n const previousFallSpeed = this._currentFallSpeed;\n this._currentFallSpeed += this._gravity * timeDelta;\n if (this._currentFallSpeed > this._maxFallingSpeed) {\n this._currentFallSpeed = this._maxFallingSpeed;\n }\n if (this._useLegacyTrajectory) {\n this._requestedDeltaY += this._currentFallSpeed * timeDelta;\n } else {\n // Use Verlet integration.\n this._requestedDeltaY +=\n ((this._currentFallSpeed + previousFallSpeed) / 2) * timeDelta;\n }\n }\n\n //Scene change is not supported\n /*\n if ( parentScene != &scene ) //Parent scene has changed\n {\n parentScene = &scene;\n sceneManager = parentScene ? &ScenePlatformObjectsManager::managers[&scene] : null;\n floorPlatform = null;\n }\n */\n /**\n * Return true if the object owning the behavior can grab the specified platform. There must be a collision\n * between the object and the platform.\n * @param platform The platform the object is in collision with\n * @param y The value in pixels on Y axis the object wants to move to\n */\n private _canGrab(platform: gdjs.PlatformRuntimeBehavior) {\n const y1 = this.owner.getY() + this._yGrabOffset - this._lastDeltaY;\n const y2 = this.owner.getY() + this._yGrabOffset;\n const platformY = platform.owner.getY() + platform.getYGrabOffset();\n // This must be inclusive for at least one position.\n // Otherwise, if the character is at the exact position,\n // it could not be able to grab the platform at any frame.\n return (\n platform.canBeGrabbed() &&\n ((y1 < platformY && platformY <= y2) ||\n (y2 <= platformY && platformY < y1))\n );\n }\n\n /**\n * Mark the platformer object as not grabbing any platform.\n */\n _releaseGrabbedPlatform() {\n if (this._state === this._grabbingPlatform) {\n this._setFalling();\n }\n }\n\n /**\n * Mark the platformer object as falling if on a ladder.\n */\n _releaseLadder() {\n if (this._state === this._onLadder) {\n this._setFalling();\n }\n }\n\n /**\n * Separate the object from all platforms passed in parameter.\n * @param candidates The platform to be tested for collision\n * @param excludeJumpThrus If set to true, jumpthru platforms are excluded. false if not defined.\n * @returns true if the object was moved\n */\n private _separateFromPlatforms(\n candidates: gdjs.PlatformRuntimeBehavior[],\n excludeJumpThrus: boolean\n ) {\n excludeJumpThrus = !!excludeJumpThrus;\n const objects = gdjs.staticArray(\n PlatformerObjectRuntimeBehavior.prototype._separateFromPlatforms\n );\n objects.length = 0;\n for (let i = 0; i < candidates.length; ++i) {\n const platform = candidates[i];\n if (\n platform.getPlatformType() === gdjs.PlatformRuntimeBehavior.LADDER\n ) {\n continue;\n }\n if (\n excludeJumpThrus &&\n platform.getPlatformType() === gdjs.PlatformRuntimeBehavior.JUMPTHRU\n ) {\n continue;\n }\n objects.push(platform.owner);\n }\n return this.owner.separateFromObjects(objects, this._ignoreTouchingEdges);\n }\n\n /**\n * Among the platforms passed in parameter, return true if there is a platform colliding with the object.\n * Ladders are *always* excluded from the test.\n * @param candidates The platform to be tested for collision\n * @param exceptThisOne The object identifier of a platform to be excluded from the check. Can be null.\n * @param excludeJumpThrus If set to true, jumpthru platforms are excluded. false if not defined.\n * @returns true if the object collides any platform\n */\n _isCollidingWithOneOf(\n candidates: gdjs.PlatformRuntimeBehavior[],\n ignoredPlatformId?: number | null,\n excludeJumpThrus?: boolean,\n ignoredPolygon?: gdjs.Polygon | null\n ) {\n excludeJumpThrus = !!excludeJumpThrus;\n for (let i = 0; i < candidates.length; ++i) {\n const platform = candidates[i];\n const isPlatformIgnored = platform.owner.id === ignoredPlatformId;\n if (isPlatformIgnored && !ignoredPolygon) {\n continue;\n }\n if (\n platform.getPlatformType() === gdjs.PlatformRuntimeBehavior.LADDER\n ) {\n continue;\n }\n if (\n excludeJumpThrus &&\n platform.getPlatformType() === gdjs.PlatformRuntimeBehavior.JUMPTHRU\n ) {\n continue;\n }\n if (\n gdjs.RuntimeObject.collisionTest(\n platform.owner,\n this.owner,\n this._ignoreTouchingEdges,\n isPlatformIgnored ? ignoredPolygon : null\n )\n ) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Find the highest floor reachable and move the owner on top of it.\n *\n * Also see {@link ./README.md}\n *\n * @param candidates The platform to be tested for collision\n * @param upwardDeltaY The owner won't move upward more than this value.\n * @param downwardDeltaY The owner won't move downward more than this value.\n * @returns the platform where to walk or if an obstacle was found\n */\n _findHighestFloorAndMoveOnTop(\n candidates: gdjs.PlatformRuntimeBehavior[],\n upwardDeltaY: float,\n downwardDeltaY: float\n ): PlatformSearchResult {\n const context = FollowConstraintContext.instance;\n context.initializeBeforeSearch(this, upwardDeltaY, downwardDeltaY);\n\n let totalHighestY = Number.MAX_VALUE;\n let highestGroundPlatform: gdjs.PlatformRuntimeBehavior | null = null;\n let highestGroundPolygon: gdjs.Polygon | null = null;\n let isCollidingAnyPlatform = false;\n for (const platform of candidates) {\n if (\n platform.getPlatformType() === gdjs.PlatformRuntimeBehavior.LADDER ||\n // Jump through platforms are obstacles only when the character comes from the top.\n (platform.getPlatformType() ===\n gdjs.PlatformRuntimeBehavior.JUMPTHRU &&\n // When following the floor, jumpthrus that are higher than the character are ignored.\n // If we only look above the character bottom, every jumpthrus can be discarded\n // without doing any collision check.\n ((this._state === this._onFloor &&\n platform !== this._onFloor.getFloorPlatform() &&\n downwardDeltaY < 0) ||\n // When trying to land on a platform, exclude jumpthrus that were already overlapped.\n (this._state !== this._onFloor &&\n this._isIn(this._overlappedJumpThru, platform.owner.id))))\n ) {\n continue;\n }\n\n const previousAllowedMinDeltaY = context.allowedMinDeltaY;\n const previousAllowedMaxDeltaY = context.allowedMaxDeltaY;\n this._findPlatformHighestRelativeYUnderObject(platform, context);\n let highestRelativeY = context.getFloorDeltaY();\n if (\n platform.getPlatformType() ===\n gdjs.PlatformRuntimeBehavior.JUMPTHRU &&\n // When following the floor, ignore jumpthrus that are higher than the character bottom.\n ((this._state === this._onFloor &&\n platform !== this._onFloor.getFloorPlatform() &&\n highestRelativeY < 0) ||\n // A jumpthrus should never constrain a character to go below.\n // Jumpthrus are considered as obstacles at the 1st frame they are overlapping the character\n // because it allows it to land on them, but they shouldn't push on its head.\n context.allowedMinDeltaY !== previousAllowedMinDeltaY)\n ) {\n // Don't follow jumpthrus that are higher than the character bottom.\n // Revert side effect on the search context.\n context.revertTo(previousAllowedMinDeltaY, previousAllowedMaxDeltaY);\n continue;\n }\n if (context.isCollidingAnyPlatform()) {\n isCollidingAnyPlatform = true;\n }\n if (context.floorIsTooHigh()) {\n // One platform is colliding the character\n // and is too high for the character to walk on.\n // This will still be an obstacle even if there\n // are other platforms that fit the requirements.\n highestGroundPlatform = null;\n highestGroundPolygon = null;\n break;\n }\n\n if (\n context.isCollidingAnyPlatform() &&\n highestRelativeY < totalHighestY\n ) {\n totalHighestY = highestRelativeY;\n highestGroundPlatform = platform;\n highestGroundPolygon = context.highestFloorPolygon;\n }\n }\n if (highestGroundPlatform) {\n const object = this.owner;\n object.setY(object.getY() + totalHighestY);\n }\n const returnValue =\n gdjs.PlatformerObjectRuntimeBehavior._platformSearchResult;\n returnValue.highestGroundPlatform = highestGroundPlatform;\n returnValue.highestGroundPolygon = highestGroundPolygon;\n returnValue.isCollidingAnyPlatform = isCollidingAnyPlatform;\n return returnValue;\n }\n\n /**\n * Find the highest Y relative to the owner bottom of the floor reachable by the owner.\n * @param platform The platform to be tested for collision.\n * @param upwardDeltaY The owner won't move upward more than this value.\n * @param downwardDeltaY The owner won't move downward more than this value.\n * @return the search context\n */\n private _findPlatformHighestRelativeYUnderObject(\n platform: gdjs.PlatformRuntimeBehavior,\n context: FollowConstraintContext\n ): FollowConstraintContext {\n const platformObject = platform.owner;\n const platformAABB = platformObject.getAABB();\n if (\n platformAABB.max[0] <= context.ownerMinX ||\n platformAABB.min[0] >= context.ownerMaxX ||\n platformAABB.max[1] <= context.headMinY ||\n platformAABB.min[1] > context.floorMaxY\n ) {\n // No collision\n return context;\n }\n\n for (const hitbox of platformObject.getHitBoxesAround(\n context.ownerMinX,\n context.headMinY,\n context.ownerMaxX,\n context.floorMaxY\n )) {\n if (hitbox.vertices.length < 3) {\n continue;\n }\n\n // Edges over the character head might not result to a collision,\n // but if there is also an edge under its head then there is a collision.\n // The platform hitbox could be in several parts.\n // So, the object could walk on one part\n // and have another part over its head.\n // This is why flags are reset between each hitbox.\n context.initializeBeforeHitboxCheck();\n\n let previousVertex = hitbox.vertices[hitbox.vertices.length - 2];\n let vertex = hitbox.vertices[hitbox.vertices.length - 1];\n for (const nextVertex of hitbox.vertices) {\n // When the character is side by side to a wall,\n // no collision should be detected.\n // Indeed, it only shares an edge so the intersection has no area.\n // But, the character can share a vertex X with a platform\n // when one of them is encompassing the other.\n // This is why the edge direction is checked in this case.\n if (\n // The vertex is strictly into the interval...\n (context.ownerMinX < vertex[0] && vertex[0] < context.ownerMaxX) ||\n // ...or is on a bound but at least one of its edges is from the inside.\n // Note: this needs strict convex hitbox to work.\n (vertex[0] === context.ownerMinX &&\n (previousVertex[0] > vertex[0] || nextVertex[0] > vertex[0])) ||\n (vertex[0] === context.ownerMaxX &&\n (previousVertex[0] < vertex[0] || nextVertex[0] < vertex[0]))\n ) {\n context.addPointConstraint(vertex[1], hitbox);\n }\n\n const deltaX = vertex[0] - previousVertex[0];\n // Vertical edges doesn't matter\n if (deltaX !== 0) {\n // Check intersection on the left side of owner\n if (\n (vertex[0] < context.ownerMinX &&\n context.ownerMinX < previousVertex[0]) ||\n (previousVertex[0] < context.ownerMinX &&\n context.ownerMinX < vertex[0])\n ) {\n const deltaY = vertex[1] - previousVertex[1];\n const intersectionY =\n previousVertex[1] +\n ((context.ownerMinX - previousVertex[0]) * deltaY) / deltaX;\n\n context.addPointConstraint(intersectionY, hitbox);\n }\n // Check intersection on the right side of owner\n if (\n (vertex[0] < context.ownerMaxX &&\n context.ownerMaxX < previousVertex[0]) ||\n (previousVertex[0] < context.ownerMaxX &&\n context.ownerMaxX < vertex[0])\n ) {\n const deltaY = vertex[1] - previousVertex[1];\n const intersectionY =\n previousVertex[1] +\n ((context.ownerMaxX - previousVertex[0]) * deltaY) / deltaX;\n\n context.addPointConstraint(intersectionY, hitbox);\n }\n }\n if (context.floorIsTooHigh()) {\n // The character can't follow the platforms.\n // No need to continue the search.\n return context;\n }\n previousVertex = vertex;\n vertex = nextVertex;\n }\n }\n return context;\n }\n\n /**\n * Among the platforms passed in parameter, return true if there is a platform colliding with the object.\n * Ladders are *always* excluded from the test.\n * @param candidates The platform to be tested for collision\n * @param exceptTheseOnes The platforms to be excluded from the test\n */\n private _isCollidingWithOneOfExcluding(\n candidates: gdjs.PlatformRuntimeBehavior[],\n exceptTheseOnes: gdjs.PlatformRuntimeBehavior[]\n ) {\n for (let i = 0; i < candidates.length; ++i) {\n const platform = candidates[i];\n if (exceptTheseOnes && this._isIn(exceptTheseOnes, platform.owner.id)) {\n continue;\n }\n if (\n platform.getPlatformType() === gdjs.PlatformRuntimeBehavior.LADDER\n ) {\n continue;\n }\n if (\n gdjs.RuntimeObject.collisionTest(\n this.owner,\n platform.owner,\n this._ignoreTouchingEdges\n )\n ) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Return true if the platform is colliding with the behavior owner object.\n * Overlapped jump thru and ladders are excluded.\n * @param platform The platform to be tested for collision\n */\n private _isCollidingWith(platform: gdjs.PlatformRuntimeBehavior): boolean {\n return (\n platform.getPlatformType() !== gdjs.PlatformRuntimeBehavior.LADDER &&\n !this._isIn(this._overlappedJumpThru, platform.owner.id) &&\n gdjs.RuntimeObject.collisionTest(\n this.owner,\n platform.owner,\n this._ignoreTouchingEdges\n )\n );\n }\n\n /**\n * Update _overlappedJumpThru member, so that it contains all the jumpthru platforms colliding with\n * the behavior owner object.\n * Note: _updatePotentialCollidingObjects must have been called before.\n */\n private _updateOverlappedJumpThru() {\n this._overlappedJumpThru.length = 0;\n for (let i = 0; i < this._potentialCollidingObjects.length; ++i) {\n const platform = this._potentialCollidingObjects[i];\n if (\n platform.getPlatformType() ===\n gdjs.PlatformRuntimeBehavior.JUMPTHRU &&\n gdjs.RuntimeObject.collisionTest(\n this.owner,\n platform.owner,\n this._ignoreTouchingEdges\n )\n ) {\n this._overlappedJumpThru.push(platform);\n }\n }\n }\n\n /**\n * Return true if the object is overlapping a ladder.\n * Note: _updatePotentialCollidingObjects must have been called before.\n */\n _isOverlappingLadder() {\n for (let i = 0; i < this._potentialCollidingObjects.length; ++i) {\n const platform = this._potentialCollidingObjects[i];\n if (\n platform.getPlatformType() !== gdjs.PlatformRuntimeBehavior.LADDER\n ) {\n continue;\n }\n\n if (\n gdjs.RuntimeObject.collisionTest(\n this.owner,\n platform.owner,\n this._ignoreTouchingEdges\n )\n ) {\n return true;\n }\n }\n return false;\n }\n\n _isIn(platformArray: gdjs.PlatformRuntimeBehavior[], id: integer) {\n for (let i = 0; i < platformArray.length; ++i) {\n if (platformArray[i].owner.id === id) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Update _potentialCollidingObjects member with platforms near the object.\n */\n private _updatePotentialCollidingObjects(maxMovementLength: float) {\n const object = this.owner;\n\n this._manager.getAllPlatformsAround(\n object,\n maxMovementLength,\n this._potentialCollidingObjects\n );\n\n // Filter the potential colliding platforms to ensure that the object owning the behavior\n // is not considered as colliding with itself, in the case that it also has the\n // platform behavior.\n for (let i = 0; i < this._potentialCollidingObjects.length; ) {\n if (this._potentialCollidingObjects[i].owner === object) {\n this._potentialCollidingObjects.splice(i, 1);\n } else {\n i++;\n }\n }\n }\n\n /**\n * Simulate a control action in the Platformer Object by specifying an input.\n * @param input The string expression of the control action [Left,Right,Up,Down,Ladder,Jump,Release,Release Ladder].\n */\n simulateControl(input: string) {\n if (input === 'Left') {\n this._leftKey = true;\n } else if (input === 'Right') {\n this._rightKey = true;\n } else if (input === 'Up') {\n this._upKey = true;\n } else if (input === 'Down') {\n this._downKey = true;\n } else if (input === 'Ladder') {\n this._ladderKey = true;\n } else if (input === 'Jump') {\n this._jumpKey = true;\n } else if (input === 'Release') {\n this._releasePlatformKey = true;\n } else if (input === 'Release Ladder') {\n this._releaseLadderKey = true;\n }\n }\n\n /**.\n * @param input The control to be tested [Left,Right,Up,Down,Ladder,Jump,Release,Release Ladder].\n * @returns true if the key was used since the last `doStepPreEvents` call.\n */\n isUsingControl(input: string): boolean {\n if (input === 'Left') {\n return this._wasLeftKeyPressed;\n }\n if (input === 'Right') {\n return this._wasRightKeyPressed;\n }\n if (input === 'Up') {\n return this._wasUpKeyPressed;\n }\n if (input === 'Down') {\n return this._wasDownKeyPressed;\n }\n if (input === 'Ladder') {\n return this._wasLadderKeyPressed;\n }\n if (input === 'Jump') {\n return this._wasJumpKeyPressed;\n }\n if (input === 'Release') {\n return this._wasReleasePlatformKeyPressed;\n }\n if (input === 'Release Ladder') {\n return this._wasReleaseLadderKeyPressed;\n }\n return false;\n }\n\n /**\n * Get the gravity of the Platformer Object.\n * @returns The current gravity.\n */\n getGravity(): float {\n return this._gravity;\n }\n\n /**\n * Get maximum angle of a slope for the Platformer Object to run on it as a floor.\n * @returns the slope maximum angle, in degrees.\n */\n getSlopeMaxAngle(): float {\n return this._slopeMaxAngle;\n }\n\n /**\n * Get the maximum falling speed of the Platformer Object.\n * @returns The maximum falling speed.\n */\n getMaxFallingSpeed(): float {\n return this._maxFallingSpeed;\n }\n\n /**\n * Get the speed used to move on Y axis when climbing a ladder.\n * @returns The speed of ladder climbing.\n */\n getLadderClimbingSpeed(): float {\n return this._ladderClimbingSpeed;\n }\n\n /**\n * Get the acceleration value of the Platformer Object.\n * @returns The current acceleration.\n */\n getAcceleration(): float {\n return this._acceleration;\n }\n\n /**\n * Get the deceleration of the Platformer Object.\n * @returns The current deceleration.\n */\n getDeceleration(): float {\n return this._deceleration;\n }\n\n /**\n * Get the maximum speed of the Platformer Object.\n * @returns The maximum speed.\n */\n getMaxSpeed(): float {\n return this._maxSpeed;\n }\n\n /**\n * Get the jump speed of the Platformer Object.\n * @returns The jump speed.\n */\n getJumpSpeed(): float {\n return this._jumpSpeed;\n }\n\n /**\n * Get the jump sustain time of the Platformer Object.\n * @returns The jump sustain time.\n */\n getJumpSustainTime(): float {\n return this._jumpSustainTime;\n }\n\n /**\n * Get the speed at which the object is falling. It is 0 when the object is on a floor, and non 0 as soon as the object leaves the floor.\n * @returns The current fall speed.\n */\n getCurrentFallSpeed(): float {\n return this._currentFallSpeed;\n }\n\n /**\n * Get the current speed of the Platformer Object.\n * @returns The current speed.\n */\n getCurrentSpeed(): float {\n return this._currentSpeed;\n }\n\n /**\n * Set the current speed of the Platformer Object.\n * @param currentSpeed The current speed.\n */\n setCurrentSpeed(currentSpeed: float): void {\n this._currentSpeed = gdjs.evtTools.common.clamp(\n currentSpeed,\n -this._maxSpeed,\n this._maxSpeed\n );\n }\n\n /**\n * Get the current jump speed of the Platformer Object.\n * @returns The current jump speed.\n */\n getCurrentJumpSpeed(): float {\n return this._jumping.getCurrentJumpSpeed();\n }\n\n /**\n * Check if the Platformer Object can grab the platforms.\n * @returns Returns true if the object can grab the platforms.\n */\n canGrabPlatforms(): boolean {\n return this._canGrabPlatforms;\n }\n\n /**\n * Check if the Platformer Object can jump.\n * @returns Returns true if the object can jump.\n */\n canJump(): boolean {\n return this._canJump;\n }\n\n /**\n * Set the gravity of the Platformer Object.\n * @param gravity The new gravity.\n */\n setGravity(gravity: float): void {\n this._gravity = gravity;\n }\n\n /**\n * Set the maximum falling speed of the Platformer Object.\n * @param maxFallingSpeed The maximum falling speed.\n * @param tryToPreserveAirSpeed If true and if jumping, tune the current jump speed to preserve the overall speed in the air.\n */\n setMaxFallingSpeed(\n maxFallingSpeed: float,\n tryToPreserveAirSpeed: boolean = false\n ): void {\n if (tryToPreserveAirSpeed && this._state === this._jumping) {\n // If the falling speed is too high compared to the new max falling speed,\n // reduce it and adapt the jump speed to preserve the overall vertical speed.\n const fallingSpeedOverflow = this._currentFallSpeed - maxFallingSpeed;\n if (fallingSpeedOverflow > 0) {\n this._currentFallSpeed -= fallingSpeedOverflow;\n this._jumping.setCurrentJumpSpeed(\n Math.max(\n 0,\n this._jumping.getCurrentJumpSpeed() - fallingSpeedOverflow\n )\n );\n }\n }\n this._maxFallingSpeed = maxFallingSpeed;\n }\n\n /**\n * Set the speed used to move on Y axis when climbing a ladder.\n * @param ladderClimbingSpeed The speed of ladder climbing.\n */\n setLadderClimbingSpeed(ladderClimbingSpeed: float): void {\n this._ladderClimbingSpeed = ladderClimbingSpeed;\n }\n\n /**\n * Set the acceleration of the Platformer Object.\n * @param acceleration The new acceleration.\n */\n setAcceleration(acceleration: float): void {\n this._acceleration = acceleration;\n }\n\n /**\n * Set the deceleration of the Platformer Object.\n * @param deceleration The new deceleration.\n */\n setDeceleration(deceleration: float): void {\n this._deceleration = deceleration;\n }\n\n /**\n * Set the maximum speed of the Platformer Object.\n * @param maxSpeed The new maximum speed.\n */\n setMaxSpeed(maxSpeed: float): void {\n this._maxSpeed = maxSpeed;\n }\n\n /**\n * Set the jump speed of the Platformer Object.\n * @param jumpSpeed The new jump speed.\n */\n setJumpSpeed(jumpSpeed: float): void {\n this._jumpSpeed = jumpSpeed;\n }\n\n /**\n * Set the jump sustain time of the Platformer Object.\n * @param jumpSustainTime The new jump sustain time.\n */\n setJumpSustainTime(jumpSustainTime: float): void {\n this._jumpSustainTime = jumpSustainTime;\n }\n\n /**\n * Set the maximum slope angle of the Platformer Object.\n * @param slopeMaxAngle The new maximum slope angle.\n */\n setSlopeMaxAngle(slopeMaxAngle: float): void {\n if (slopeMaxAngle < 0 || slopeMaxAngle >= 90) {\n return;\n }\n this._slopeMaxAngle = slopeMaxAngle;\n\n //Avoid rounding errors\n if (slopeMaxAngle === 45) {\n this._slopeClimbingFactor = 1;\n } else {\n this._slopeClimbingFactor = Math.tan(\n (slopeMaxAngle * 3.1415926) / 180.0\n );\n }\n\n // Avoid a `_slopeClimbingFactor` set to exactly 0.\n // Otherwise, this can lead the floor finding functions to consider\n // a floor to be \"too high\" to reach, even if the object is very slightly\n // inside it, which can happen because of rounding errors.\n // See \"Floating-point error mitigations\" tests.\n if (this._slopeClimbingFactor < 1 / 1024) {\n this._slopeClimbingFactor = 1 / 1024;\n }\n }\n\n /**\n * Allow the Platformer Object to jump again.\n */\n setCanJump(): void {\n this._canJump = true;\n }\n\n /**\n * Forbid the Platformer Object to air jump.\n */\n setCanNotAirJump(): void {\n if (this._state === this._jumping || this._state === this._falling) {\n this._canJump = false;\n }\n }\n\n /**\n * Abort the current jump.\n *\n * When the character is not in the jumping state this method has no effect.\n */\n abortJump(): void {\n if (this._state === this._jumping) {\n this._currentFallSpeed = 0;\n this._setFalling();\n }\n }\n\n /**\n * Set the current fall speed.\n *\n * When the character is not in the falling state this method has no effect.\n */\n setCurrentFallSpeed(currentFallSpeed: float) {\n if (this._state === this._falling) {\n this._currentFallSpeed = gdjs.evtTools.common.clamp(\n currentFallSpeed,\n 0,\n this._maxFallingSpeed\n );\n }\n }\n\n /**\n * Set if the Platformer Object can grab platforms.\n * @param enable Enable / Disable grabbing of platforms.\n */\n setCanGrabPlatforms(enable: boolean): void {\n this._canGrabPlatforms = enable;\n if (!this._canGrabPlatforms) {\n this._releaseGrabbedPlatform();\n }\n }\n\n /**\n * Ignore the default controls of the Platformer Object.\n * @param ignore Enable / Disable default controls.\n */\n ignoreDefaultControls(ignore: boolean) {\n this._ignoreDefaultControls = ignore;\n }\n\n /**\n * Check if the default controls of the Platformer Object are ignored.\n * @returns true if the default controls are ignored.\n */\n shouldIgnoreDefaultControls() {\n return (\n this._ignoreDefaultControls ||\n this._ignoreDefaultControlsAsSyncedByNetwork\n );\n }\n\n /**\n * Simulate the \"Left\" control of the Platformer Object.\n */\n simulateLeftKey() {\n this._leftKey = true;\n }\n\n /**\n * Simulate the \"Right\" control of the Platformer Object.\n */\n simulateRightKey() {\n this._rightKey = true;\n }\n\n /**\n * Simulate the \"Ladder\" control of the Platformer Object.\n */\n simulateLadderKey() {\n this._ladderKey = true;\n }\n\n /**\n * Simulate the \"Release Ladder\" control of the Platformer Object.\n */\n simulateReleaseLadderKey() {\n this._releaseLadderKey = true;\n }\n\n /**\n * Simulate the \"Up\" control of the Platformer Object.\n */\n simulateUpKey() {\n this._upKey = true;\n }\n\n /**\n * Simulate the \"Down\" control of the Platformer Object.\n */\n simulateDownKey() {\n this._downKey = true;\n }\n\n /**\n * Simulate the \"Jump\" control of the Platformer Object.\n */\n simulateJumpKey() {\n this._jumpKey = true;\n }\n\n /**\n * Simulate the \"Release\" control of the Platformer Object.\n */\n simulateReleasePlatformKey() {\n this._releasePlatformKey = true;\n }\n\n /**\n * Check if the Platformer Object is on a floor.\n * @returns Returns true if on a floor and false if not.\n */\n isOnFloor(): boolean {\n return this._state === this._onFloor;\n }\n\n /**\n * Check if the Platformer Object is on the given object.\n * @returns Returns true if on the object and false if not.\n */\n isOnFloorObject(object: gdjs.RuntimeObject): boolean {\n if (this.isOnFloor()) {\n const floorPlatform = this._onFloor.getFloorPlatform();\n return !!floorPlatform && floorPlatform.owner.id === object.id;\n }\n return false;\n }\n\n /**\n * Check if the Platformer Object is on a ladder.\n * @returns Returns true if on a ladder and false if not.\n */\n isOnLadder(): boolean {\n return this._state === this._onLadder;\n }\n\n /**\n * Check if the Platformer Object is jumping.\n * @returns Returns true if jumping and false if not.\n */\n isJumping(): boolean {\n return this._state === this._jumping;\n }\n\n /**\n * Check if the Platformer Object is grabbing a platform.\n * @returns Returns true if a platform is grabbed and false if not.\n */\n isGrabbingPlatform(): boolean {\n return this._state === this._grabbingPlatform;\n }\n\n /**\n * Check if the Platformer Object is in the falling state. This is false\n * if the object is jumping, even if the object is going down after reaching\n * the jump peak.\n * @returns Returns true if it is falling and false if not.\n */\n isFallingWithoutJumping(): boolean {\n return this._state === this._falling;\n }\n\n /**\n * Check if the Platformer Object is \"going down\", either because it's in the\n * falling state *or* because it's jumping but reached the jump peak and\n * is now going down (because the jump speed can't compensate anymore the\n * falling speed).\n *\n * If you want to check if the object is falling outside of a jump (or because\n * the jump is entirely finished and there is no jump speed applied to the object\n * anymore), consider using `isFallingWithoutJumping`.\n *\n * @returns Returns true if it is \"going down\" and false if not.\n */\n isFalling(): boolean {\n return (\n this._state === this._falling ||\n (this._state === this._jumping &&\n this._currentFallSpeed > this._jumping.getCurrentJumpSpeed())\n );\n }\n\n /**\n * Check if the Platformer Object is moving.\n *\n * When walking or climbing on a ladder,\n * a speed of less than one pixel per frame won't be detected.\n *\n * @returns Returns true if it is moving and false if not.\n * @deprecated use isMovingEvenALittle instead\n */\n isMoving(): boolean {\n return (\n (this._hasMovedAtLeastOnePixel &&\n (this._currentSpeed !== 0 || this._state === this._onLadder)) ||\n this._jumping.getCurrentJumpSpeed() !== 0 ||\n this._currentFallSpeed !== 0\n );\n }\n\n /**\n * Check if the Platformer Object is moving.\n * @returns Returns true if it is moving and false if not.\n */\n isMovingEvenALittle(): boolean {\n return (\n (this._hasReallyMoved &&\n (this._currentSpeed !== 0 || this._state === this._onLadder)) ||\n this._jumping.getCurrentJumpSpeed() !== 0 ||\n this._currentFallSpeed !== 0\n );\n }\n }\n\n /**\n * The object can take 5 states: OnFloor, Falling, Jumping, GrabbingPlatform and OnLadder.\n * The implementations of this interface hold the specific behaviors and internal state of theses 5 states.\n * @see PlatformerObjectRuntimeBehavior.doStepPreEvents to understand how the functions are called.\n */\n interface State {\n /**\n * Called when the object leaves this state.\n * It's a good place to reset the internal state.\n * @see OnFloor.enter that is not part of the interface because it takes specific parameters.\n */\n leave(): void;\n /**\n * Called before the obstacle search.\n * The object position may need adjustments to handle external changes.\n */\n beforeUpdatingObstacles(timeDelta: float): void;\n /**\n * Check if transitions to other states are needed and apply them before moving horizontally.\n */\n checkTransitionBeforeX(): void;\n /**\n * Use _requestedDeltaX and _requestedDeltaY to choose the movement that suits the state before moving horizontally.\n */\n beforeMovingX(): void;\n /**\n * Check if transitions to other states are needed and apply them before moving vertically.\n */\n checkTransitionBeforeY(timeDelta: float): void;\n /**\n * Use _requestedDeltaY to choose the movement that suits the state before moving vertically.\n */\n beforeMovingY(timeDelta: float, oldX: float): void;\n\n getNetworkSyncData(): StateNetworkSyncData;\n\n updateFromNetworkSyncData(syncData: StateNetworkSyncData): void;\n }\n\n /**\n * The object is on the floor standing or walking.\n *\n * Also see {@link ./README.md}\n */\n class OnFloor implements State {\n private _behavior: PlatformerObjectRuntimeBehavior;\n private _floorPlatform: gdjs.PlatformRuntimeBehavior | null = null;\n private _floorPolygon: gdjs.Polygon | null = null;\n private _floorLastX: float = 0;\n private _floorLastY: float = 0;\n _oldHeight: float = 0;\n\n constructor(behavior: PlatformerObjectRuntimeBehavior) {\n this._behavior = behavior;\n }\n\n getFloorPlatform() {\n return this._floorPlatform;\n }\n\n getFloorPolygon() {\n return this._floorPolygon;\n }\n\n enter(\n floorPlatform: gdjs.PlatformRuntimeBehavior,\n floorPolygon: gdjs.Polygon\n ) {\n this._floorPlatform = floorPlatform;\n this._floorPolygon = floorPolygon;\n this.updateFloorPosition();\n this._behavior._canJump = true;\n this._behavior._currentFallSpeed = 0;\n }\n\n leave() {\n this._floorPlatform = null;\n this._floorPolygon = null;\n }\n\n updateFloorPosition() {\n this._floorLastX = this._floorPlatform!.owner.getX();\n this._floorLastY = this._floorPlatform!.owner.getY();\n }\n\n beforeUpdatingObstacles(timeDelta: float) {\n const object = this._behavior.owner;\n // Stick the object to the floor if its height has changed.\n if (this._oldHeight !== object.getHeight()) {\n // TODO This should probably be done after the events because\n // the character stays at the wrong place during 1 frame.\n const deltaY =\n ((this._oldHeight - object.getHeight()) *\n (object.getHeight() + object.getDrawableY() - object.getY())) /\n object.getHeight();\n object.setY(object.getY() + deltaY);\n }\n // Directly follow the floor movement on the Y axis by moving the character.\n // For the X axis, we follow the floor movement using `_requestedDeltaX`\n // (see `beforeMovingX`).\n // We don't use `_requestedDeltaY` to follow the floor on the Y axis\n // to avoid a transition loop with the Falling state.\n // Indeed, if we used it, then:\n // - going down, the character could no longer be on a platform and start falling.\n // - going up, the character will already be pushed on top on the platform\n // by `beforeMovingY` that handle slopes or by `_separateFromPlatforms` that\n // avoid characters being stuck. So using `_requestedDeltaY`, the character\n // would be going too much higher and fall at the next frame.\n //\n // We could make the character follow a platform moving up\n // at a greater speed as it's coherent from a physics point of view.\n // But, when the character is put on top of the platform to follow it up,\n // the platform AABB may not be updated in RBush yet\n // and the platform can go out of the spatial search rectangle\n // even though they are next to each other, which means\n // that the character will fall.\n const deltaY = this._floorPlatform!.owner.getY() - this._floorLastY;\n if (\n deltaY !== 0 &&\n Math.abs(deltaY) <=\n Math.abs(this._behavior._maxFallingSpeed * timeDelta)\n ) {\n object.setY(object.getY() + deltaY);\n }\n }\n\n checkTransitionBeforeX() {\n const behavior = this._behavior;\n // Check that the floor object still exists and is near the object.\n if (\n !behavior._isIn(\n behavior._potentialCollidingObjects,\n this._floorPlatform!.owner.id\n )\n ) {\n behavior._setFalling();\n } else if (\n this._behavior._downKey &&\n this._floorPlatform!._platformType ===\n gdjs.PlatformRuntimeBehavior.JUMPTHRU &&\n behavior._canGoDownFromJumpthru\n ) {\n behavior._overlappedJumpThru.push(this._floorPlatform!);\n behavior._setFalling();\n }\n\n // It was originally in checkTransitionBeforeY.\n // The character is ignoring the floor when moving on X to be able to\n // follow up a slope when moving Y (it enter inside it).\n // When the current floor and the wall the character is facing is part of\n // the same instance, the wall is also ignored when moving on X, but the\n // wall is too high to follow and it is seen as colliding an obstacle\n // from behind.\n // Moving against a wall before jumping in this configuration was making\n // jumps being aborted.\n behavior._checkTransitionJumping();\n }\n\n beforeMovingX() {\n const behavior = this._behavior;\n // Shift the object according to the floor movement.\n behavior._requestedDeltaX +=\n this._floorPlatform!.owner.getX() - this._floorLastX;\n // See `beforeUpdatingObstacles` for the logic for the Y axis.\n }\n\n checkTransitionBeforeY(timeDelta: float) {\n const behavior = this._behavior;\n // Go on a ladder\n behavior._checkTransitionOnLadder();\n }\n\n beforeMovingY(timeDelta: float, oldX: float) {\n const behavior = this._behavior;\n const object = behavior.owner;\n\n if (object.getX() === oldX + behavior._requestedDeltaX) {\n // The character didn't encounter any obstacles on the X axis.\n // It follows the floor.\n\n // In theory, this max delta on the Y axis could be 0. In practice,\n // `behavior._slopeClimbingFactor` has a lower bound of 1 / 1024.\n // This avoids this max delta Y to be strictly 0, which would then risk\n // considering a floor \"too high\", even if the object is inside it because\n // of a very small rounding error.\n // See \"Floating-point error mitigations\" tests.\n const deltaMaxY = Math.abs(\n behavior._requestedDeltaX * behavior._slopeClimbingFactor\n );\n const {\n highestGroundPlatform,\n highestGroundPolygon,\n isCollidingAnyPlatform,\n } = behavior._findHighestFloorAndMoveOnTop(\n behavior._potentialCollidingObjects,\n -deltaMaxY,\n deltaMaxY\n );\n if (\n highestGroundPlatform &&\n highestGroundPolygon &&\n (highestGroundPlatform !== this._floorPlatform ||\n highestGroundPolygon !== this._floorPolygon)\n ) {\n behavior._setOnFloor(highestGroundPlatform, highestGroundPolygon);\n }\n if (highestGroundPlatform === null && isCollidingAnyPlatform) {\n // Unable to follow the floor (too steep): go back to the original position.\n behavior.owner.setX(oldX);\n }\n } else {\n // The character encountered an obstacle on the X axis.\n // Try to walk on it or stop before it.\n\n // Try to follow the platform until the obstacle.\n const {\n highestGroundPlatform: highestGroundOnPlatform,\n isCollidingAnyPlatform,\n } = behavior._findHighestFloorAndMoveOnTop(\n behavior._potentialCollidingObjects,\n Math.min(\n 0,\n -Math.abs(object.getX() - oldX) * behavior._slopeClimbingFactor\n ),\n 0\n );\n if (highestGroundOnPlatform === null && isCollidingAnyPlatform) {\n // Unable to follow the floor (too steep): go back to the original position.\n behavior.owner.setX(oldX);\n } else {\n const requestedDeltaX = behavior._requestedDeltaX;\n // The current platform is climbed.\n // Can the obstacle be climbed too from here?\n // We do a look-up in 2 steps:\n // 1. Try to move 1 pixel on X to climb the junction\n // (because the obstacle detection is done 1 pixel by 1 pixel).\n // 2. Try to follow the obstacle slope by at least 1 pixel on X axis\n // (it can only be done after the junction because otherwise\n // the slope angle would be a mean between the current platform and\n // the obstacles).\n //\n // The 2nd step is done using a 1 pixel width at least, when remainingDeltaX\n // is less than 2 pixels: this will be a \"lookahead\". This is to ensure\n // the character doesn't start to climb a slope it actually can't.\n const remainingDeltaX = requestedDeltaX - (object.getX() - oldX);\n const beforeObstacleY = object.getY();\n const beforeObstacleX = object.getX();\n\n // 1. Try to move 1 pixel on the X axis to climb the junction.\n object.setX(object.getX() + Math.sign(requestedDeltaX));\n const { highestGroundPlatform: highestGroundAtJunction } =\n behavior._findHighestFloorAndMoveOnTop(\n behavior._potentialCollidingObjects,\n // Look up from at least 1 pixel to bypass not perfectly aligned floors.\n Math.min(-1, -1 * behavior._slopeClimbingFactor),\n 0\n );\n if (highestGroundAtJunction) {\n // The obstacle 1st pixel can be climbed.\n // Now that the character is on the obstacle,\n // try to follow the slope for at least 1 pixel.\n const deltaX =\n Math.sign(requestedDeltaX) *\n Math.max(\n 1,\n // - 1, because the owner moved from 1 pixel at the junction.\n Math.abs(remainingDeltaX) - 1\n );\n object.setX(object.getX() + deltaX);\n const {\n highestGroundPlatform: highestGroundOnObstacle,\n highestGroundPolygon,\n } = behavior._findHighestFloorAndMoveOnTop(\n behavior._potentialCollidingObjects,\n // Do an exact slope angle check.\n -Math.abs(deltaX) * behavior._slopeClimbingFactor,\n 0\n );\n if (highestGroundOnObstacle && highestGroundPolygon) {\n // The obstacle slope can be climbed.\n if (Math.abs(remainingDeltaX) >= 2) {\n behavior._setOnFloor(\n highestGroundOnObstacle,\n highestGroundPolygon\n );\n } else {\n // We went too far in order to check that.\n // Now, find the right position on the obstacles.\n object.setPosition(oldX + requestedDeltaX, beforeObstacleY);\n const { highestGroundPlatform: highestGroundOnObstacle } =\n behavior._findHighestFloorAndMoveOnTop(\n behavior._potentialCollidingObjects,\n // requestedDeltaX can be small when the object start moving.\n // So, look up from at least 1 pixel to bypass not perfectly aligned floors.\n Math.min(\n -1,\n -Math.abs(remainingDeltaX) * behavior._slopeClimbingFactor\n ),\n 0\n );\n // Should always be true\n if (highestGroundOnObstacle && highestGroundPolygon) {\n behavior._setOnFloor(\n highestGroundOnObstacle,\n highestGroundPolygon\n );\n }\n }\n } else {\n // Don't climb on the obstacle\n // because the obstacle slope is too steep.\n if (\n Math.sign(beforeObstacleX - oldX) === Math.sign(requestedDeltaX)\n ) {\n object.setPosition(beforeObstacleX, beforeObstacleY);\n } else {\n // Avoid to go backward\n object.setPosition(oldX, beforeObstacleY);\n }\n behavior._currentSpeed = 0;\n }\n } else {\n // Don't climb on the obstacle\n // because the obstacle 1st pixel is more than 1 pixel high (or too steep).\n if (\n Math.sign(beforeObstacleX - oldX) === Math.sign(requestedDeltaX)\n ) {\n object.setPosition(beforeObstacleX, beforeObstacleY);\n } else {\n // Avoid to go backward\n object.setPosition(oldX, beforeObstacleY);\n }\n behavior._currentSpeed = 0;\n }\n }\n }\n }\n\n getNetworkSyncData(): OnFloorStateNetworkSyncData {\n return {\n flx: this._floorLastX,\n fly: this._floorLastY,\n oh: this._oldHeight,\n };\n }\n\n updateFromNetworkSyncData(data: OnFloorStateNetworkSyncData) {\n this._floorLastX = data.flx;\n this._floorLastY = data.fly;\n this._oldHeight = data.oh;\n }\n\n toString(): String {\n return 'OnFloor';\n }\n }\n\n /**\n * The object is falling.\n */\n class Falling implements State {\n private _behavior: PlatformerObjectRuntimeBehavior;\n\n constructor(behavior: PlatformerObjectRuntimeBehavior) {\n this._behavior = behavior;\n }\n\n enter(from: State) {\n // Only forbid jumping when starting to fall from a platform,\n // not when falling during a jump. This is because the Jumping\n // state has already set `_canJump` to false and we don't want to reset\n // it again because it could have been set back to `true` to allow\n // for an \"air jump\".\n // Transition from Falling to Falling state should not happen,\n // but don't change anything if this ever happen.\n if (from !== this._behavior._jumping && from !== this) {\n this._behavior._canJump = false;\n }\n }\n\n leave() {}\n\n beforeUpdatingObstacles(timeDelta: float) {}\n\n checkTransitionBeforeX() {}\n\n beforeMovingX() {}\n\n checkTransitionBeforeY(timeDelta: float) {\n const behavior = this._behavior;\n // Go on a ladder\n behavior._checkTransitionOnLadder();\n // Jumping\n behavior._checkTransitionJumping();\n\n // Grabbing a platform\n if (\n behavior._canGrabPlatforms &&\n (behavior._requestedDeltaX !== 0 || behavior._canGrabWithoutMoving)\n ) {\n behavior._checkGrabPlatform();\n }\n }\n\n beforeMovingY(timeDelta: float, oldX: float) {\n //Fall\n this._behavior._fall(timeDelta);\n }\n\n getNetworkSyncData(): FallingStateNetworkSyncData {\n return {};\n }\n\n updateFromNetworkSyncData(data: FallingStateNetworkSyncData) {}\n\n toString(): String {\n return 'Falling';\n }\n }\n\n /**\n * The object is on the ascending and descending part of the jump.\n * The object is considered falling when the jump continue to a lower position than the initial one.\n */\n class Jumping implements State {\n private _behavior: PlatformerObjectRuntimeBehavior;\n private _currentJumpSpeed: number = 0;\n private _timeSinceCurrentJumpStart: number = 0;\n private _jumpKeyHeldSinceJumpStart: boolean = false;\n private _jumpingFirstDelta: boolean = false;\n\n constructor(behavior: PlatformerObjectRuntimeBehavior) {\n this._behavior = behavior;\n }\n\n getCurrentJumpSpeed() {\n return this._currentJumpSpeed;\n }\n\n setCurrentJumpSpeed(currentJumpSpeed: number) {\n this._currentJumpSpeed = currentJumpSpeed;\n }\n\n enter(from: State) {\n const behavior = this._behavior;\n this._timeSinceCurrentJumpStart = 0;\n this._jumpKeyHeldSinceJumpStart = true;\n\n if (from !== behavior._jumping && from !== behavior._falling) {\n this._jumpingFirstDelta = true;\n }\n\n behavior._canJump = false;\n this._currentJumpSpeed = behavior._jumpSpeed;\n behavior._currentFallSpeed = 0;\n }\n\n leave() {\n this._currentJumpSpeed = 0;\n }\n\n beforeUpdatingObstacles(timeDelta: float) {}\n\n checkTransitionBeforeX() {}\n\n beforeMovingX() {}\n\n checkTransitionBeforeY(timeDelta: float) {\n const behavior = this._behavior;\n // Go on a ladder\n behavior._checkTransitionOnLadder();\n // Jumping\n behavior._checkTransitionJumping();\n\n // Grabbing a platform\n if (\n behavior._canGrabPlatforms &&\n (behavior._requestedDeltaX !== 0 || behavior._canGrabWithoutMoving) &&\n behavior._lastDeltaY >= 0\n ) {\n behavior._checkGrabPlatform();\n }\n }\n\n beforeMovingY(timeDelta: float, oldX: float) {\n const behavior = this._behavior;\n\n // Check if the jump key is continuously held since\n // the beginning of the jump.\n if (!behavior._jumpKey) {\n this._jumpKeyHeldSinceJumpStart = false;\n }\n this._timeSinceCurrentJumpStart += timeDelta;\n\n const previousJumpSpeed = this._currentJumpSpeed;\n // Decrease jump speed after the (optional) jump sustain time is over.\n const sustainJumpSpeed =\n this._jumpKeyHeldSinceJumpStart &&\n this._timeSinceCurrentJumpStart < behavior._jumpSustainTime;\n if (!sustainJumpSpeed) {\n this._currentJumpSpeed -= behavior._gravity * timeDelta;\n }\n\n if (this._behavior._useLegacyTrajectory) {\n behavior._requestedDeltaY -= previousJumpSpeed * timeDelta;\n\n // Fall\n // The condition is a legacy thing.\n // There is no actual reason not to fall at 1st frame.\n // Before a refactoring, it used to not be this obvious.\n if (!this._jumpingFirstDelta) {\n behavior._fall(timeDelta);\n }\n } else {\n // Use Verlet integration.\n behavior._requestedDeltaY +=\n ((-previousJumpSpeed - this._currentJumpSpeed) / 2) * timeDelta;\n\n // Fall\n behavior._fall(timeDelta);\n }\n this._jumpingFirstDelta = false;\n\n if (this._currentJumpSpeed < 0) {\n behavior._setFalling();\n }\n }\n\n getNetworkSyncData(): JumpingStateNetworkSyncData {\n return {\n cjs: this._currentJumpSpeed,\n tscjs: this._timeSinceCurrentJumpStart,\n jkhsjs: this._jumpKeyHeldSinceJumpStart,\n jfd: this._jumpingFirstDelta,\n };\n }\n\n updateFromNetworkSyncData(data: JumpingStateNetworkSyncData) {\n this._currentJumpSpeed = data.cjs;\n this._timeSinceCurrentJumpStart = data.tscjs;\n this._jumpKeyHeldSinceJumpStart = data.jkhsjs;\n this._jumpingFirstDelta = data.jfd;\n }\n\n toString(): String {\n return 'Jumping';\n }\n }\n\n /**\n * The object grabbed the edge of a platform and is standing there.\n */\n class GrabbingPlatform implements State {\n private _behavior: PlatformerObjectRuntimeBehavior;\n private _grabbedPlatform: any = null;\n private _grabbedPlatformLastX: any;\n private _grabbedPlatformLastY: any;\n\n constructor(behavior: PlatformerObjectRuntimeBehavior) {\n this._behavior = behavior;\n }\n\n enter(grabbedPlatform: gdjs.PlatformRuntimeBehavior) {\n this._grabbedPlatform = grabbedPlatform;\n this._behavior._canJump = true;\n this._behavior._currentFallSpeed = 0;\n }\n\n leave() {\n this._grabbedPlatform = null;\n }\n\n beforeUpdatingObstacles(timeDelta: float) {}\n\n checkTransitionBeforeX() {\n const behavior = this._behavior;\n //Check that the grabbed platform object still exists and is near the object.\n if (\n !behavior._isIn(\n behavior._potentialCollidingObjects,\n this._grabbedPlatform.owner.id\n )\n ) {\n behavior._releaseGrabbedPlatform();\n }\n }\n\n beforeMovingX() {\n const behavior = this._behavior;\n //Shift the object according to the grabbed platform movement.\n // this erases any other movement\n behavior._requestedDeltaX =\n this._grabbedPlatform.owner.getX() - this._grabbedPlatformLastX;\n behavior._requestedDeltaY =\n this._grabbedPlatform.owner.getY() - this._grabbedPlatformLastY;\n }\n\n checkTransitionBeforeY(timeDelta: float) {\n const behavior = this._behavior;\n //Go on a ladder\n behavior._checkTransitionOnLadder();\n\n //Release the platform\n if (behavior._releasePlatformKey) {\n behavior._releaseGrabbedPlatform();\n }\n\n //Jumping\n behavior._checkTransitionJumping();\n }\n\n beforeMovingY(timeDelta: float, oldX: float) {\n this._grabbedPlatformLastX = this._grabbedPlatform.owner.getX();\n this._grabbedPlatformLastY = this._grabbedPlatform.owner.getY();\n }\n\n getNetworkSyncData(): GrabbingPlatformStateNetworkSyncData {\n return {\n gplx: this._grabbedPlatformLastX,\n gply: this._grabbedPlatformLastY,\n };\n }\n\n updateFromNetworkSyncData(data: GrabbingPlatformStateNetworkSyncData) {\n this._grabbedPlatformLastX = data.gplx;\n this._grabbedPlatformLastY = data.gply;\n }\n\n toString(): String {\n return 'GrabbingPlatform';\n }\n }\n\n /**\n * The object grabbed a ladder. It can stand or move in 8 directions.\n */\n class OnLadder implements State {\n private _behavior: PlatformerObjectRuntimeBehavior;\n\n constructor(behavior: PlatformerObjectRuntimeBehavior) {\n this._behavior = behavior;\n }\n\n enter() {\n this._behavior._canJump = true;\n this._behavior._currentFallSpeed = 0;\n }\n\n leave() {}\n\n beforeUpdatingObstacles(timeDelta: float) {}\n\n checkTransitionBeforeX() {}\n\n beforeMovingX() {}\n\n checkTransitionBeforeY(timeDelta: float) {\n const behavior = this._behavior;\n //Coming to an extremity of a ladder\n if (!behavior._isOverlappingLadder()) {\n behavior._setFalling();\n }\n\n //Jumping\n behavior._checkTransitionJumping();\n\n //Release the ladder\n if (behavior._releaseLadderKey) {\n behavior._releaseLadder();\n }\n }\n\n beforeMovingY(timeDelta: float, oldX: float) {\n const behavior = this._behavior;\n\n // TODO: we could consider supporting acceleration for ladder climbing in the future.\n if (behavior._upKey) {\n behavior._requestedDeltaY -= behavior._ladderClimbingSpeed * timeDelta;\n }\n if (behavior._downKey) {\n behavior._requestedDeltaY += behavior._ladderClimbingSpeed * timeDelta;\n }\n }\n\n getNetworkSyncData(): OnLadderStateNetworkSyncData {\n return {};\n }\n\n updateFromNetworkSyncData(data: OnLadderStateNetworkSyncData) {}\n\n toString(): String {\n return 'OnLadder';\n }\n }\n\n /**\n * A context used to search for a floor.\n */\n class FollowConstraintContext {\n static readonly instance: FollowConstraintContext =\n new FollowConstraintContext();\n /**\n * Character right side\n *\n * (constant to a search)\n */\n ownerMinX: float = 0;\n /**\n * Character left side\n *\n * (constant to a search)\n */\n ownerMaxX: float = 0;\n /**\n * The maximum top position the character top can go.\n *\n * (constant to a search)\n */\n headMinY: float = 0;\n /**\n * Character top\n *\n * (constant to a search)\n */\n ownerMinY: float = 0;\n /**\n * The maximum bottom position the character top can go.\n *\n * (constant to a search)\n */\n headMaxY: float = 0;\n /**\n * The maximum top position the character bottom can go.\n *\n * (constant to a search)\n */\n floorMinY: float = 0;\n /**\n * Character bottom\n *\n * (constant to a search)\n */\n ownerMaxY: float = 0;\n /**\n * The maximum bottom position the character bottom can go.\n *\n * (constant to a search)\n */\n floorMaxY: float = 0;\n\n /**\n * The minimum upward delta according to already checked platforms.\n *\n * (a result of the search)\n */\n allowedMinDeltaY: float = 0;\n /**\n * The maximum downward delta according to already checked platforms.\n *\n * (a result of the search)\n */\n allowedMaxDeltaY: float = 0;\n\n /**\n * True if any edge has been found over where the character top can go (downward).\n *\n * It allows to check for encompassing platforms.\n *\n * (local to one hitbox check)\n */\n foundOverHead: boolean = false;\n /**\n * True if any edge has been found under where the character bottom can go (upward).\n *\n * It allows to check for encompassing platforms.\n *\n * (local to one hitbox check)\n */\n foundUnderBottom: boolean = false;\n\n highestFloorPolygon: gdjs.Polygon | null = null;\n\n initializeBeforeSearch(\n behavior: PlatformerObjectRuntimeBehavior,\n upwardDeltaY: float,\n downwardDeltaY: float\n ) {\n let ownerMinX = Number.MAX_VALUE;\n let ownerMaxX = -Number.MAX_VALUE;\n let ownerMinY = Number.MAX_VALUE;\n let ownerMaxY = -Number.MAX_VALUE;\n for (const hitBox of behavior.owner.getHitBoxes()) {\n for (const vertex of hitBox.vertices) {\n ownerMinX = Math.min(ownerMinX, vertex[0]);\n ownerMaxX = Math.max(ownerMaxX, vertex[0]);\n ownerMinY = Math.min(ownerMinY, vertex[1]);\n ownerMaxY = Math.max(ownerMaxY, vertex[1]);\n }\n }\n\n this.ownerMinX = ownerMinX;\n this.ownerMaxX = ownerMaxX;\n this.headMinY = ownerMinY + upwardDeltaY;\n this.ownerMinY = ownerMinY;\n this.headMaxY = ownerMinY + downwardDeltaY;\n this.floorMinY = ownerMaxY + upwardDeltaY;\n this.ownerMaxY = ownerMaxY;\n this.floorMaxY = ownerMaxY + downwardDeltaY;\n\n this.allowedMinDeltaY = upwardDeltaY;\n // Number.MAX_VALUE and not downwardDeltaY\n // because it would means that a platform was found.\n // see isCollidingAnyPlatform()\n this.allowedMaxDeltaY = Number.MAX_VALUE;\n }\n\n initializeBeforeHitboxCheck() {\n this.foundOverHead = false;\n this.foundUnderBottom = false;\n }\n\n /**\n * Revert the search variables to a given state.\n *\n * This is used to revert side effect of jumpthru check.\n * @param previousAllowedMinDeltaY\n * @param previousAllowedMaxDeltaY\n */\n revertTo(previousAllowedMinDeltaY: float, previousAllowedMaxDeltaY: float) {\n // Other members are either constants or local to an hitbox search.\n this.allowedMinDeltaY = previousAllowedMinDeltaY;\n this.allowedMaxDeltaY = previousAllowedMaxDeltaY;\n }\n\n setFloorIsTooHigh() {\n this.allowedMinDeltaY = Number.MAX_VALUE;\n this.allowedMaxDeltaY = -Number.MAX_VALUE;\n }\n\n floorIsTooHigh(): boolean {\n // Return true when the 2 constraints are incompatible.\n return this.allowedMinDeltaY > this.allowedMaxDeltaY;\n }\n\n isCollidingAnyPlatform(): boolean {\n return this.ownerMaxY + this.allowedMaxDeltaY <= this.floorMaxY;\n }\n\n getFloorDeltaY(): float {\n return this.allowedMaxDeltaY;\n }\n\n /**\n * Check if the character can follow a given Y or move not to touch it\n * and update the context with this new constraint.\n * @param y\n */\n addPointConstraint(y: float, sourcePolygon: gdjs.Polygon): void {\n if (y < this.floorMinY) {\n // The platform is too high to walk on...\n if (y > this.headMaxY) {\n // ...but not over the object.\n this.setFloorIsTooHigh();\n return;\n }\n // ...but over the object.\n this.foundOverHead = true;\n if (this.foundUnderBottom) {\n // The current hitbox is below and above at the same time.\n // As hitboxes are convex, the platform overlaps the character.\n this.setFloorIsTooHigh();\n return;\n }\n // When there is a platform on the top,\n // the character is constraint on how high\n // he can follow a floor.\n this.allowedMinDeltaY = Math.max(\n this.allowedMinDeltaY,\n y - this.ownerMinY\n );\n } else {\n // The platform can be walked on.\n this.foundUnderBottom = true;\n if (this.foundOverHead) {\n // The current hitbox is below and above at the same time.\n // As hitboxes are convex, the platform overlaps the character.\n this.setFloorIsTooHigh();\n return;\n }\n // Add the vertex to the constraints.\n // When there is a platform on the bottom,\n // the character is constraint on how low\n // he can follow a floor.\n this.allowedMaxDeltaY = Math.min(\n this.allowedMaxDeltaY,\n y - this.ownerMaxY\n );\n this.highestFloorPolygon = sourcePolygon;\n }\n }\n }\n\n gdjs.registerBehavior(\n 'PlatformBehavior::PlatformerObjectBehavior',\n gdjs.PlatformerObjectRuntimeBehavior\n );\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/*\nGDevelop - Platform Behavior Extension\nCopyright (c) 2013-2016 Florian Rival (Florian.Rival@gmail.com)\n */\nnamespace gdjs {\n /**\n * Returned by _findHighestFloorAndMoveOnTop\n */\n type PlatformSearchResult = {\n highestGroundPlatform: gdjs.PlatformRuntimeBehavior | null;\n highestGroundPolygon: gdjs.Polygon | null;\n isCollidingAnyPlatform: boolean;\n };\n\n interface OnFloorStateNetworkSyncData {\n flx: number;\n fly: number;\n oh: number;\n }\n\n interface FallingStateNetworkSyncData {}\n\n interface JumpingStateNetworkSyncData {\n cjs: number;\n tscjs: number;\n jfd: boolean;\n }\n\n interface GrabbingPlatformStateNetworkSyncData {\n gplx: float;\n gply: float;\n }\n\n interface OnLadderStateNetworkSyncData {}\n\n type StateNetworkSyncData =\n | OnFloorStateNetworkSyncData\n | FallingStateNetworkSyncData\n | JumpingStateNetworkSyncData\n | GrabbingPlatformStateNetworkSyncData\n | OnLadderStateNetworkSyncData;\n\n interface PlatformerObjectNetworkSyncDataType {\n cs: float;\n rdx: float;\n rdy: float;\n ldy: float;\n cfs: float;\n cj: boolean;\n ldl: boolean;\n lek: boolean;\n rik: boolean;\n lak: boolean;\n upk: boolean;\n dok: boolean;\n juk: boolean;\n rpk: boolean;\n rlk: boolean;\n jkhsjs: boolean;\n sn: string;\n ssd: StateNetworkSyncData;\n }\n\n export interface PlatformerObjectNetworkSyncData\n extends BehaviorNetworkSyncData {\n props: PlatformerObjectNetworkSyncDataType;\n }\n\n /**\n * PlatformerObjectRuntimeBehavior represents a behavior allowing objects to be\n * considered as a platform by objects having PlatformerObject Behavior.\n */\n export class PlatformerObjectRuntimeBehavior extends gdjs.RuntimeBehavior {\n /**\n * Returned by _findHighestFloorAndMoveOnTop\n */\n private static readonly _platformSearchResult: PlatformSearchResult = {\n highestGroundPlatform: null,\n highestGroundPolygon: null,\n isCollidingAnyPlatform: false,\n };\n\n /**\n * A very small value compare to 1 pixel, yet very huge compare to rounding errors.\n */\n private static readonly epsilon = 2 ** -20;\n\n // Behavior configuration\n\n /** To achieve pixel-perfect precision when positioning object on platform or\n * handling collision with \"walls\", edges of the hitboxes must be ignored during\n * collision checks, so that two overlapping edges are not considered as colliding.\n *\n * For example, if a character is 10px width and is at position (0, 0), it must not be\n * considered as colliding with a platform which is at position (10, 0). Edges will\n * still be overlapping (because character hitbox right edge is at X position 10 and\n * platform hitbox left edge is also at X position 10).\n *\n * This parameter \"_ignoreTouchingEdges\" will be passed to all collision handling functions.\n */\n _ignoreTouchingEdges: boolean = true;\n\n private _acceleration: float;\n private _deceleration: float;\n private _maxSpeed: float;\n private _slopeMaxAngle: float;\n _slopeClimbingFactor: float = 1;\n\n _gravity: float;\n _maxFallingSpeed: float;\n _jumpSpeed: float;\n _jumpSustainTime: float;\n\n _ladderClimbingSpeed: float;\n\n _canGrabPlatforms: boolean;\n _canGrabWithoutMoving: boolean;\n private _yGrabOffset: any;\n private _xGrabTolerance: any;\n\n _useLegacyTrajectory: boolean;\n _useRepeatedJump: boolean;\n\n _canGoDownFromJumpthru: boolean = false;\n\n // Behavior state\n\n _currentSpeed: float = 0;\n _requestedDeltaX: float = 0;\n _requestedDeltaY: float = 0;\n _lastDeltaY: float = 0;\n _currentFallSpeed: float = 0;\n _canJump: boolean = false;\n _lastDirectionIsLeft: boolean = false;\n\n private _ignoreDefaultControls: boolean;\n private _leftKey: boolean = false;\n private _rightKey: boolean = false;\n private _ladderKey: boolean = false;\n _upKey: boolean = false;\n _downKey: boolean = false;\n _jumpKey: boolean = false;\n _jumpKeyHeldSinceJumpStart: boolean = false;\n _releasePlatformKey: boolean = false;\n _releaseLadderKey: boolean = false;\n\n // This is useful when the object is synchronized by an external source\n // like in a multiplayer game, and we want to be able to predict the\n // movement of the object, even if the inputs are not updated every frame.\n _dontClearInputsBetweenFrames: boolean = false;\n // This is useful when the object is synchronized over the network,\n // object is controlled by the network and we want to ensure the current player\n // cannot control it.\n _ignoreDefaultControlsAsSyncedByNetwork: boolean = false;\n\n // This is useful for extensions that need to know\n // which keys were pressed and doesn't know the mapping\n // done by the scene events.\n private _wasLeftKeyPressed: boolean = false;\n private _wasRightKeyPressed: boolean = false;\n private _wasLadderKeyPressed: boolean = false;\n private _wasUpKeyPressed: boolean = false;\n private _wasDownKeyPressed: boolean = false;\n private _wasJumpKeyPressed: boolean = false;\n private _wasReleasePlatformKeyPressed: boolean = false;\n private _wasReleaseLadderKeyPressed: boolean = false;\n\n private _state: State;\n _falling: Falling;\n _onFloor: OnFloor;\n _jumping: Jumping;\n _grabbingPlatform: GrabbingPlatform;\n _onLadder: OnLadder;\n\n /** Platforms near the object, updated with `_updatePotentialCollidingObjects`. */\n _potentialCollidingObjects: Array<gdjs.PlatformRuntimeBehavior>;\n\n /** Overlapped jump-thru platforms, updated with `_updateOverlappedJumpThru`. */\n _overlappedJumpThru: Array<gdjs.PlatformRuntimeBehavior>;\n\n private _hasReallyMoved: boolean = false;\n /** @deprecated use _hasReallyMoved instead */\n private _hasMovedAtLeastOnePixel: boolean = false;\n private _manager: gdjs.PlatformObjectsManager;\n\n constructor(\n instanceContainer: gdjs.RuntimeInstanceContainer,\n behaviorData,\n owner: gdjs.RuntimeObject\n ) {\n super(instanceContainer, behaviorData, owner);\n this._gravity = behaviorData.gravity;\n this._maxFallingSpeed = behaviorData.maxFallingSpeed;\n this._ladderClimbingSpeed = behaviorData.ladderClimbingSpeed || 150;\n this._acceleration = behaviorData.acceleration;\n this._deceleration = behaviorData.deceleration;\n this._maxSpeed = behaviorData.maxSpeed;\n this._jumpSpeed = behaviorData.jumpSpeed;\n this._canGrabPlatforms = behaviorData.canGrabPlatforms || false;\n this._canGrabWithoutMoving = behaviorData.canGrabWithoutMoving;\n this._yGrabOffset = behaviorData.yGrabOffset || 0;\n this._xGrabTolerance = behaviorData.xGrabTolerance || 10;\n this._jumpSustainTime = behaviorData.jumpSustainTime || 0;\n this._ignoreDefaultControls = behaviorData.ignoreDefaultControls;\n this._useLegacyTrajectory =\n behaviorData.useLegacyTrajectory === undefined\n ? true\n : behaviorData.useLegacyTrajectory;\n this._useRepeatedJump =\n behaviorData.useRepeatedJump === undefined\n ? true\n : behaviorData.useRepeatedJump;\n this._canGoDownFromJumpthru = behaviorData.canGoDownFromJumpthru;\n this._slopeMaxAngle = 0;\n this.setSlopeMaxAngle(behaviorData.slopeMaxAngle);\n\n this._potentialCollidingObjects = [];\n this._overlappedJumpThru = [];\n\n this._manager = gdjs.PlatformObjectsManager.getManager(instanceContainer);\n\n this._falling = new Falling(this);\n this._onFloor = new OnFloor(this);\n this._jumping = new Jumping(this);\n this._grabbingPlatform = new GrabbingPlatform(this);\n this._onLadder = new OnLadder(this);\n this._state = this._falling;\n }\n\n getNetworkSyncData(): PlatformerObjectNetworkSyncData {\n // This method is called, so we are synchronizing this object.\n // Let's clear the inputs between frames as we control it.\n this._dontClearInputsBetweenFrames = false;\n this._ignoreDefaultControlsAsSyncedByNetwork = false;\n\n return {\n ...super.getNetworkSyncData(),\n props: {\n cs: this._currentSpeed,\n\n // TODO Try to remove these 3 fields from the synch\n // They are reset every frame and are not part of the state.\n rdx: this._requestedDeltaX,\n rdy: this._requestedDeltaY,\n ldy: this._lastDeltaY,\n\n cfs: this._currentFallSpeed,\n cj: this._canJump,\n ldl: this._lastDirectionIsLeft,\n lek: this._wasLeftKeyPressed,\n rik: this._wasRightKeyPressed,\n lak: this._wasLadderKeyPressed,\n upk: this._wasUpKeyPressed,\n dok: this._wasDownKeyPressed,\n juk: this._wasJumpKeyPressed,\n rpk: this._wasReleasePlatformKeyPressed,\n rlk: this._wasReleaseLadderKeyPressed,\n jkhsjs: this._jumpKeyHeldSinceJumpStart,\n sn: this._state.toString(),\n ssd: this._state.getNetworkSyncData(),\n },\n };\n }\n\n updateFromNetworkSyncData(\n networkSyncData: PlatformerObjectNetworkSyncData\n ) {\n super.updateFromNetworkSyncData(networkSyncData);\n\n const behaviorSpecificProps = networkSyncData.props;\n if (behaviorSpecificProps.cs !== this._currentSpeed) {\n this._currentSpeed = behaviorSpecificProps.cs;\n }\n if (behaviorSpecificProps.rdx !== this._requestedDeltaX) {\n this._requestedDeltaX = behaviorSpecificProps.rdx;\n }\n if (behaviorSpecificProps.rdy !== this._requestedDeltaY) {\n this._requestedDeltaY = behaviorSpecificProps.rdy;\n }\n if (behaviorSpecificProps.ldy !== this._lastDeltaY) {\n this._lastDeltaY = behaviorSpecificProps.ldy;\n }\n if (behaviorSpecificProps.cfs !== this._currentFallSpeed) {\n this._currentFallSpeed = behaviorSpecificProps.cfs;\n }\n if (behaviorSpecificProps.cj !== this._canJump) {\n this._canJump = behaviorSpecificProps.cj;\n }\n if (behaviorSpecificProps.ldl !== this._lastDirectionIsLeft) {\n this._lastDirectionIsLeft = behaviorSpecificProps.ldl;\n }\n if (behaviorSpecificProps.lek !== this._leftKey) {\n this._leftKey = behaviorSpecificProps.lek;\n }\n if (behaviorSpecificProps.rik !== this._rightKey) {\n this._rightKey = behaviorSpecificProps.rik;\n }\n if (behaviorSpecificProps.lak !== this._ladderKey) {\n this._ladderKey = behaviorSpecificProps.lak;\n }\n if (behaviorSpecificProps.upk !== this._upKey) {\n this._upKey = behaviorSpecificProps.upk;\n }\n if (behaviorSpecificProps.dok !== this._downKey) {\n this._downKey = behaviorSpecificProps.dok;\n }\n if (behaviorSpecificProps.juk !== this._jumpKey) {\n this._jumpKey = behaviorSpecificProps.juk;\n }\n if (behaviorSpecificProps.rpk !== this._releasePlatformKey) {\n this._releasePlatformKey = behaviorSpecificProps.rpk;\n }\n if (behaviorSpecificProps.rlk !== this._releaseLadderKey) {\n this._releaseLadderKey = behaviorSpecificProps.rlk;\n }\n if (behaviorSpecificProps.jkhsjs !== this._jumpKeyHeldSinceJumpStart) {\n this._jumpKeyHeldSinceJumpStart = behaviorSpecificProps.jkhsjs;\n }\n\n if (behaviorSpecificProps.sn !== this._state.toString()) {\n switch (behaviorSpecificProps.sn) {\n case 'Falling':\n this._setFalling();\n break;\n case 'OnFloor':\n // Let it handle automatically as we don't know which platform to land on.\n break;\n case 'Jumping':\n this._setJumping();\n break;\n case 'GrabbingPlatform':\n // Let it handle automatically as we don't know which platform to grab.\n break;\n case 'OnLadder':\n this._setOnLadder();\n break;\n default:\n console.error(\n 'Unknown state name: ' + behaviorSpecificProps.sn + '.'\n );\n break;\n }\n }\n\n if (behaviorSpecificProps.sn === this._state.toString()) {\n this._state.updateFromNetworkSyncData(behaviorSpecificProps.ssd);\n }\n\n // When the object is synchronized from the network, the inputs must not be cleared.\n this._dontClearInputsBetweenFrames = true;\n // And we are not using the default controls.\n this._ignoreDefaultControlsAsSyncedByNetwork = true;\n }\n\n updateFromBehaviorData(oldBehaviorData, newBehaviorData): boolean {\n if (oldBehaviorData.gravity !== newBehaviorData.gravity) {\n this.setGravity(newBehaviorData.gravity);\n }\n if (oldBehaviorData.maxFallingSpeed !== newBehaviorData.maxFallingSpeed) {\n this.setMaxFallingSpeed(newBehaviorData.maxFallingSpeed);\n }\n if (oldBehaviorData.acceleration !== newBehaviorData.acceleration) {\n this.setAcceleration(newBehaviorData.acceleration);\n }\n if (oldBehaviorData.deceleration !== newBehaviorData.deceleration) {\n this.setDeceleration(newBehaviorData.deceleration);\n }\n if (oldBehaviorData.maxSpeed !== newBehaviorData.maxSpeed) {\n this.setMaxSpeed(newBehaviorData.maxSpeed);\n }\n if (oldBehaviorData.jumpSpeed !== newBehaviorData.jumpSpeed) {\n this.setJumpSpeed(newBehaviorData.jumpSpeed);\n }\n if (\n oldBehaviorData.canGrabPlatforms !== newBehaviorData.canGrabPlatforms\n ) {\n this.setCanGrabPlatforms(newBehaviorData.canGrabPlatforms);\n }\n if (\n oldBehaviorData.canGrabWithoutMoving !==\n newBehaviorData.canGrabWithoutMoving\n ) {\n this._canGrabWithoutMoving = newBehaviorData.canGrabWithoutMoving;\n }\n if (oldBehaviorData.yGrabOffset !== newBehaviorData.yGrabOffset) {\n this._yGrabOffset = newBehaviorData.yGrabOffset;\n }\n if (oldBehaviorData.xGrabTolerance !== newBehaviorData.xGrabTolerance) {\n this._xGrabTolerance = newBehaviorData.xGrabTolerance;\n }\n if (oldBehaviorData.jumpSustainTime !== newBehaviorData.jumpSustainTime) {\n this.setJumpSustainTime(newBehaviorData.jumpSustainTime);\n }\n if (\n oldBehaviorData.useLegacyTrajectory !==\n newBehaviorData.useLegacyTrajectory\n ) {\n this._useLegacyTrajectory = newBehaviorData.useLegacyTrajectory;\n }\n if (\n oldBehaviorData.canGoDownFromJumpthru !==\n newBehaviorData.canGoDownFromJumpthru\n ) {\n this._canGoDownFromJumpthru = newBehaviorData.canGoDownFromJumpthru;\n }\n return true;\n }\n\n doStepPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {\n const LEFTKEY = 37;\n const UPKEY = 38;\n const RIGHTKEY = 39;\n const DOWNKEY = 40;\n const LSHIFTKEY = 1016;\n const RSHIFTKEY = 2016;\n const SPACEKEY = 32;\n const object = this.owner;\n const timeDelta = this.owner.getElapsedTime() / 1000;\n\n //0.1) Get the player input:\n this._requestedDeltaX = 0;\n this._requestedDeltaY = 0;\n\n const inputManager = instanceContainer.getGame().getInputManager();\n this._leftKey ||\n (this._leftKey =\n !this.shouldIgnoreDefaultControls() &&\n inputManager.isKeyPressed(LEFTKEY));\n this._rightKey ||\n (this._rightKey =\n !this.shouldIgnoreDefaultControls() &&\n inputManager.isKeyPressed(RIGHTKEY));\n\n this._jumpKey ||\n (this._jumpKey =\n !this.shouldIgnoreDefaultControls() &&\n (inputManager.isKeyPressed(LSHIFTKEY) ||\n inputManager.isKeyPressed(RSHIFTKEY) ||\n inputManager.isKeyPressed(SPACEKEY)));\n // Check if the jump key is continuously held since\n // the beginning of the jump.\n if (!this._jumpKey) {\n this._jumpKeyHeldSinceJumpStart = false;\n }\n\n this._ladderKey ||\n (this._ladderKey =\n !this.shouldIgnoreDefaultControls() &&\n inputManager.isKeyPressed(UPKEY));\n\n this._upKey ||\n (this._upKey =\n !this.shouldIgnoreDefaultControls() &&\n inputManager.isKeyPressed(UPKEY));\n this._downKey ||\n (this._downKey =\n !this.shouldIgnoreDefaultControls() &&\n inputManager.isKeyPressed(DOWNKEY));\n\n this._releasePlatformKey ||\n (this._releasePlatformKey =\n !this.shouldIgnoreDefaultControls() &&\n inputManager.isKeyPressed(DOWNKEY));\n\n this._requestedDeltaX += this._updateSpeed(timeDelta);\n\n if (this._leftKey !== this._rightKey) {\n this._lastDirectionIsLeft = this._leftKey;\n }\n\n //0.2) Track changes in object size\n this._state.beforeUpdatingObstacles(timeDelta);\n this._onFloor._oldHeight = object.getHeight();\n\n //0.3) Update list of platforms around/related to the object\n\n //Compute the list of the objects that will be used\n this._updatePotentialCollidingObjects(\n Math.max(this._requestedDeltaX, this._maxFallingSpeed * timeDelta)\n );\n this._updateOverlappedJumpThru();\n\n //1) X axis:\n const beforeMovingXState = this._state;\n this._state.checkTransitionBeforeX();\n this._state.beforeMovingX();\n\n //Ensure the object is not stuck\n if (this._separateFromPlatforms(this._potentialCollidingObjects, true)) {\n //After being unstuck, the object must be able to jump again.\n this._canJump = true;\n }\n\n const oldX = object.getX();\n this._moveX();\n const mayCollideWall = object.getX() !== oldX + this._requestedDeltaX;\n\n //2) Y axis:\n const beforeMovingYState = this._state;\n this._state.checkTransitionBeforeY(timeDelta);\n this._state.beforeMovingY(timeDelta, oldX);\n\n const oldY = object.getY();\n this._moveY();\n\n //3) Update the current floor data for the next tick:\n const beforeLastTransitionYState = this._state;\n //TODO what about a moving platforms, remove this condition to do the same as for grabbing?\n if (this._state !== this._onLadder) {\n this._checkTransitionOnFloorOrFalling();\n }\n\n if (\n // When the character is against a wall and the player hold left or\n // right, the speed shouldn't stack because starting at full speed when\n // jumping over the wall would look strange.\n mayCollideWall &&\n // Whereas, when the state has change, the collision is probably a\n // landing or a collision from the floor when stating to jump. The\n // speed must not be lost in these cases.\n this._state === beforeMovingXState &&\n this._state === beforeMovingYState &&\n this._state === beforeLastTransitionYState &&\n // When the character is on the floor, it will try to walk on the\n // obstacles and already stop if necessary.\n this._state !== this._onFloor\n ) {\n this._currentSpeed = 0;\n }\n\n this._wasLeftKeyPressed = this._leftKey;\n this._wasRightKeyPressed = this._rightKey;\n this._wasLadderKeyPressed = this._ladderKey;\n this._wasUpKeyPressed = this._upKey;\n this._wasDownKeyPressed = this._downKey;\n this._wasJumpKeyPressed = this._jumpKey;\n this._wasReleasePlatformKeyPressed = this._releasePlatformKey;\n this._wasReleaseLadderKeyPressed = this._releaseLadderKey;\n //4) Do not forget to reset pressed keys\n if (!this._dontClearInputsBetweenFrames) {\n // Reset the keys only if the inputs are not supposed to survive between frames.\n // (Most of the time, except if this object is synchronized by an external source)\n this._leftKey = false;\n this._rightKey = false;\n this._ladderKey = false;\n this._upKey = false;\n this._downKey = false;\n this._jumpKey = false;\n this._releasePlatformKey = false;\n this._releaseLadderKey = false;\n }\n\n //5) Track the movement\n this._hasReallyMoved =\n Math.abs(object.getX() - oldX) >\n PlatformerObjectRuntimeBehavior.epsilon ||\n Math.abs(object.getY() - oldY) >\n PlatformerObjectRuntimeBehavior.epsilon;\n this._hasMovedAtLeastOnePixel =\n Math.abs(object.getX() - oldX) >= 1 ||\n Math.abs(object.getY() - oldY) >= 1;\n this._lastDeltaY = object.getY() - oldY;\n }\n\n doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {}\n\n private _updateSpeed(timeDelta: float): float {\n const previousSpeed = this._currentSpeed;\n // Change the speed according to the player's input.\n // TODO Give priority to the last key for faster reaction time.\n if (this._leftKey !== this._rightKey) {\n if (this._leftKey) {\n if (this._currentSpeed <= 0) {\n this._currentSpeed -= this._acceleration * timeDelta;\n } else {\n // Turn back at least as fast as it would stop.\n this._currentSpeed -=\n Math.max(this._acceleration, this._deceleration) * timeDelta;\n }\n } else if (this._rightKey) {\n if (this._currentSpeed >= 0) {\n this._currentSpeed += this._acceleration * timeDelta;\n } else {\n this._currentSpeed +=\n Math.max(this._acceleration, this._deceleration) * timeDelta;\n }\n }\n }\n\n //Take deceleration into account only if no key is pressed.\n if (this._leftKey === this._rightKey) {\n const wasPositive = this._currentSpeed > 0;\n this._currentSpeed -=\n this._deceleration * timeDelta * (wasPositive ? 1.0 : -1.0);\n\n //Set the speed to 0 if the speed was too low.\n if (wasPositive && this._currentSpeed < 0) {\n this._currentSpeed = 0;\n }\n if (!wasPositive && this._currentSpeed > 0) {\n this._currentSpeed = 0;\n }\n }\n if (this._currentSpeed > this._maxSpeed) {\n this._currentSpeed = this._maxSpeed;\n }\n if (this._currentSpeed < -this._maxSpeed) {\n this._currentSpeed = -this._maxSpeed;\n }\n // Use Verlet integration.\n return ((this._currentSpeed + previousSpeed) * timeDelta) / 2;\n }\n\n /**\n * Also see {@link ./README.md}\n */\n private _moveX() {\n const object = this.owner;\n //Move the object on x axis.\n const oldX = object.getX();\n if (this._requestedDeltaX !== 0) {\n let floorPlatformId =\n this._onFloor.getFloorPlatform() !== null\n ? this._onFloor.getFloorPlatform()!.owner.id\n : null;\n object.setX(object.getX() + this._requestedDeltaX);\n let tryRounding = true;\n\n //Colliding: Try to push out from the solid.\n //Note that jump thru are never obstacle on X axis.\n while (\n this._isCollidingWithOneOf(\n this._potentialCollidingObjects,\n floorPlatformId,\n /*excludeJumpthrus=*/\n true,\n this._onFloor.getFloorPolygon()\n )\n ) {\n if (\n (this._requestedDeltaX > 0 && object.getX() <= oldX) ||\n (this._requestedDeltaX < 0 && object.getX() >= oldX)\n ) {\n object.setX(\n //Unable to move the object without being stuck in an obstacle.\n oldX\n );\n break;\n }\n if (tryRounding) {\n // First try rounding the position as this might be sufficient to get the object\n // out of the wall.\n object.setX(Math.round(object.getX()));\n tryRounding = false;\n } else {\n object.setX(\n Math.round(object.getX()) + (this._requestedDeltaX > 0 ? -1 : 1)\n );\n }\n }\n }\n }\n\n private _moveY() {\n const object = this.owner;\n //Move the object on Y axis\n if (this._requestedDeltaY !== 0) {\n if (this._requestedDeltaY > 0) {\n // Use the same method as for following the floor.\n // This is to be consistent on all floor collision.\n // The object will land right on floor.\n\n const { highestGroundPlatform } = this._findHighestFloorAndMoveOnTop(\n this._potentialCollidingObjects,\n 0,\n this._requestedDeltaY\n );\n if (!highestGroundPlatform) {\n object.setY(object.getY() + this._requestedDeltaY);\n }\n } else {\n // The same logic could be applied going up one day.\n let oldY = object.getY();\n object.setY(object.getY() + this._requestedDeltaY);\n\n // Stop when colliding with an obstacle.\n while (\n // Jumpthru == obstacle <=> Never when going up.\n (this._requestedDeltaY < 0 &&\n this._isCollidingWithOneOf(\n this._potentialCollidingObjects,\n null,\n /*excludeJumpThrus=*/\n true\n )) ||\n // Jumpthru == obstacle <=> Only if not already overlapped when going down.\n (this._requestedDeltaY > 0 &&\n this._isCollidingWithOneOfExcluding(\n this._potentialCollidingObjects,\n this._overlappedJumpThru\n ))\n ) {\n if (this._state === this._jumping) {\n this._setFalling();\n }\n if (\n (this._requestedDeltaY > 0 && object.getY() <= oldY) ||\n (this._requestedDeltaY < 0 && object.getY() >= oldY)\n ) {\n object.setY(\n // Unable to move the object without being stuck in an obstacle.\n oldY\n );\n break;\n }\n object.setY(\n Math.floor(object.getY()) + (this._requestedDeltaY > 0 ? -1 : 1)\n );\n }\n }\n }\n }\n\n _setFalling() {\n this._state.leave();\n const from = this._state;\n this._state = this._falling;\n this._falling.enter(from);\n }\n\n _setOnFloor(\n collidingPlatform: gdjs.PlatformRuntimeBehavior,\n floorPolygon: gdjs.Polygon\n ) {\n this._state.leave();\n this._state = this._onFloor;\n this._onFloor.enter(collidingPlatform, floorPolygon);\n }\n\n private _setJumping() {\n this._state.leave();\n const from = this._state;\n this._state = this._jumping;\n this._jumping.enter(from);\n }\n\n private _setGrabbingPlatform(\n grabbedPlatform: gdjs.PlatformRuntimeBehavior\n ) {\n this._state.leave();\n this._state = this._grabbingPlatform;\n this._grabbingPlatform.enter(grabbedPlatform);\n }\n\n private _setOnLadder() {\n this._state.leave();\n this._state = this._onLadder;\n this._onLadder.enter();\n }\n\n _checkTransitionOnLadder() {\n if (this._ladderKey && this._isOverlappingLadder()) {\n this._setOnLadder();\n }\n }\n\n _checkTransitionJumping() {\n if (\n this._canJump &&\n this._jumpKey &&\n (!this._jumpKeyHeldSinceJumpStart || this._useRepeatedJump)\n ) {\n this._setJumping();\n }\n }\n\n _checkGrabPlatform() {\n const object = this.owner;\n\n let oldX = object.getX();\n object.setX(\n object.getX() +\n (this._requestedDeltaX < 0 ||\n (this._requestedDeltaX === 0 && this._lastDirectionIsLeft)\n ? -this._xGrabTolerance\n : this._xGrabTolerance)\n );\n const collidingPlatforms: gdjs.PlatformRuntimeBehavior[] =\n gdjs.staticArray(\n PlatformerObjectRuntimeBehavior.prototype._checkGrabPlatform\n );\n collidingPlatforms.length = 0;\n for (const platform of this._potentialCollidingObjects) {\n if (this._isCollidingWith(platform) && this._canGrab(platform)) {\n collidingPlatforms.push(platform);\n }\n }\n object.setX(oldX);\n\n //Check if we can grab the collided platform\n let oldY = object.getY();\n for (const collidingPlatform of collidingPlatforms) {\n object.setY(\n collidingPlatform.owner.getY() +\n collidingPlatform.getYGrabOffset() -\n this._yGrabOffset\n );\n if (\n !this._isCollidingWithOneOf(\n this._potentialCollidingObjects,\n null,\n /*excludeJumpthrus=*/\n true\n )\n ) {\n this._setGrabbingPlatform(collidingPlatform);\n this._requestedDeltaY = 0;\n collidingPlatforms.length = 0;\n return;\n }\n object.setY(oldY);\n }\n collidingPlatforms.length = 0;\n }\n\n private _checkTransitionOnFloorOrFalling() {\n const object = this.owner;\n const oldY = object.getY();\n // Avoid landing on a platform if the object is not going down.\n // (which could happen for Jumpthru, when the object jump and pass just at the top\n // of a jumpthru, it could be considered as landing if not for this extra check).\n const canLand = this._requestedDeltaY >= 0;\n\n // The interval could be smaller.\n // It's just for rounding errors.\n const { highestGroundPlatform, highestGroundPolygon } =\n this._findHighestFloorAndMoveOnTop(\n this._potentialCollidingObjects,\n -1,\n 1\n );\n // don't fall if GrabbingPlatform or OnLadder\n if (this._state === this._onFloor) {\n if (!highestGroundPlatform || !highestGroundPolygon) {\n this._setFalling();\n } else if (\n highestGroundPlatform === this._onFloor.getFloorPlatform() &&\n highestGroundPolygon === this._onFloor.getFloorPolygon()\n ) {\n this._onFloor.updateFloorPosition();\n } else {\n this._setOnFloor(highestGroundPlatform, highestGroundPolygon);\n }\n } else if (highestGroundPlatform && highestGroundPolygon && canLand) {\n this._setOnFloor(highestGroundPlatform, highestGroundPolygon);\n } else {\n // The object can't land.\n object.setY(oldY);\n }\n }\n\n _fall(timeDelta: float) {\n const previousFallSpeed = this._currentFallSpeed;\n this._currentFallSpeed += this._gravity * timeDelta;\n if (this._currentFallSpeed > this._maxFallingSpeed) {\n this._currentFallSpeed = this._maxFallingSpeed;\n }\n if (this._useLegacyTrajectory) {\n this._requestedDeltaY += this._currentFallSpeed * timeDelta;\n } else {\n // Use Verlet integration.\n this._requestedDeltaY +=\n ((this._currentFallSpeed + previousFallSpeed) / 2) * timeDelta;\n }\n }\n\n //Scene change is not supported\n /*\n if ( parentScene != &scene ) //Parent scene has changed\n {\n parentScene = &scene;\n sceneManager = parentScene ? &ScenePlatformObjectsManager::managers[&scene] : null;\n floorPlatform = null;\n }\n */\n /**\n * Return true if the object owning the behavior can grab the specified platform. There must be a collision\n * between the object and the platform.\n * @param platform The platform the object is in collision with\n * @param y The value in pixels on Y axis the object wants to move to\n */\n private _canGrab(platform: gdjs.PlatformRuntimeBehavior) {\n const y1 = this.owner.getY() + this._yGrabOffset - this._lastDeltaY;\n const y2 = this.owner.getY() + this._yGrabOffset;\n const platformY = platform.owner.getY() + platform.getYGrabOffset();\n // This must be inclusive for at least one position.\n // Otherwise, if the character is at the exact position,\n // it could not be able to grab the platform at any frame.\n return (\n platform.canBeGrabbed() &&\n ((y1 < platformY && platformY <= y2) ||\n (y2 <= platformY && platformY < y1))\n );\n }\n\n /**\n * Mark the platformer object as not grabbing any platform.\n */\n _releaseGrabbedPlatform() {\n if (this._state === this._grabbingPlatform) {\n this._setFalling();\n }\n }\n\n /**\n * Mark the platformer object as falling if on a ladder.\n */\n _releaseLadder() {\n if (this._state === this._onLadder) {\n this._setFalling();\n }\n }\n\n /**\n * Separate the object from all platforms passed in parameter.\n * @param candidates The platform to be tested for collision\n * @param excludeJumpThrus If set to true, jumpthru platforms are excluded. false if not defined.\n * @returns true if the object was moved\n */\n private _separateFromPlatforms(\n candidates: gdjs.PlatformRuntimeBehavior[],\n excludeJumpThrus: boolean\n ) {\n excludeJumpThrus = !!excludeJumpThrus;\n const objects = gdjs.staticArray(\n PlatformerObjectRuntimeBehavior.prototype._separateFromPlatforms\n );\n objects.length = 0;\n for (let i = 0; i < candidates.length; ++i) {\n const platform = candidates[i];\n if (\n platform.getPlatformType() === gdjs.PlatformRuntimeBehavior.LADDER\n ) {\n continue;\n }\n if (\n excludeJumpThrus &&\n platform.getPlatformType() === gdjs.PlatformRuntimeBehavior.JUMPTHRU\n ) {\n continue;\n }\n objects.push(platform.owner);\n }\n return this.owner.separateFromObjects(objects, this._ignoreTouchingEdges);\n }\n\n /**\n * Among the platforms passed in parameter, return true if there is a platform colliding with the object.\n * Ladders are *always* excluded from the test.\n * @param candidates The platform to be tested for collision\n * @param exceptThisOne The object identifier of a platform to be excluded from the check. Can be null.\n * @param excludeJumpThrus If set to true, jumpthru platforms are excluded. false if not defined.\n * @returns true if the object collides any platform\n */\n _isCollidingWithOneOf(\n candidates: gdjs.PlatformRuntimeBehavior[],\n ignoredPlatformId?: number | null,\n excludeJumpThrus?: boolean,\n ignoredPolygon?: gdjs.Polygon | null\n ) {\n excludeJumpThrus = !!excludeJumpThrus;\n for (let i = 0; i < candidates.length; ++i) {\n const platform = candidates[i];\n const isPlatformIgnored = platform.owner.id === ignoredPlatformId;\n if (isPlatformIgnored && !ignoredPolygon) {\n continue;\n }\n if (\n platform.getPlatformType() === gdjs.PlatformRuntimeBehavior.LADDER\n ) {\n continue;\n }\n if (\n excludeJumpThrus &&\n platform.getPlatformType() === gdjs.PlatformRuntimeBehavior.JUMPTHRU\n ) {\n continue;\n }\n if (\n gdjs.RuntimeObject.collisionTest(\n platform.owner,\n this.owner,\n this._ignoreTouchingEdges,\n isPlatformIgnored ? ignoredPolygon : null\n )\n ) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Find the highest floor reachable and move the owner on top of it.\n *\n * Also see {@link ./README.md}\n *\n * @param candidates The platform to be tested for collision\n * @param upwardDeltaY The owner won't move upward more than this value.\n * @param downwardDeltaY The owner won't move downward more than this value.\n * @returns the platform where to walk or if an obstacle was found\n */\n _findHighestFloorAndMoveOnTop(\n candidates: gdjs.PlatformRuntimeBehavior[],\n upwardDeltaY: float,\n downwardDeltaY: float\n ): PlatformSearchResult {\n const context = FollowConstraintContext.instance;\n context.initializeBeforeSearch(this, upwardDeltaY, downwardDeltaY);\n\n let totalHighestY = Number.MAX_VALUE;\n let highestGroundPlatform: gdjs.PlatformRuntimeBehavior | null = null;\n let highestGroundPolygon: gdjs.Polygon | null = null;\n let isCollidingAnyPlatform = false;\n for (const platform of candidates) {\n if (\n platform.getPlatformType() === gdjs.PlatformRuntimeBehavior.LADDER ||\n // Jump through platforms are obstacles only when the character comes from the top.\n (platform.getPlatformType() ===\n gdjs.PlatformRuntimeBehavior.JUMPTHRU &&\n // When following the floor, jumpthrus that are higher than the character are ignored.\n // If we only look above the character bottom, every jumpthrus can be discarded\n // without doing any collision check.\n ((this._state === this._onFloor &&\n platform !== this._onFloor.getFloorPlatform() &&\n downwardDeltaY < 0) ||\n // When trying to land on a platform, exclude jumpthrus that were already overlapped.\n (this._state !== this._onFloor &&\n this._isIn(this._overlappedJumpThru, platform.owner.id))))\n ) {\n continue;\n }\n\n const previousAllowedMinDeltaY = context.allowedMinDeltaY;\n const previousAllowedMaxDeltaY = context.allowedMaxDeltaY;\n this._findPlatformHighestRelativeYUnderObject(platform, context);\n let highestRelativeY = context.getFloorDeltaY();\n if (\n platform.getPlatformType() ===\n gdjs.PlatformRuntimeBehavior.JUMPTHRU &&\n // When following the floor, ignore jumpthrus that are higher than the character bottom.\n ((this._state === this._onFloor &&\n platform !== this._onFloor.getFloorPlatform() &&\n highestRelativeY < 0) ||\n // A jumpthrus should never constrain a character to go below.\n // Jumpthrus are considered as obstacles at the 1st frame they are overlapping the character\n // because it allows it to land on them, but they shouldn't push on its head.\n context.allowedMinDeltaY !== previousAllowedMinDeltaY)\n ) {\n // Don't follow jumpthrus that are higher than the character bottom.\n // Revert side effect on the search context.\n context.revertTo(previousAllowedMinDeltaY, previousAllowedMaxDeltaY);\n continue;\n }\n if (context.isCollidingAnyPlatform()) {\n isCollidingAnyPlatform = true;\n }\n if (context.floorIsTooHigh()) {\n // One platform is colliding the character\n // and is too high for the character to walk on.\n // This will still be an obstacle even if there\n // are other platforms that fit the requirements.\n highestGroundPlatform = null;\n highestGroundPolygon = null;\n break;\n }\n\n if (\n context.isCollidingAnyPlatform() &&\n highestRelativeY < totalHighestY\n ) {\n totalHighestY = highestRelativeY;\n highestGroundPlatform = platform;\n highestGroundPolygon = context.highestFloorPolygon;\n }\n }\n if (highestGroundPlatform) {\n const object = this.owner;\n object.setY(object.getY() + totalHighestY);\n }\n const returnValue =\n gdjs.PlatformerObjectRuntimeBehavior._platformSearchResult;\n returnValue.highestGroundPlatform = highestGroundPlatform;\n returnValue.highestGroundPolygon = highestGroundPolygon;\n returnValue.isCollidingAnyPlatform = isCollidingAnyPlatform;\n return returnValue;\n }\n\n /**\n * Find the highest Y relative to the owner bottom of the floor reachable by the owner.\n * @param platform The platform to be tested for collision.\n * @param upwardDeltaY The owner won't move upward more than this value.\n * @param downwardDeltaY The owner won't move downward more than this value.\n * @return the search context\n */\n private _findPlatformHighestRelativeYUnderObject(\n platform: gdjs.PlatformRuntimeBehavior,\n context: FollowConstraintContext\n ): FollowConstraintContext {\n const platformObject = platform.owner;\n const platformAABB = platformObject.getAABB();\n if (\n platformAABB.max[0] <= context.ownerMinX ||\n platformAABB.min[0] >= context.ownerMaxX ||\n platformAABB.max[1] <= context.headMinY ||\n platformAABB.min[1] > context.floorMaxY\n ) {\n // No collision\n return context;\n }\n\n for (const hitbox of platformObject.getHitBoxesAround(\n context.ownerMinX,\n context.headMinY,\n context.ownerMaxX,\n context.floorMaxY\n )) {\n if (hitbox.vertices.length < 3) {\n continue;\n }\n\n // Edges over the character head might not result to a collision,\n // but if there is also an edge under its head then there is a collision.\n // The platform hitbox could be in several parts.\n // So, the object could walk on one part\n // and have another part over its head.\n // This is why flags are reset between each hitbox.\n context.initializeBeforeHitboxCheck();\n\n let previousVertex = hitbox.vertices[hitbox.vertices.length - 2];\n let vertex = hitbox.vertices[hitbox.vertices.length - 1];\n for (const nextVertex of hitbox.vertices) {\n // When the character is side by side to a wall,\n // no collision should be detected.\n // Indeed, it only shares an edge so the intersection has no area.\n // But, the character can share a vertex X with a platform\n // when one of them is encompassing the other.\n // This is why the edge direction is checked in this case.\n if (\n // The vertex is strictly into the interval...\n (context.ownerMinX < vertex[0] && vertex[0] < context.ownerMaxX) ||\n // ...or is on a bound but at least one of its edges is from the inside.\n // Note: this needs strict convex hitbox to work.\n (vertex[0] === context.ownerMinX &&\n (previousVertex[0] > vertex[0] || nextVertex[0] > vertex[0])) ||\n (vertex[0] === context.ownerMaxX &&\n (previousVertex[0] < vertex[0] || nextVertex[0] < vertex[0]))\n ) {\n context.addPointConstraint(vertex[1], hitbox);\n }\n\n const deltaX = vertex[0] - previousVertex[0];\n // Vertical edges doesn't matter\n if (deltaX !== 0) {\n // Check intersection on the left side of owner\n if (\n (vertex[0] < context.ownerMinX &&\n context.ownerMinX < previousVertex[0]) ||\n (previousVertex[0] < context.ownerMinX &&\n context.ownerMinX < vertex[0])\n ) {\n const deltaY = vertex[1] - previousVertex[1];\n const intersectionY =\n previousVertex[1] +\n ((context.ownerMinX - previousVertex[0]) * deltaY) / deltaX;\n\n context.addPointConstraint(intersectionY, hitbox);\n }\n // Check intersection on the right side of owner\n if (\n (vertex[0] < context.ownerMaxX &&\n context.ownerMaxX < previousVertex[0]) ||\n (previousVertex[0] < context.ownerMaxX &&\n context.ownerMaxX < vertex[0])\n ) {\n const deltaY = vertex[1] - previousVertex[1];\n const intersectionY =\n previousVertex[1] +\n ((context.ownerMaxX - previousVertex[0]) * deltaY) / deltaX;\n\n context.addPointConstraint(intersectionY, hitbox);\n }\n }\n if (context.floorIsTooHigh()) {\n // The character can't follow the platforms.\n // No need to continue the search.\n return context;\n }\n previousVertex = vertex;\n vertex = nextVertex;\n }\n }\n return context;\n }\n\n /**\n * Among the platforms passed in parameter, return true if there is a platform colliding with the object.\n * Ladders are *always* excluded from the test.\n * @param candidates The platform to be tested for collision\n * @param exceptTheseOnes The platforms to be excluded from the test\n */\n private _isCollidingWithOneOfExcluding(\n candidates: gdjs.PlatformRuntimeBehavior[],\n exceptTheseOnes: gdjs.PlatformRuntimeBehavior[]\n ) {\n for (let i = 0; i < candidates.length; ++i) {\n const platform = candidates[i];\n if (exceptTheseOnes && this._isIn(exceptTheseOnes, platform.owner.id)) {\n continue;\n }\n if (\n platform.getPlatformType() === gdjs.PlatformRuntimeBehavior.LADDER\n ) {\n continue;\n }\n if (\n gdjs.RuntimeObject.collisionTest(\n this.owner,\n platform.owner,\n this._ignoreTouchingEdges\n )\n ) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Return true if the platform is colliding with the behavior owner object.\n * Overlapped jump thru and ladders are excluded.\n * @param platform The platform to be tested for collision\n */\n private _isCollidingWith(platform: gdjs.PlatformRuntimeBehavior): boolean {\n return (\n platform.getPlatformType() !== gdjs.PlatformRuntimeBehavior.LADDER &&\n !this._isIn(this._overlappedJumpThru, platform.owner.id) &&\n gdjs.RuntimeObject.collisionTest(\n this.owner,\n platform.owner,\n this._ignoreTouchingEdges\n )\n );\n }\n\n /**\n * Update _overlappedJumpThru member, so that it contains all the jumpthru platforms colliding with\n * the behavior owner object.\n * Note: _updatePotentialCollidingObjects must have been called before.\n */\n private _updateOverlappedJumpThru() {\n this._overlappedJumpThru.length = 0;\n for (let i = 0; i < this._potentialCollidingObjects.length; ++i) {\n const platform = this._potentialCollidingObjects[i];\n if (\n platform.getPlatformType() ===\n gdjs.PlatformRuntimeBehavior.JUMPTHRU &&\n gdjs.RuntimeObject.collisionTest(\n this.owner,\n platform.owner,\n this._ignoreTouchingEdges\n )\n ) {\n this._overlappedJumpThru.push(platform);\n }\n }\n }\n\n /**\n * Return true if the object is overlapping a ladder.\n * Note: _updatePotentialCollidingObjects must have been called before.\n */\n _isOverlappingLadder() {\n for (let i = 0; i < this._potentialCollidingObjects.length; ++i) {\n const platform = this._potentialCollidingObjects[i];\n if (\n platform.getPlatformType() !== gdjs.PlatformRuntimeBehavior.LADDER\n ) {\n continue;\n }\n\n if (\n gdjs.RuntimeObject.collisionTest(\n this.owner,\n platform.owner,\n this._ignoreTouchingEdges\n )\n ) {\n return true;\n }\n }\n return false;\n }\n\n _isIn(platformArray: gdjs.PlatformRuntimeBehavior[], id: integer) {\n for (let i = 0; i < platformArray.length; ++i) {\n if (platformArray[i].owner.id === id) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Update _potentialCollidingObjects member with platforms near the object.\n */\n private _updatePotentialCollidingObjects(maxMovementLength: float) {\n const object = this.owner;\n\n this._manager.getAllPlatformsAround(\n object,\n maxMovementLength,\n this._potentialCollidingObjects\n );\n\n // Filter the potential colliding platforms to ensure that the object owning the behavior\n // is not considered as colliding with itself, in the case that it also has the\n // platform behavior.\n for (let i = 0; i < this._potentialCollidingObjects.length; ) {\n if (this._potentialCollidingObjects[i].owner === object) {\n this._potentialCollidingObjects.splice(i, 1);\n } else {\n i++;\n }\n }\n }\n\n /**\n * Simulate a control action in the Platformer Object by specifying an input.\n * @param input The string expression of the control action [Left,Right,Up,Down,Ladder,Jump,Release,Release Ladder].\n */\n simulateControl(input: string) {\n if (input === 'Left') {\n this._leftKey = true;\n } else if (input === 'Right') {\n this._rightKey = true;\n } else if (input === 'Up') {\n this._upKey = true;\n } else if (input === 'Down') {\n this._downKey = true;\n } else if (input === 'Ladder') {\n this._ladderKey = true;\n } else if (input === 'Jump') {\n this._jumpKey = true;\n } else if (input === 'Release') {\n this._releasePlatformKey = true;\n } else if (input === 'Release Ladder') {\n this._releaseLadderKey = true;\n }\n }\n\n /**.\n * @param input The control to be tested [Left,Right,Up,Down,Ladder,Jump,Release,Release Ladder].\n * @returns true if the key was used since the last `doStepPreEvents` call.\n */\n isUsingControl(input: string): boolean {\n if (input === 'Left') {\n return this._wasLeftKeyPressed;\n }\n if (input === 'Right') {\n return this._wasRightKeyPressed;\n }\n if (input === 'Up') {\n return this._wasUpKeyPressed;\n }\n if (input === 'Down') {\n return this._wasDownKeyPressed;\n }\n if (input === 'Ladder') {\n return this._wasLadderKeyPressed;\n }\n if (input === 'Jump') {\n return this._wasJumpKeyPressed;\n }\n if (input === 'Release') {\n return this._wasReleasePlatformKeyPressed;\n }\n if (input === 'Release Ladder') {\n return this._wasReleaseLadderKeyPressed;\n }\n return false;\n }\n\n /**\n * Get the gravity of the Platformer Object.\n * @returns The current gravity.\n */\n getGravity(): float {\n return this._gravity;\n }\n\n /**\n * Get maximum angle of a slope for the Platformer Object to run on it as a floor.\n * @returns the slope maximum angle, in degrees.\n */\n getSlopeMaxAngle(): float {\n return this._slopeMaxAngle;\n }\n\n /**\n * Get the maximum falling speed of the Platformer Object.\n * @returns The maximum falling speed.\n */\n getMaxFallingSpeed(): float {\n return this._maxFallingSpeed;\n }\n\n /**\n * Get the speed used to move on Y axis when climbing a ladder.\n * @returns The speed of ladder climbing.\n */\n getLadderClimbingSpeed(): float {\n return this._ladderClimbingSpeed;\n }\n\n /**\n * Get the acceleration value of the Platformer Object.\n * @returns The current acceleration.\n */\n getAcceleration(): float {\n return this._acceleration;\n }\n\n /**\n * Get the deceleration of the Platformer Object.\n * @returns The current deceleration.\n */\n getDeceleration(): float {\n return this._deceleration;\n }\n\n /**\n * Get the maximum speed of the Platformer Object.\n * @returns The maximum speed.\n */\n getMaxSpeed(): float {\n return this._maxSpeed;\n }\n\n /**\n * Get the jump speed of the Platformer Object.\n * @returns The jump speed.\n */\n getJumpSpeed(): float {\n return this._jumpSpeed;\n }\n\n /**\n * Get the jump sustain time of the Platformer Object.\n * @returns The jump sustain time.\n */\n getJumpSustainTime(): float {\n return this._jumpSustainTime;\n }\n\n /**\n * Get the speed at which the object is falling. It is 0 when the object is on a floor, and non 0 as soon as the object leaves the floor.\n * @returns The current fall speed.\n */\n getCurrentFallSpeed(): float {\n return this._currentFallSpeed;\n }\n\n /**\n * Get the current speed of the Platformer Object.\n * @returns The current speed.\n */\n getCurrentSpeed(): float {\n return this._currentSpeed;\n }\n\n /**\n * Set the current speed of the Platformer Object.\n * @param currentSpeed The current speed.\n */\n setCurrentSpeed(currentSpeed: float): void {\n this._currentSpeed = gdjs.evtTools.common.clamp(\n currentSpeed,\n -this._maxSpeed,\n this._maxSpeed\n );\n }\n\n /**\n * Get the current jump speed of the Platformer Object.\n * @returns The current jump speed.\n */\n getCurrentJumpSpeed(): float {\n return this._jumping.getCurrentJumpSpeed();\n }\n\n /**\n * Check if the Platformer Object can grab the platforms.\n * @returns Returns true if the object can grab the platforms.\n */\n canGrabPlatforms(): boolean {\n return this._canGrabPlatforms;\n }\n\n /**\n * Check if the Platformer Object can jump.\n * @returns Returns true if the object can jump.\n */\n canJump(): boolean {\n return this._canJump;\n }\n\n /**\n * Set the gravity of the Platformer Object.\n * @param gravity The new gravity.\n */\n setGravity(gravity: float): void {\n this._gravity = gravity;\n }\n\n /**\n * Set the maximum falling speed of the Platformer Object.\n * @param maxFallingSpeed The maximum falling speed.\n * @param tryToPreserveAirSpeed If true and if jumping, tune the current jump speed to preserve the overall speed in the air.\n */\n setMaxFallingSpeed(\n maxFallingSpeed: float,\n tryToPreserveAirSpeed: boolean = false\n ): void {\n if (tryToPreserveAirSpeed && this._state === this._jumping) {\n // If the falling speed is too high compared to the new max falling speed,\n // reduce it and adapt the jump speed to preserve the overall vertical speed.\n const fallingSpeedOverflow = this._currentFallSpeed - maxFallingSpeed;\n if (fallingSpeedOverflow > 0) {\n this._currentFallSpeed -= fallingSpeedOverflow;\n this._jumping.setCurrentJumpSpeed(\n Math.max(\n 0,\n this._jumping.getCurrentJumpSpeed() - fallingSpeedOverflow\n )\n );\n }\n }\n this._maxFallingSpeed = maxFallingSpeed;\n }\n\n /**\n * Set the speed used to move on Y axis when climbing a ladder.\n * @param ladderClimbingSpeed The speed of ladder climbing.\n */\n setLadderClimbingSpeed(ladderClimbingSpeed: float): void {\n this._ladderClimbingSpeed = ladderClimbingSpeed;\n }\n\n /**\n * Set the acceleration of the Platformer Object.\n * @param acceleration The new acceleration.\n */\n setAcceleration(acceleration: float): void {\n this._acceleration = acceleration;\n }\n\n /**\n * Set the deceleration of the Platformer Object.\n * @param deceleration The new deceleration.\n */\n setDeceleration(deceleration: float): void {\n this._deceleration = deceleration;\n }\n\n /**\n * Set the maximum speed of the Platformer Object.\n * @param maxSpeed The new maximum speed.\n */\n setMaxSpeed(maxSpeed: float): void {\n this._maxSpeed = maxSpeed;\n }\n\n /**\n * Set the jump speed of the Platformer Object.\n * @param jumpSpeed The new jump speed.\n */\n setJumpSpeed(jumpSpeed: float): void {\n this._jumpSpeed = jumpSpeed;\n }\n\n /**\n * Set the jump sustain time of the Platformer Object.\n * @param jumpSustainTime The new jump sustain time.\n */\n setJumpSustainTime(jumpSustainTime: float): void {\n this._jumpSustainTime = jumpSustainTime;\n }\n\n /**\n * Set the maximum slope angle of the Platformer Object.\n * @param slopeMaxAngle The new maximum slope angle.\n */\n setSlopeMaxAngle(slopeMaxAngle: float): void {\n if (slopeMaxAngle < 0 || slopeMaxAngle >= 90) {\n return;\n }\n this._slopeMaxAngle = slopeMaxAngle;\n\n //Avoid rounding errors\n if (slopeMaxAngle === 45) {\n this._slopeClimbingFactor = 1;\n } else {\n this._slopeClimbingFactor = Math.tan(\n (slopeMaxAngle * 3.1415926) / 180.0\n );\n }\n\n // Avoid a `_slopeClimbingFactor` set to exactly 0.\n // Otherwise, this can lead the floor finding functions to consider\n // a floor to be \"too high\" to reach, even if the object is very slightly\n // inside it, which can happen because of rounding errors.\n // See \"Floating-point error mitigations\" tests.\n if (this._slopeClimbingFactor < 1 / 1024) {\n this._slopeClimbingFactor = 1 / 1024;\n }\n }\n\n /**\n * Allow the Platformer Object to jump again.\n */\n setCanJump(): void {\n this._canJump = true;\n }\n\n /**\n * Forbid the Platformer Object to air jump.\n */\n setCanNotAirJump(): void {\n if (this._state === this._jumping || this._state === this._falling) {\n this._canJump = false;\n }\n }\n\n /**\n * Abort the current jump.\n *\n * When the character is not in the jumping state this method has no effect.\n */\n abortJump(): void {\n if (this._state === this._jumping) {\n this._currentFallSpeed = 0;\n this._setFalling();\n }\n }\n\n /**\n * Set the current fall speed.\n *\n * When the character is not in the falling state this method has no effect.\n */\n setCurrentFallSpeed(currentFallSpeed: float) {\n if (this._state === this._falling) {\n this._currentFallSpeed = gdjs.evtTools.common.clamp(\n currentFallSpeed,\n 0,\n this._maxFallingSpeed\n );\n }\n }\n\n /**\n * Set if the Platformer Object can grab platforms.\n * @param enable Enable / Disable grabbing of platforms.\n */\n setCanGrabPlatforms(enable: boolean): void {\n this._canGrabPlatforms = enable;\n if (!this._canGrabPlatforms) {\n this._releaseGrabbedPlatform();\n }\n }\n\n /**\n * Ignore the default controls of the Platformer Object.\n * @param ignore Enable / Disable default controls.\n */\n ignoreDefaultControls(ignore: boolean) {\n this._ignoreDefaultControls = ignore;\n }\n\n /**\n * Check if the default controls of the Platformer Object are ignored.\n * @returns true if the default controls are ignored.\n */\n shouldIgnoreDefaultControls() {\n return (\n this._ignoreDefaultControls ||\n this._ignoreDefaultControlsAsSyncedByNetwork\n );\n }\n\n /**\n * Simulate the \"Left\" control of the Platformer Object.\n */\n simulateLeftKey() {\n this._leftKey = true;\n }\n\n /**\n * Simulate the \"Right\" control of the Platformer Object.\n */\n simulateRightKey() {\n this._rightKey = true;\n }\n\n /**\n * Simulate the \"Ladder\" control of the Platformer Object.\n */\n simulateLadderKey() {\n this._ladderKey = true;\n }\n\n /**\n * Simulate the \"Release Ladder\" control of the Platformer Object.\n */\n simulateReleaseLadderKey() {\n this._releaseLadderKey = true;\n }\n\n /**\n * Simulate the \"Up\" control of the Platformer Object.\n */\n simulateUpKey() {\n this._upKey = true;\n }\n\n /**\n * Simulate the \"Down\" control of the Platformer Object.\n */\n simulateDownKey() {\n this._downKey = true;\n }\n\n /**\n * Simulate the \"Jump\" control of the Platformer Object.\n */\n simulateJumpKey() {\n this._jumpKey = true;\n }\n\n /**\n * Simulate the \"Release\" control of the Platformer Object.\n */\n simulateReleasePlatformKey() {\n this._releasePlatformKey = true;\n }\n\n /**\n * Check if the Platformer Object is on a floor.\n * @returns Returns true if on a floor and false if not.\n */\n isOnFloor(): boolean {\n return this._state === this._onFloor;\n }\n\n /**\n * Check if the Platformer Object is on the given object.\n * @returns Returns true if on the object and false if not.\n */\n isOnFloorObject(object: gdjs.RuntimeObject): boolean {\n if (this.isOnFloor()) {\n const floorPlatform = this._onFloor.getFloorPlatform();\n return !!floorPlatform && floorPlatform.owner.id === object.id;\n }\n return false;\n }\n\n /**\n * Check if the Platformer Object is on a ladder.\n * @returns Returns true if on a ladder and false if not.\n */\n isOnLadder(): boolean {\n return this._state === this._onLadder;\n }\n\n /**\n * Check if the Platformer Object is jumping.\n * @returns Returns true if jumping and false if not.\n */\n isJumping(): boolean {\n return this._state === this._jumping;\n }\n\n /**\n * Check if the Platformer Object is grabbing a platform.\n * @returns Returns true if a platform is grabbed and false if not.\n */\n isGrabbingPlatform(): boolean {\n return this._state === this._grabbingPlatform;\n }\n\n /**\n * Check if the Platformer Object is in the falling state. This is false\n * if the object is jumping, even if the object is going down after reaching\n * the jump peak.\n * @returns Returns true if it is falling and false if not.\n */\n isFallingWithoutJumping(): boolean {\n return this._state === this._falling;\n }\n\n /**\n * Check if the Platformer Object is \"going down\", either because it's in the\n * falling state *or* because it's jumping but reached the jump peak and\n * is now going down (because the jump speed can't compensate anymore the\n * falling speed).\n *\n * If you want to check if the object is falling outside of a jump (or because\n * the jump is entirely finished and there is no jump speed applied to the object\n * anymore), consider using `isFallingWithoutJumping`.\n *\n * @returns Returns true if it is \"going down\" and false if not.\n */\n isFalling(): boolean {\n return (\n this._state === this._falling ||\n (this._state === this._jumping &&\n this._currentFallSpeed > this._jumping.getCurrentJumpSpeed())\n );\n }\n\n /**\n * Check if the Platformer Object is moving.\n *\n * When walking or climbing on a ladder,\n * a speed of less than one pixel per frame won't be detected.\n *\n * @returns Returns true if it is moving and false if not.\n * @deprecated use isMovingEvenALittle instead\n */\n isMoving(): boolean {\n return (\n (this._hasMovedAtLeastOnePixel &&\n (this._currentSpeed !== 0 || this._state === this._onLadder)) ||\n this._jumping.getCurrentJumpSpeed() !== 0 ||\n this._currentFallSpeed !== 0\n );\n }\n\n /**\n * Check if the Platformer Object is moving.\n * @returns Returns true if it is moving and false if not.\n */\n isMovingEvenALittle(): boolean {\n return (\n (this._hasReallyMoved &&\n (this._currentSpeed !== 0 || this._state === this._onLadder)) ||\n this._jumping.getCurrentJumpSpeed() !== 0 ||\n this._currentFallSpeed !== 0\n );\n }\n }\n\n /**\n * The object can take 5 states: OnFloor, Falling, Jumping, GrabbingPlatform and OnLadder.\n * The implementations of this interface hold the specific behaviors and internal state of theses 5 states.\n * @see PlatformerObjectRuntimeBehavior.doStepPreEvents to understand how the functions are called.\n */\n interface State {\n /**\n * Called when the object leaves this state.\n * It's a good place to reset the internal state.\n * @see OnFloor.enter that is not part of the interface because it takes specific parameters.\n */\n leave(): void;\n /**\n * Called before the obstacle search.\n * The object position may need adjustments to handle external changes.\n */\n beforeUpdatingObstacles(timeDelta: float): void;\n /**\n * Check if transitions to other states are needed and apply them before moving horizontally.\n */\n checkTransitionBeforeX(): void;\n /**\n * Use _requestedDeltaX and _requestedDeltaY to choose the movement that suits the state before moving horizontally.\n */\n beforeMovingX(): void;\n /**\n * Check if transitions to other states are needed and apply them before moving vertically.\n */\n checkTransitionBeforeY(timeDelta: float): void;\n /**\n * Use _requestedDeltaY to choose the movement that suits the state before moving vertically.\n */\n beforeMovingY(timeDelta: float, oldX: float): void;\n\n getNetworkSyncData(): StateNetworkSyncData;\n\n updateFromNetworkSyncData(syncData: StateNetworkSyncData): void;\n }\n\n /**\n * The object is on the floor standing or walking.\n *\n * Also see {@link ./README.md}\n */\n class OnFloor implements State {\n private _behavior: PlatformerObjectRuntimeBehavior;\n private _floorPlatform: gdjs.PlatformRuntimeBehavior | null = null;\n private _floorPolygon: gdjs.Polygon | null = null;\n private _floorLastX: float = 0;\n private _floorLastY: float = 0;\n _oldHeight: float = 0;\n\n constructor(behavior: PlatformerObjectRuntimeBehavior) {\n this._behavior = behavior;\n }\n\n getFloorPlatform() {\n return this._floorPlatform;\n }\n\n getFloorPolygon() {\n return this._floorPolygon;\n }\n\n enter(\n floorPlatform: gdjs.PlatformRuntimeBehavior,\n floorPolygon: gdjs.Polygon\n ) {\n this._floorPlatform = floorPlatform;\n this._floorPolygon = floorPolygon;\n this.updateFloorPosition();\n this._behavior._canJump = true;\n this._behavior._currentFallSpeed = 0;\n }\n\n leave() {\n this._floorPlatform = null;\n this._floorPolygon = null;\n }\n\n updateFloorPosition() {\n this._floorLastX = this._floorPlatform!.owner.getX();\n this._floorLastY = this._floorPlatform!.owner.getY();\n }\n\n beforeUpdatingObstacles(timeDelta: float) {\n const object = this._behavior.owner;\n // Stick the object to the floor if its height has changed.\n if (this._oldHeight !== object.getHeight()) {\n // TODO This should probably be done after the events because\n // the character stays at the wrong place during 1 frame.\n const deltaY =\n ((this._oldHeight - object.getHeight()) *\n (object.getHeight() + object.getDrawableY() - object.getY())) /\n object.getHeight();\n object.setY(object.getY() + deltaY);\n }\n // Directly follow the floor movement on the Y axis by moving the character.\n // For the X axis, we follow the floor movement using `_requestedDeltaX`\n // (see `beforeMovingX`).\n // We don't use `_requestedDeltaY` to follow the floor on the Y axis\n // to avoid a transition loop with the Falling state.\n // Indeed, if we used it, then:\n // - going down, the character could no longer be on a platform and start falling.\n // - going up, the character will already be pushed on top on the platform\n // by `beforeMovingY` that handle slopes or by `_separateFromPlatforms` that\n // avoid characters being stuck. So using `_requestedDeltaY`, the character\n // would be going too much higher and fall at the next frame.\n //\n // We could make the character follow a platform moving up\n // at a greater speed as it's coherent from a physics point of view.\n // But, when the character is put on top of the platform to follow it up,\n // the platform AABB may not be updated in RBush yet\n // and the platform can go out of the spatial search rectangle\n // even though they are next to each other, which means\n // that the character will fall.\n const deltaY = this._floorPlatform!.owner.getY() - this._floorLastY;\n if (\n deltaY !== 0 &&\n Math.abs(deltaY) <=\n Math.abs(this._behavior._maxFallingSpeed * timeDelta)\n ) {\n object.setY(object.getY() + deltaY);\n }\n }\n\n checkTransitionBeforeX() {\n const behavior = this._behavior;\n // Check that the floor object still exists and is near the object.\n if (\n !behavior._isIn(\n behavior._potentialCollidingObjects,\n this._floorPlatform!.owner.id\n )\n ) {\n behavior._setFalling();\n } else if (\n this._behavior._downKey &&\n this._floorPlatform!._platformType ===\n gdjs.PlatformRuntimeBehavior.JUMPTHRU &&\n behavior._canGoDownFromJumpthru\n ) {\n behavior._overlappedJumpThru.push(this._floorPlatform!);\n behavior._setFalling();\n }\n\n // It was originally in checkTransitionBeforeY.\n // The character is ignoring the floor when moving on X to be able to\n // follow up a slope when moving Y (it enter inside it).\n // When the current floor and the wall the character is facing is part of\n // the same instance, the wall is also ignored when moving on X, but the\n // wall is too high to follow and it is seen as colliding an obstacle\n // from behind.\n // Moving against a wall before jumping in this configuration was making\n // jumps being aborted.\n behavior._checkTransitionJumping();\n }\n\n beforeMovingX() {\n const behavior = this._behavior;\n // Shift the object according to the floor movement.\n behavior._requestedDeltaX +=\n this._floorPlatform!.owner.getX() - this._floorLastX;\n // See `beforeUpdatingObstacles` for the logic for the Y axis.\n }\n\n checkTransitionBeforeY(timeDelta: float) {\n const behavior = this._behavior;\n // Go on a ladder\n behavior._checkTransitionOnLadder();\n }\n\n beforeMovingY(timeDelta: float, oldX: float) {\n const behavior = this._behavior;\n const object = behavior.owner;\n\n if (object.getX() === oldX + behavior._requestedDeltaX) {\n // The character didn't encounter any obstacles on the X axis.\n // It follows the floor.\n\n // In theory, this max delta on the Y axis could be 0. In practice,\n // `behavior._slopeClimbingFactor` has a lower bound of 1 / 1024.\n // This avoids this max delta Y to be strictly 0, which would then risk\n // considering a floor \"too high\", even if the object is inside it because\n // of a very small rounding error.\n // See \"Floating-point error mitigations\" tests.\n const deltaMaxY = Math.abs(\n behavior._requestedDeltaX * behavior._slopeClimbingFactor\n );\n const {\n highestGroundPlatform,\n highestGroundPolygon,\n isCollidingAnyPlatform,\n } = behavior._findHighestFloorAndMoveOnTop(\n behavior._potentialCollidingObjects,\n -deltaMaxY,\n deltaMaxY\n );\n if (\n highestGroundPlatform &&\n highestGroundPolygon &&\n (highestGroundPlatform !== this._floorPlatform ||\n highestGroundPolygon !== this._floorPolygon)\n ) {\n behavior._setOnFloor(highestGroundPlatform, highestGroundPolygon);\n }\n if (highestGroundPlatform === null && isCollidingAnyPlatform) {\n // Unable to follow the floor (too steep): go back to the original position.\n behavior.owner.setX(oldX);\n }\n } else {\n // The character encountered an obstacle on the X axis.\n // Try to walk on it or stop before it.\n\n // Try to follow the platform until the obstacle.\n const {\n highestGroundPlatform: highestGroundOnPlatform,\n isCollidingAnyPlatform,\n } = behavior._findHighestFloorAndMoveOnTop(\n behavior._potentialCollidingObjects,\n Math.min(\n 0,\n -Math.abs(object.getX() - oldX) * behavior._slopeClimbingFactor\n ),\n 0\n );\n if (highestGroundOnPlatform === null && isCollidingAnyPlatform) {\n // Unable to follow the floor (too steep): go back to the original position.\n behavior.owner.setX(oldX);\n } else {\n const requestedDeltaX = behavior._requestedDeltaX;\n // The current platform is climbed.\n // Can the obstacle be climbed too from here?\n // We do a look-up in 2 steps:\n // 1. Try to move 1 pixel on X to climb the junction\n // (because the obstacle detection is done 1 pixel by 1 pixel).\n // 2. Try to follow the obstacle slope by at least 1 pixel on X axis\n // (it can only be done after the junction because otherwise\n // the slope angle would be a mean between the current platform and\n // the obstacles).\n //\n // The 2nd step is done using a 1 pixel width at least, when remainingDeltaX\n // is less than 2 pixels: this will be a \"lookahead\". This is to ensure\n // the character doesn't start to climb a slope it actually can't.\n const remainingDeltaX = requestedDeltaX - (object.getX() - oldX);\n const beforeObstacleY = object.getY();\n const beforeObstacleX = object.getX();\n\n // 1. Try to move 1 pixel on the X axis to climb the junction.\n object.setX(object.getX() + Math.sign(requestedDeltaX));\n const { highestGroundPlatform: highestGroundAtJunction } =\n behavior._findHighestFloorAndMoveOnTop(\n behavior._potentialCollidingObjects,\n // Look up from at least 1 pixel to bypass not perfectly aligned floors.\n Math.min(-1, -1 * behavior._slopeClimbingFactor),\n 0\n );\n if (highestGroundAtJunction) {\n // The obstacle 1st pixel can be climbed.\n // Now that the character is on the obstacle,\n // try to follow the slope for at least 1 pixel.\n const deltaX =\n Math.sign(requestedDeltaX) *\n Math.max(\n 1,\n // - 1, because the owner moved from 1 pixel at the junction.\n Math.abs(remainingDeltaX) - 1\n );\n object.setX(object.getX() + deltaX);\n const {\n highestGroundPlatform: highestGroundOnObstacle,\n highestGroundPolygon,\n } = behavior._findHighestFloorAndMoveOnTop(\n behavior._potentialCollidingObjects,\n // Do an exact slope angle check.\n -Math.abs(deltaX) * behavior._slopeClimbingFactor,\n 0\n );\n if (highestGroundOnObstacle && highestGroundPolygon) {\n // The obstacle slope can be climbed.\n if (Math.abs(remainingDeltaX) >= 2) {\n behavior._setOnFloor(\n highestGroundOnObstacle,\n highestGroundPolygon\n );\n } else {\n // We went too far in order to check that.\n // Now, find the right position on the obstacles.\n object.setPosition(oldX + requestedDeltaX, beforeObstacleY);\n const { highestGroundPlatform: highestGroundOnObstacle } =\n behavior._findHighestFloorAndMoveOnTop(\n behavior._potentialCollidingObjects,\n // requestedDeltaX can be small when the object start moving.\n // So, look up from at least 1 pixel to bypass not perfectly aligned floors.\n Math.min(\n -1,\n -Math.abs(remainingDeltaX) * behavior._slopeClimbingFactor\n ),\n 0\n );\n // Should always be true\n if (highestGroundOnObstacle && highestGroundPolygon) {\n behavior._setOnFloor(\n highestGroundOnObstacle,\n highestGroundPolygon\n );\n }\n }\n } else {\n // Don't climb on the obstacle\n // because the obstacle slope is too steep.\n if (\n Math.sign(beforeObstacleX - oldX) === Math.sign(requestedDeltaX)\n ) {\n object.setPosition(beforeObstacleX, beforeObstacleY);\n } else {\n // Avoid to go backward\n object.setPosition(oldX, beforeObstacleY);\n }\n behavior._currentSpeed = 0;\n }\n } else {\n // Don't climb on the obstacle\n // because the obstacle 1st pixel is more than 1 pixel high (or too steep).\n if (\n Math.sign(beforeObstacleX - oldX) === Math.sign(requestedDeltaX)\n ) {\n object.setPosition(beforeObstacleX, beforeObstacleY);\n } else {\n // Avoid to go backward\n object.setPosition(oldX, beforeObstacleY);\n }\n behavior._currentSpeed = 0;\n }\n }\n }\n }\n\n getNetworkSyncData(): OnFloorStateNetworkSyncData {\n return {\n flx: this._floorLastX,\n fly: this._floorLastY,\n oh: this._oldHeight,\n };\n }\n\n updateFromNetworkSyncData(data: OnFloorStateNetworkSyncData) {\n this._floorLastX = data.flx;\n this._floorLastY = data.fly;\n this._oldHeight = data.oh;\n }\n\n toString(): String {\n return 'OnFloor';\n }\n }\n\n /**\n * The object is falling.\n */\n class Falling implements State {\n private _behavior: PlatformerObjectRuntimeBehavior;\n\n constructor(behavior: PlatformerObjectRuntimeBehavior) {\n this._behavior = behavior;\n }\n\n enter(from: State) {\n // Only forbid jumping when starting to fall from a platform,\n // not when falling during a jump. This is because the Jumping\n // state has already set `_canJump` to false and we don't want to reset\n // it again because it could have been set back to `true` to allow\n // for an \"air jump\".\n // Transition from Falling to Falling state should not happen,\n // but don't change anything if this ever happen.\n if (from !== this._behavior._jumping && from !== this) {\n this._behavior._canJump = false;\n }\n }\n\n leave() {}\n\n beforeUpdatingObstacles(timeDelta: float) {}\n\n checkTransitionBeforeX() {}\n\n beforeMovingX() {}\n\n checkTransitionBeforeY(timeDelta: float) {\n const behavior = this._behavior;\n // Go on a ladder\n behavior._checkTransitionOnLadder();\n // Jumping\n behavior._checkTransitionJumping();\n\n // Grabbing a platform\n if (\n behavior._canGrabPlatforms &&\n (behavior._requestedDeltaX !== 0 || behavior._canGrabWithoutMoving)\n ) {\n behavior._checkGrabPlatform();\n }\n }\n\n beforeMovingY(timeDelta: float, oldX: float) {\n //Fall\n this._behavior._fall(timeDelta);\n }\n\n getNetworkSyncData(): FallingStateNetworkSyncData {\n return {};\n }\n\n updateFromNetworkSyncData(data: FallingStateNetworkSyncData) {}\n\n toString(): String {\n return 'Falling';\n }\n }\n\n /**\n * The object is on the ascending and descending part of the jump.\n * The object is considered falling when the jump continue to a lower position than the initial one.\n */\n class Jumping implements State {\n private _behavior: PlatformerObjectRuntimeBehavior;\n private _currentJumpSpeed: number = 0;\n private _timeSinceCurrentJumpStart: number = 0;\n private _jumpingFirstDelta: boolean = false;\n\n constructor(behavior: PlatformerObjectRuntimeBehavior) {\n this._behavior = behavior;\n }\n\n getCurrentJumpSpeed() {\n return this._currentJumpSpeed;\n }\n\n setCurrentJumpSpeed(currentJumpSpeed: number) {\n this._currentJumpSpeed = currentJumpSpeed;\n }\n\n enter(from: State) {\n const behavior = this._behavior;\n this._timeSinceCurrentJumpStart = 0;\n behavior._jumpKeyHeldSinceJumpStart = true;\n\n if (from !== behavior._jumping && from !== behavior._falling) {\n this._jumpingFirstDelta = true;\n }\n\n behavior._canJump = false;\n this._currentJumpSpeed = behavior._jumpSpeed;\n behavior._currentFallSpeed = 0;\n }\n\n leave() {\n this._currentJumpSpeed = 0;\n }\n\n beforeUpdatingObstacles(timeDelta: float) {}\n\n checkTransitionBeforeX() {}\n\n beforeMovingX() {}\n\n checkTransitionBeforeY(timeDelta: float) {\n const behavior = this._behavior;\n // Go on a ladder\n behavior._checkTransitionOnLadder();\n // Jumping\n behavior._checkTransitionJumping();\n\n // Grabbing a platform\n if (\n behavior._canGrabPlatforms &&\n (behavior._requestedDeltaX !== 0 || behavior._canGrabWithoutMoving) &&\n behavior._lastDeltaY >= 0\n ) {\n behavior._checkGrabPlatform();\n }\n }\n\n beforeMovingY(timeDelta: float, oldX: float) {\n const behavior = this._behavior;\n\n this._timeSinceCurrentJumpStart += timeDelta;\n\n const previousJumpSpeed = this._currentJumpSpeed;\n // Decrease jump speed after the (optional) jump sustain time is over.\n const sustainJumpSpeed =\n behavior._jumpKeyHeldSinceJumpStart &&\n this._timeSinceCurrentJumpStart < behavior._jumpSustainTime;\n if (!sustainJumpSpeed) {\n this._currentJumpSpeed -= behavior._gravity * timeDelta;\n }\n\n if (this._behavior._useLegacyTrajectory) {\n behavior._requestedDeltaY -= previousJumpSpeed * timeDelta;\n\n // Fall\n // The condition is a legacy thing.\n // There is no actual reason not to fall at 1st frame.\n // Before a refactoring, it used to not be this obvious.\n if (!this._jumpingFirstDelta) {\n behavior._fall(timeDelta);\n }\n } else {\n // Use Verlet integration.\n behavior._requestedDeltaY +=\n ((-previousJumpSpeed - this._currentJumpSpeed) / 2) * timeDelta;\n\n // Fall\n behavior._fall(timeDelta);\n }\n this._jumpingFirstDelta = false;\n\n if (this._currentJumpSpeed < 0) {\n behavior._setFalling();\n }\n }\n\n getNetworkSyncData(): JumpingStateNetworkSyncData {\n return {\n cjs: this._currentJumpSpeed,\n tscjs: this._timeSinceCurrentJumpStart,\n jfd: this._jumpingFirstDelta,\n };\n }\n\n updateFromNetworkSyncData(data: JumpingStateNetworkSyncData) {\n this._currentJumpSpeed = data.cjs;\n this._timeSinceCurrentJumpStart = data.tscjs;\n this._jumpingFirstDelta = data.jfd;\n }\n\n toString(): String {\n return 'Jumping';\n }\n }\n\n /**\n * The object grabbed the edge of a platform and is standing there.\n */\n class GrabbingPlatform implements State {\n private _behavior: PlatformerObjectRuntimeBehavior;\n private _grabbedPlatform: any = null;\n private _grabbedPlatformLastX: any;\n private _grabbedPlatformLastY: any;\n\n constructor(behavior: PlatformerObjectRuntimeBehavior) {\n this._behavior = behavior;\n }\n\n enter(grabbedPlatform: gdjs.PlatformRuntimeBehavior) {\n this._grabbedPlatform = grabbedPlatform;\n this._behavior._canJump = true;\n this._behavior._currentFallSpeed = 0;\n }\n\n leave() {\n this._grabbedPlatform = null;\n }\n\n beforeUpdatingObstacles(timeDelta: float) {}\n\n checkTransitionBeforeX() {\n const behavior = this._behavior;\n //Check that the grabbed platform object still exists and is near the object.\n if (\n !behavior._isIn(\n behavior._potentialCollidingObjects,\n this._grabbedPlatform.owner.id\n )\n ) {\n behavior._releaseGrabbedPlatform();\n }\n }\n\n beforeMovingX() {\n const behavior = this._behavior;\n //Shift the object according to the grabbed platform movement.\n // this erases any other movement\n behavior._requestedDeltaX =\n this._grabbedPlatform.owner.getX() - this._grabbedPlatformLastX;\n behavior._requestedDeltaY =\n this._grabbedPlatform.owner.getY() - this._grabbedPlatformLastY;\n }\n\n checkTransitionBeforeY(timeDelta: float) {\n const behavior = this._behavior;\n //Go on a ladder\n behavior._checkTransitionOnLadder();\n\n //Release the platform\n if (behavior._releasePlatformKey) {\n behavior._releaseGrabbedPlatform();\n }\n\n //Jumping\n behavior._checkTransitionJumping();\n }\n\n beforeMovingY(timeDelta: float, oldX: float) {\n this._grabbedPlatformLastX = this._grabbedPlatform.owner.getX();\n this._grabbedPlatformLastY = this._grabbedPlatform.owner.getY();\n }\n\n getNetworkSyncData(): GrabbingPlatformStateNetworkSyncData {\n return {\n gplx: this._grabbedPlatformLastX,\n gply: this._grabbedPlatformLastY,\n };\n }\n\n updateFromNetworkSyncData(data: GrabbingPlatformStateNetworkSyncData) {\n this._grabbedPlatformLastX = data.gplx;\n this._grabbedPlatformLastY = data.gply;\n }\n\n toString(): String {\n return 'GrabbingPlatform';\n }\n }\n\n /**\n * The object grabbed a ladder. It can stand or move in 8 directions.\n */\n class OnLadder implements State {\n private _behavior: PlatformerObjectRuntimeBehavior;\n\n constructor(behavior: PlatformerObjectRuntimeBehavior) {\n this._behavior = behavior;\n }\n\n enter() {\n this._behavior._canJump = true;\n this._behavior._currentFallSpeed = 0;\n }\n\n leave() {}\n\n beforeUpdatingObstacles(timeDelta: float) {}\n\n checkTransitionBeforeX() {}\n\n beforeMovingX() {}\n\n checkTransitionBeforeY(timeDelta: float) {\n const behavior = this._behavior;\n //Coming to an extremity of a ladder\n if (!behavior._isOverlappingLadder()) {\n behavior._setFalling();\n }\n\n //Jumping\n behavior._checkTransitionJumping();\n\n //Release the ladder\n if (behavior._releaseLadderKey) {\n behavior._releaseLadder();\n }\n }\n\n beforeMovingY(timeDelta: float, oldX: float) {\n const behavior = this._behavior;\n\n // TODO: we could consider supporting acceleration for ladder climbing in the future.\n if (behavior._upKey) {\n behavior._requestedDeltaY -= behavior._ladderClimbingSpeed * timeDelta;\n }\n if (behavior._downKey) {\n behavior._requestedDeltaY += behavior._ladderClimbingSpeed * timeDelta;\n }\n }\n\n getNetworkSyncData(): OnLadderStateNetworkSyncData {\n return {};\n }\n\n updateFromNetworkSyncData(data: OnLadderStateNetworkSyncData) {}\n\n toString(): String {\n return 'OnLadder';\n }\n }\n\n /**\n * A context used to search for a floor.\n */\n class FollowConstraintContext {\n static readonly instance: FollowConstraintContext =\n new FollowConstraintContext();\n /**\n * Character right side\n *\n * (constant to a search)\n */\n ownerMinX: float = 0;\n /**\n * Character left side\n *\n * (constant to a search)\n */\n ownerMaxX: float = 0;\n /**\n * The maximum top position the character top can go.\n *\n * (constant to a search)\n */\n headMinY: float = 0;\n /**\n * Character top\n *\n * (constant to a search)\n */\n ownerMinY: float = 0;\n /**\n * The maximum bottom position the character top can go.\n *\n * (constant to a search)\n */\n headMaxY: float = 0;\n /**\n * The maximum top position the character bottom can go.\n *\n * (constant to a search)\n */\n floorMinY: float = 0;\n /**\n * Character bottom\n *\n * (constant to a search)\n */\n ownerMaxY: float = 0;\n /**\n * The maximum bottom position the character bottom can go.\n *\n * (constant to a search)\n */\n floorMaxY: float = 0;\n\n /**\n * The minimum upward delta according to already checked platforms.\n *\n * (a result of the search)\n */\n allowedMinDeltaY: float = 0;\n /**\n * The maximum downward delta according to already checked platforms.\n *\n * (a result of the search)\n */\n allowedMaxDeltaY: float = 0;\n\n /**\n * True if any edge has been found over where the character top can go (downward).\n *\n * It allows to check for encompassing platforms.\n *\n * (local to one hitbox check)\n */\n foundOverHead: boolean = false;\n /**\n * True if any edge has been found under where the character bottom can go (upward).\n *\n * It allows to check for encompassing platforms.\n *\n * (local to one hitbox check)\n */\n foundUnderBottom: boolean = false;\n\n highestFloorPolygon: gdjs.Polygon | null = null;\n\n initializeBeforeSearch(\n behavior: PlatformerObjectRuntimeBehavior,\n upwardDeltaY: float,\n downwardDeltaY: float\n ) {\n let ownerMinX = Number.MAX_VALUE;\n let ownerMaxX = -Number.MAX_VALUE;\n let ownerMinY = Number.MAX_VALUE;\n let ownerMaxY = -Number.MAX_VALUE;\n for (const hitBox of behavior.owner.getHitBoxes()) {\n for (const vertex of hitBox.vertices) {\n ownerMinX = Math.min(ownerMinX, vertex[0]);\n ownerMaxX = Math.max(ownerMaxX, vertex[0]);\n ownerMinY = Math.min(ownerMinY, vertex[1]);\n ownerMaxY = Math.max(ownerMaxY, vertex[1]);\n }\n }\n\n this.ownerMinX = ownerMinX;\n this.ownerMaxX = ownerMaxX;\n this.headMinY = ownerMinY + upwardDeltaY;\n this.ownerMinY = ownerMinY;\n this.headMaxY = ownerMinY + downwardDeltaY;\n this.floorMinY = ownerMaxY + upwardDeltaY;\n this.ownerMaxY = ownerMaxY;\n this.floorMaxY = ownerMaxY + downwardDeltaY;\n\n this.allowedMinDeltaY = upwardDeltaY;\n // Number.MAX_VALUE and not downwardDeltaY\n // because it would means that a platform was found.\n // see isCollidingAnyPlatform()\n this.allowedMaxDeltaY = Number.MAX_VALUE;\n }\n\n initializeBeforeHitboxCheck() {\n this.foundOverHead = false;\n this.foundUnderBottom = false;\n }\n\n /**\n * Revert the search variables to a given state.\n *\n * This is used to revert side effect of jumpthru check.\n * @param previousAllowedMinDeltaY\n * @param previousAllowedMaxDeltaY\n */\n revertTo(previousAllowedMinDeltaY: float, previousAllowedMaxDeltaY: float) {\n // Other members are either constants or local to an hitbox search.\n this.allowedMinDeltaY = previousAllowedMinDeltaY;\n this.allowedMaxDeltaY = previousAllowedMaxDeltaY;\n }\n\n setFloorIsTooHigh() {\n this.allowedMinDeltaY = Number.MAX_VALUE;\n this.allowedMaxDeltaY = -Number.MAX_VALUE;\n }\n\n floorIsTooHigh(): boolean {\n // Return true when the 2 constraints are incompatible.\n return this.allowedMinDeltaY > this.allowedMaxDeltaY;\n }\n\n isCollidingAnyPlatform(): boolean {\n return this.ownerMaxY + this.allowedMaxDeltaY <= this.floorMaxY;\n }\n\n getFloorDeltaY(): float {\n return this.allowedMaxDeltaY;\n }\n\n /**\n * Check if the character can follow a given Y or move not to touch it\n * and update the context with this new constraint.\n * @param y\n */\n addPointConstraint(y: float, sourcePolygon: gdjs.Polygon): void {\n if (y < this.floorMinY) {\n // The platform is too high to walk on...\n if (y > this.headMaxY) {\n // ...but not over the object.\n this.setFloorIsTooHigh();\n return;\n }\n // ...but over the object.\n this.foundOverHead = true;\n if (this.foundUnderBottom) {\n // The current hitbox is below and above at the same time.\n // As hitboxes are convex, the platform overlaps the character.\n this.setFloorIsTooHigh();\n return;\n }\n // When there is a platform on the top,\n // the character is constraint on how high\n // he can follow a floor.\n this.allowedMinDeltaY = Math.max(\n this.allowedMinDeltaY,\n y - this.ownerMinY\n );\n } else {\n // The platform can be walked on.\n this.foundUnderBottom = true;\n if (this.foundOverHead) {\n // The current hitbox is below and above at the same time.\n // As hitboxes are convex, the platform overlaps the character.\n this.setFloorIsTooHigh();\n return;\n }\n // Add the vertex to the constraints.\n // When there is a platform on the bottom,\n // the character is constraint on how low\n // he can follow a floor.\n this.allowedMaxDeltaY = Math.min(\n this.allowedMaxDeltaY,\n y - this.ownerMaxY\n );\n this.highestFloorPolygon = sourcePolygon;\n }\n }\n }\n\n gdjs.registerBehavior(\n 'PlatformBehavior::PlatformerObjectBehavior',\n gdjs.PlatformerObjectRuntimeBehavior\n );\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }