From 6ca67bd3448a7a6ab47b5d74b6f5b37982a35321 Mon Sep 17 00:00:00 2001 From: D8H Date: Sat, 27 Jul 2024 18:12:26 +0200 Subject: [PATCH] [Reviewed] [Pixel perfect] Use the new syntax (#1341) - Don't show in changelog --- extensions/reviewed/PixelPerfectMovement.json | 1014 ++++++++--------- 1 file changed, 488 insertions(+), 526 deletions(-) diff --git a/extensions/reviewed/PixelPerfectMovement.json b/extensions/reviewed/PixelPerfectMovement.json index 8fa5795d..87e76794 100644 --- a/extensions/reviewed/PixelPerfectMovement.json +++ b/extensions/reviewed/PixelPerfectMovement.json @@ -8,7 +8,7 @@ "name": "PixelPerfectMovement", "previewIconUrl": "https://resources.gdevelop-app.com/assets/Icons/Line Hero Pack/Master/SVG/Graphic Design/Graphic Design_grid.svg", "shortDescription": "Grid-based or pixel perfect platformer and top-down movements.", - "version": "0.2.0", + "version": "0.2.1", "description": [ "Games with pixel art usually use pixels bigger than actual pixels of the screen. This can lead to big pixels partially overlapping each other which doesn't look good.", "", @@ -36,6 +36,8 @@ "mMR36hCjO5dlcYmhNSuVtcREM473" ], "dependencies": [], + "globalVariables": [], + "sceneVariables": [], "eventsFunctions": [ { "description": "Return the speed necessary to cover a distance according to the deceleration.", @@ -53,7 +55,7 @@ "value": "BuiltinCommonInstructions::CompareNumbers" }, "parameters": [ - "GetArgumentAsNumber(\"Distance\")", + "Distance", ">=", "0" ] @@ -65,7 +67,7 @@ "value": "SetReturnNumber" }, "parameters": [ - "sqrt(2 * GetArgumentAsNumber(\"Distance\") * GetArgumentAsNumber(\"Deceleration\"))" + "sqrt(2 * Distance * Deceleration)" ] } ] @@ -78,7 +80,7 @@ "value": "BuiltinCommonInstructions::CompareNumbers" }, "parameters": [ - "GetArgumentAsNumber(\"Distance\")", + "Distance", "<", "0" ] @@ -90,7 +92,7 @@ "value": "SetReturnNumber" }, "parameters": [ - "-sqrt(-2 * GetArgumentAsNumber(\"Distance\") * GetArgumentAsNumber(\"Deceleration\"))" + "-sqrt(-2 * Distance * Deceleration)" ] } ] @@ -130,7 +132,7 @@ "value": "SetReturnNumber" }, "parameters": [ - "GetArgumentAsNumber(\"Speed\") * GetArgumentAsNumber(\"Speed\") / (2 * GetArgumentAsNumber(\"Deceleration\"))" + "Speed * Speed / (2 * Deceleration)" ] } ] @@ -162,482 +164,457 @@ "sentence": "Define JavaScript classes for top-down", "events": [ { - "type": "BuiltinCommonInstructions::Standard", - "conditions": [ - { - "type": { - "value": "GlobalVariableAsBoolean" - }, - "parameters": [ - "__pixelPerfect.TopDownClassesDefined", - "" - ] - } + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__pixelPerfectExtension) {", + " return;", + "}", + "", + "const epsilon = 1 / (1 << 20);", + "", + "class PixelPerfectTopDownMovement {", + "", + " /**", + " * @param {gdjs.RuntimeBehavior} pixelPerfectBehavior", + " * @param {gdjs.TopDownMovementRuntimeBehavior} topDownBehavior", + " */", + " constructor(pixelPerfectBehavior, topDownBehavior) {", + " /** @type {gdjs.RuntimeBehavior} */", + " this.pixelPerfectBehavior = pixelPerfectBehavior;", + " /** @type {gdjs.TopDownMovementRuntimeBehavior} */", + " this.topDownBehavior = topDownBehavior;", + "", + " topDownBehavior.registerHook(this);", + "", + " /** @type {number | null} */", + " this.targetX = null;", + " /** @type {number | null} */", + " this.targetY = null;", + " this.targetDirectionX = 0;", + " this.targetDirectionY = 0;", + " this.lastDirection = -1;", + " this.isVelocityAdjusted = false;", + " this.isVelocityAdjustedOnX = false;", + " this.isVelocityAdjustedOnY = false;", + " }", + "", + " /**", + " * Return the direction to use instead of the direction given in", + " * parameter.", + " * @param {gdjs.TopDownMovementRuntimeBehavior.TopDownMovementHookContext} context", + " * @return {number}", + " */", + " overrideDirection(context) {", + " let direction = context.getDirection();", + " if (!this.pixelPerfectBehavior.activated()) {", + " return direction;", + " }", + "", + " /** @type {number} */", + " const cellSize = this.pixelPerfectBehavior._getPixelSize();", + " const that = this.topDownBehavior;", + " const object = that.owner;", + "", + " if (cellSize <= 0 || that._allowDiagonals) {", + " return direction;", + " }", + "", + " // Forbid to turn before being aligned on the grid.", + "", + " const timeDelta = object.getElapsedTime() / 1000;", + " const deltaX = Math.abs(that._xVelocity * timeDelta);", + " const deltaY = Math.abs(that._yVelocity * timeDelta);", + "", + " const isTryingToMoveOnX = direction === 4 || direction === 0;", + " const isTryingToMoveOnY = direction === 6 || direction === 2;", + " if (isTryingToMoveOnX) {", + " if (that._yVelocity < 0) {", + " if (Math.abs(this.ceilToCellY(object.y) - object.y) > deltaY) {", + " direction = 6;", + " } else {", + " object.y = this.ceilToCellY(object.y);", + " }", + " }", + " if (that._yVelocity > 0) {", + " if (Math.abs(this.floorToCellY(object.y) - object.y) > deltaY) {", + " direction = 2;", + " } else {", + " object.y = this.floorToCellY(object.y);", + " }", + " }", + " } else if (isTryingToMoveOnY) {", + " if (that._xVelocity < 0) {", + " if (Math.abs(this.ceilToCellX(object.x) - object.x) > deltaX) {", + " direction = 4;", + " } else {", + " object.x = this.ceilToCellX(object.x);", + " }", + " }", + " if (that._xVelocity > 0) {", + " if (Math.abs(this.floorToCellX(object.x) - object.x) > deltaX) {", + " direction = 0;", + " } else {", + " object.x = this.floorToCellX(object.x);", + " }", + " }", + " }", + "", + " // Ensure sharp turn even with Verlet integrations.", + " const speed = Math.abs(that._xVelocity + that._yVelocity);", + " if (direction === 0) {", + " that._xVelocity = speed;", + " that._yVelocity = 0;", + " } else if (direction === 4) {", + " that._xVelocity = -speed;", + " that._yVelocity = 0;", + " } else if (direction === 2) {", + " that._yVelocity = speed;", + " that._xVelocity = 0;", + " } else if (direction === 6) {", + " that._yVelocity = -speed;", + " that._xVelocity = 0;", + " }", + "", + " this.lastDirection = direction;", + " return direction;", + " }", + "", + " /**", + " * Called before the acceleration and new direction is applied to the", + " * velocity.", + " * @param {gdjs.TopDownMovementRuntimeBehavior.TopDownMovementHookContext} context", + " */", + " beforeSpeedUpdate(context) {", + " if (!this.pixelPerfectBehavior.activated()) {", + " return;", + " }", + "", + " const direction = context.getDirection();", + " /** @type {number} */", + " const cellSize = this.pixelPerfectBehavior._getPixelSize();", + " const that = this.topDownBehavior;", + " const object = that.owner;", + "", + " if (cellSize <= 0) {", + " return;", + " }", + "", + " const isMovingOnX =", + " direction !== -1 && direction !== 2 && direction !== 6;", + " if (isMovingOnX) {", + " this.targetX = null;", + " } else if (this.targetX === null) {", + " // Find where the deceleration should stop the object.", + " if (that._xVelocity > 0) {", + " this.targetX = this.ceilToCellX(", + " object.x + this.getBreakingDistanceX()", + " );", + " this.targetDirectionX = 1;", + " }", + " if (that._xVelocity < 0) {", + " this.targetX = this.floorToCellX(", + " object.x - this.getBreakingDistanceX()", + " );", + " this.targetDirectionX = -1;", + " }", + " }", + "", + " const isMovingOnY =", + " direction !== -1 && direction !== 0 && direction !== 4;", + " if (isMovingOnY) {", + " this.targetY = null;", + " } else if (this.targetY === null) {", + " // Find where the deceleration should stop the object.", + " if (that._yVelocity > 0) {", + " this.targetY = this.ceilToCellY(", + " object.y + this.getBreakingDistanceY()", + " );", + " this.targetDirectionY = 1;", + " }", + " if (that._yVelocity < 0) {", + " this.targetY = this.floorToCellY(", + " object.y - this.getBreakingDistanceY()", + " );", + " this.targetDirectionY = -1;", + " }", + " }", + "", + " // Make as if the player had press button a bit longer to reach exactly", + " // the next cell.", + "", + " this.isVelocityAdjustedOnX = this.targetX !== null;", + " if (this.isVelocityAdjustedOnX) {", + " if (this.targetDirectionX > 0) {", + " if (this.targetX > object.getX()) {", + " that._xVelocity = Math.min(", + " that._xVelocity + that._acceleration,", + " that._maxSpeed,", + " this.getSpeedToReach(this.targetX - object.getX())", + " );", + " }", + " const nextFrameX = object.getX() + that._xVelocity * object.getElapsedTime() / 1000;", + " if (this.targetX <= nextFrameX) {", + " that._xVelocity = 0;", + " object.setX(this.roundToCellX(object.getX()));", + " this.targetX = null;", + " }", + " }", + " if (this.targetDirectionX < 0) {", + " if (this.targetX < object.getX()) {", + " that._xVelocity = Math.max(", + " that._xVelocity - that._acceleration,", + " -that._maxSpeed,", + " this.getSpeedToReach(this.targetX - object.getX())", + " );", + " }", + " const nextFrameX = object.getX() + that._xVelocity * object.getElapsedTime() / 1000;", + " if (this.targetX >= nextFrameX) {", + " that._xVelocity = 0;", + " object.setX(this.roundToCellX(object.getX()));", + " this.targetX = null;", + " }", + " }", + " // The velocity is exact. There no need for Verlet integration.", + " this.previousVelocityX = that._xVelocity;", + " }", + "", + " this.isVelocityAdjustedOnY = this.targetY !== null;", + " if (this.isVelocityAdjustedOnY) {", + " if (this.targetDirectionY > 0) {", + " if (this.targetY > object.getY()) {", + " that._yVelocity = Math.min(", + " that._yVelocity + that._acceleration,", + " that._maxSpeed,", + " this.getSpeedToReach(this.targetY - object.getY())", + " );", + " }", + " const nextFrameY = object.getY() + that._yVelocity * object.getElapsedTime() / 1000;", + " if (this.targetY <= nextFrameY) {", + " that._yVelocity = 0;", + " object.setY(this.roundToCellY(object.getY()));", + " this.targetY = null;", + " }", + " }", + " if (this.targetDirectionY < 0) {", + " if (this.targetY < object.getY()) {", + " that._yVelocity = Math.max(", + " that._yVelocity - that._acceleration,", + " -that._maxSpeed,", + " this.getSpeedToReach(this.targetY - object.getY())", + " );", + " }", + " const nextFrameY = object.getY() + that._yVelocity * object.getElapsedTime() / 1000;", + " if (this.targetY >= nextFrameY) {", + " that._yVelocity = 0;", + " object.setY(this.roundToCellY(object.getY()));", + " this.targetY = null;", + " }", + " }", + " // The velocity is exact. There no need for Verlet integration.", + " this.previousVelocityY = that._yVelocity;", + " }", + " }", + "", + " /**", + " * Called before the velocity is applied to the object position and", + " * angle.", + " */", + " beforePositionUpdate() {", + " if (!this.pixelPerfectBehavior.activated()) {", + " return;", + " }", + "", + " /** @type {number} */", + " const cellSize = this.pixelPerfectBehavior._getPixelSize();", + " if (cellSize <= 0) {", + " return;", + " }", + "", + " const that = this.topDownBehavior;", + "", + " if (this.isVelocityAdjustedOnX) {", + " // The velocity is exact. There no need for Verlet integration.", + " that._xVelocity = this.previousVelocityX;", + " }", + " if (this.isVelocityAdjustedOnY) {", + " // The velocity is exact. There no need for Verlet integration.", + " that._yVelocity = this.previousVelocityY;", + " }", + " }", + "", + " doStepPostEvents(instanceContainer) {", + " /** @type {number} */", + " const cellSize = this.pixelPerfectBehavior._getPixelSize();", + " if (cellSize <= 0) {", + " return;", + " }", + "", + " const that = this.topDownBehavior;", + " const object = that.owner;", + "", + " const isMovingOnX =", + " this.lastDirection !== -1 &&", + " this.lastDirection !== 2 &&", + " this.lastDirection !== 6;", + " const isMovingOnY =", + " this.lastDirection !== -1 &&", + " this.lastDirection !== 0 &&", + " this.lastDirection !== 4;", + "", + " // Avoid rounding errors after a call to \"separate\" to make characters", + " // move indefinitely in front of a wall because they can't reach the cell.", + " if (!isMovingOnX && that._xVelocity !== 0) {", + " const x = object.getX();", + " const roundedX = this.roundToCellX(x);", + " if (Math.abs(roundedX - x) < epsilon) {", + " object.setX(roundedX);", + " this.targetDirectionX = 0;", + " that._xVelocity = 0;", + " }", + " }", + " if (!isMovingOnY && that._yVelocity !== 0) {", + " const y = object.getY();", + " const roundedY = this.roundToCellY(y);", + " if (Math.abs(roundedY - y) < epsilon) {", + " object.setY(roundedY);", + " this.targetDirectionY = 0;", + " that._yVelocity = 0;", + " }", + " }", + " }", + "", + " /**", + " * @returns {number} the braking distance according to an initial speed and a deceleration.", + " */", + " getBreakingDistanceX() {", + " const that = this.topDownBehavior;", + " return (that._xVelocity * that._xVelocity) / (2 * that._deceleration);", + " }", + "", + " /**", + " * @returns {number} the braking distance according to an initial speed and a deceleration.", + " */", + " getBreakingDistanceY() {", + " const that = this.topDownBehavior;", + " return (that._yVelocity * that._yVelocity) / (2 * that._deceleration);", + " }", + "", + " /**", + " * @param {number} displacement", + " * @returns {number} the speed necessary to cover a distance according to the deceleration.", + " */", + " getSpeedToReach(displacement) {", + " const that = this.topDownBehavior;", + " return (", + " Math.sign(displacement) *", + " Math.sqrt(2 * Math.abs(displacement) * that._deceleration)", + " );", + " }", + "", + " /**", + " * @param {number} x", + " * @return {number}", + " */", + " ceilToCellX(x) {", + " /** @type {number} */", + " const cellSize = this.pixelPerfectBehavior._getPixelSize();", + " /** @type {number} */", + " const gridOffsetX = this.pixelPerfectBehavior._getOffsetX();", + "", + " return (", + " gridOffsetX +", + " cellSize * Math.ceil((x - gridOffsetX) / cellSize)", + " );", + " }", + "", + " /**", + " * @param {number} x", + " * @return {number}", + " */", + " roundToCellX(x) {", + " /** @type {number} */", + " const cellSize = this.pixelPerfectBehavior._getPixelSize();", + " /** @type {number} */", + " const gridOffsetX = this.pixelPerfectBehavior._getOffsetX();", + "", + " return (", + " gridOffsetX +", + " cellSize * Math.round((x - gridOffsetX) / cellSize)", + " );", + " }", + "", + " /**", + " * @param {number} x", + " * @return {number}", + " */", + " floorToCellX(x) {", + " /** @type {number} */", + " const cellSize = this.pixelPerfectBehavior._getPixelSize();", + " /** @type {number} */", + " const gridOffsetX = this.pixelPerfectBehavior._getOffsetX();", + "", + " return (", + " gridOffsetX +", + " cellSize * Math.floor((x - gridOffsetX) / cellSize)", + " );", + " }", + "", + " /**", + " * @param {number} y", + " * @return {number}", + " */", + " ceilToCellY(y) {", + " /** @type {number} */", + " const cellSize = this.pixelPerfectBehavior._getPixelSize();", + " /** @type {number} */", + " const gridOffsetY = this.pixelPerfectBehavior._getOffsetY();", + "", + " return (", + " gridOffsetY +", + " cellSize * Math.ceil((y - gridOffsetY) / cellSize)", + " );", + " }", + "", + " /**", + " * @param {number} y", + " * @return {number}", + " */", + " roundToCellY(y) {", + " /** @type {number} */", + " const cellSize = this.pixelPerfectBehavior._getPixelSize();", + " /** @type {number} */", + " const gridOffsetY = this.pixelPerfectBehavior._getOffsetY();", + "", + " return (", + " gridOffsetY +", + " cellSize * Math.round((y - gridOffsetY) / cellSize)", + " );", + " }", + "", + " /**", + " * @param {number} y", + " * @return {number}", + " */", + " floorToCellY(y) {", + " /** @type {number} */", + " const cellSize = this.pixelPerfectBehavior._getPixelSize();", + " /** @type {number} */", + " const gridOffsetY = this.pixelPerfectBehavior._getOffsetY();", + "", + " return (", + " gridOffsetY +", + " cellSize * Math.floor((y - gridOffsetY) / cellSize)", + " );", + " }", + "}", + "", + "gdjs.__pixelPerfectExtension = {", + " PixelPerfectTopDownMovement", + "}" ], - "actions": [ - { - "type": { - "value": "SetGlobalVariableAsBoolean" - }, - "parameters": [ - "__pixelPerfect.TopDownClassesDefined", - "True" - ] - } - ], - "events": [ - { - "type": "BuiltinCommonInstructions::JsCode", - "inlineCode": [ - "gdjs.__pixelPerfectExtension = gdjs.__pixelPerfectExtension || {};", - "", - "gdjs.__pixelPerfectExtension.PixelPerfectTopDownMovement = /** @class */ (function () {", - "", - " /**", - " * @param {gdjs.RuntimeBehavior} pixelPerfectBehavior", - " * @param {gdjs.TopDownMovementRuntimeBehavior} topDownBehavior", - " */", - " function PixelPerfectTopDownMovement(pixelPerfectBehavior, topDownBehavior) {", - " /** @type {gdjs.RuntimeBehavior} */", - " this.pixelPerfectBehavior = pixelPerfectBehavior;", - " /** @type {gdjs.TopDownMovementRuntimeBehavior} */", - " this.topDownBehavior = topDownBehavior;", - "", - " topDownBehavior.registerHook(this);", - "", - " /** @type {number | null} */", - " this.targetX = null;", - " /** @type {number | null} */", - " this.targetY = null;", - " this.targetDirectionX = 0;", - " this.targetDirectionY = 0;", - " this.lastDirection = -1;", - " this.isVelocityAdjusted = false;", - " this.isVelocityAdjustedOnX = false;", - " this.isVelocityAdjustedOnY = false;", - " }", - "", - " /**", - " * Return the direction to use instead of the direction given in", - " * parameter.", - " * @param {gdjs.TopDownMovementRuntimeBehavior.TopDownMovementHookContext} context", - " * @return {number}", - " */", - " PixelPerfectTopDownMovement.prototype.overrideDirection = function (context) {", - " let direction = context.getDirection();", - " if (!this.pixelPerfectBehavior.activated()) {", - " return direction;", - " }", - "", - " /** @type {number} */", - " const cellSize = this.pixelPerfectBehavior._getPixelSize();", - " const that = this.topDownBehavior;", - " const object = that.owner;", - "", - " if (cellSize <= 0 || that._allowDiagonals) {", - " return direction;", - " }", - "", - " // Forbid to turn before being aligned on the grid.", - "", - " const timeDelta = object.getElapsedTime() / 1000;", - " const deltaX = Math.abs(that._xVelocity * timeDelta);", - " const deltaY = Math.abs(that._yVelocity * timeDelta);", - "", - " const isTryingToMoveOnX = direction === 4 || direction === 0;", - " const isTryingToMoveOnY = direction === 6 || direction === 2;", - " if (isTryingToMoveOnX) {", - " if (that._yVelocity < 0) {", - " if (Math.abs(this.ceilToCellY(object.y) - object.y) > deltaY) {", - " direction = 6;", - " } else {", - " object.y = this.ceilToCellY(object.y);", - " }", - " }", - " if (that._yVelocity > 0) {", - " if (Math.abs(this.floorToCellY(object.y) - object.y) > deltaY) {", - " direction = 2;", - " } else {", - " object.y = this.floorToCellY(object.y);", - " }", - " }", - " } else if (isTryingToMoveOnY) {", - " if (that._xVelocity < 0) {", - " if (Math.abs(this.ceilToCellX(object.x) - object.x) > deltaX) {", - " direction = 4;", - " } else {", - " object.x = this.ceilToCellX(object.x);", - " }", - " }", - " if (that._xVelocity > 0) {", - " if (Math.abs(this.floorToCellX(object.x) - object.x) > deltaX) {", - " direction = 0;", - " } else {", - " object.x = this.floorToCellX(object.x);", - " }", - " }", - " }", - "", - " // Ensure sharp turn even with Verlet integrations.", - " const speed = Math.abs(that._xVelocity + that._yVelocity);", - " if (direction === 0) {", - " that._xVelocity = speed;", - " that._yVelocity = 0;", - " } else if (direction === 4) {", - " that._xVelocity = -speed;", - " that._yVelocity = 0;", - " } else if (direction === 2) {", - " that._yVelocity = speed;", - " that._xVelocity = 0;", - " } else if (direction === 6) {", - " that._yVelocity = -speed;", - " that._xVelocity = 0;", - " }", - "", - " this.lastDirection = direction;", - " return direction;", - " }", - "", - " /**", - " * Called before the acceleration and new direction is applied to the", - " * velocity.", - " * @param {gdjs.TopDownMovementRuntimeBehavior.TopDownMovementHookContext} context", - " */", - " PixelPerfectTopDownMovement.prototype.beforeSpeedUpdate = function (context) {", - " if (!this.pixelPerfectBehavior.activated()) {", - " return;", - " }", - "", - " const direction = context.getDirection();", - " /** @type {number} */", - " const cellSize = this.pixelPerfectBehavior._getPixelSize();", - " const that = this.topDownBehavior;", - " const object = that.owner;", - "", - " if (cellSize <= 0) {", - " return;", - " }", - "", - " const isMovingOnX =", - " direction !== -1 && direction !== 2 && direction !== 6;", - " if (isMovingOnX) {", - " this.targetX = null;", - " } else if (this.targetX === null) {", - " // Find where the deceleration should stop the object.", - " if (that._xVelocity > 0) {", - " this.targetX = this.ceilToCellX(", - " object.x + this.getBreakingDistanceX()", - " );", - " this.targetDirectionX = 1;", - " }", - " if (that._xVelocity < 0) {", - " this.targetX = this.floorToCellX(", - " object.x - this.getBreakingDistanceX()", - " );", - " this.targetDirectionX = -1;", - " }", - " }", - "", - " const isMovingOnY =", - " direction !== -1 && direction !== 0 && direction !== 4;", - " if (isMovingOnY) {", - " this.targetY = null;", - " } else if (this.targetY === null) {", - " // Find where the deceleration should stop the object.", - " if (that._yVelocity > 0) {", - " this.targetY = this.ceilToCellY(", - " object.y + this.getBreakingDistanceY()", - " );", - " this.targetDirectionY = 1;", - " }", - " if (that._yVelocity < 0) {", - " this.targetY = this.floorToCellY(", - " object.y - this.getBreakingDistanceY()", - " );", - " this.targetDirectionY = -1;", - " }", - " }", - "", - " // Make as if the player had press button a bit longer to reach exactly", - " // the next cell.", - "", - " this.isVelocityAdjustedOnX = this.targetX !== null;", - " if (this.isVelocityAdjustedOnX) {", - " if (this.targetDirectionX > 0) {", - " if (this.targetX > object.getX()) {", - " that._xVelocity = Math.min(", - " that._xVelocity + that._acceleration,", - " that._maxSpeed,", - " this.getSpeedToReach(this.targetX - object.getX())", - " );", - " }", - " const nextFrameX = object.getX() + that._xVelocity * object.getElapsedTime() / 1000;", - " if (this.targetX <= nextFrameX) {", - " that._xVelocity = 0;", - " object.setX(this.roundToCellX(object.getX()));", - " this.targetX = null;", - " }", - " }", - " if (this.targetDirectionX < 0) {", - " if (this.targetX < object.getX()) {", - " that._xVelocity = Math.max(", - " that._xVelocity - that._acceleration,", - " -that._maxSpeed,", - " this.getSpeedToReach(this.targetX - object.getX())", - " );", - " }", - " const nextFrameX = object.getX() + that._xVelocity * object.getElapsedTime() / 1000;", - " if (this.targetX >= nextFrameX) {", - " that._xVelocity = 0;", - " object.setX(this.roundToCellX(object.getX()));", - " this.targetX = null;", - " }", - " }", - " // The velocity is exact. There no need for Verlet integration.", - " this.previousVelocityX = that._xVelocity;", - " }", - "", - " this.isVelocityAdjustedOnY = this.targetY !== null;", - " if (this.isVelocityAdjustedOnY) {", - " if (this.targetDirectionY > 0) {", - " if (this.targetY > object.getY()) {", - " that._yVelocity = Math.min(", - " that._yVelocity + that._acceleration,", - " that._maxSpeed,", - " this.getSpeedToReach(this.targetY - object.getY())", - " );", - " }", - " const nextFrameY = object.getY() + that._yVelocity * object.getElapsedTime() / 1000;", - " if (this.targetY <= nextFrameY) {", - " that._yVelocity = 0;", - " object.setY(this.roundToCellY(object.getY()));", - " this.targetY = null;", - " }", - " }", - " if (this.targetDirectionY < 0) {", - " if (this.targetY < object.getY()) {", - " that._yVelocity = Math.max(", - " that._yVelocity - that._acceleration,", - " -that._maxSpeed,", - " this.getSpeedToReach(this.targetY - object.getY())", - " );", - " }", - " const nextFrameY = object.getY() + that._yVelocity * object.getElapsedTime() / 1000;", - " if (this.targetY >= nextFrameY) {", - " that._yVelocity = 0;", - " object.setY(this.roundToCellY(object.getY()));", - " this.targetY = null;", - " }", - " }", - " // The velocity is exact. There no need for Verlet integration.", - " this.previousVelocityY = that._yVelocity;", - " }", - " }", - "", - " /**", - " * Called before the velocity is applied to the object position and", - " * angle.", - " */", - " PixelPerfectTopDownMovement.prototype.beforePositionUpdate = function () {", - " if (!this.pixelPerfectBehavior.activated()) {", - " return;", - " }", - "", - " /** @type {number} */", - " const cellSize = this.pixelPerfectBehavior._getPixelSize();", - " if (cellSize <= 0) {", - " return;", - " }", - "", - " const that = this.topDownBehavior;", - "", - " if (this.isVelocityAdjustedOnX) {", - " // The velocity is exact. There no need for Verlet integration.", - " that._xVelocity = this.previousVelocityX;", - " }", - " if (this.isVelocityAdjustedOnY) {", - " // The velocity is exact. There no need for Verlet integration.", - " that._yVelocity = this.previousVelocityY;", - " }", - " }", - "", - " const epsilon = 1 / (1 << 20);", - "", - " PixelPerfectTopDownMovement.prototype.doStepPostEvents = function (instanceContainer) {", - " /** @type {number} */", - " const cellSize = this.pixelPerfectBehavior._getPixelSize();", - " if (cellSize <= 0) {", - " return;", - " }", - "", - " const that = this.topDownBehavior;", - " const object = that.owner;", - "", - " const isMovingOnX =", - " this.lastDirection !== -1 &&", - " this.lastDirection !== 2 &&", - " this.lastDirection !== 6;", - " const isMovingOnY =", - " this.lastDirection !== -1 &&", - " this.lastDirection !== 0 &&", - " this.lastDirection !== 4;", - "", - " // Avoid rounding errors after a call to \"separate\" to make characters", - " // move indefinitely in front of a wall because they can't reach the cell.", - " if (!isMovingOnX && that._xVelocity !== 0) {", - " const x = object.getX();", - " const roundedX = this.roundToCellX(x);", - " if (Math.abs(roundedX - x) < epsilon) {", - " object.setX(roundedX);", - " this.targetDirectionX = 0;", - " that._xVelocity = 0;", - " }", - " }", - " if (!isMovingOnY && that._yVelocity !== 0) {", - " const y = object.getY();", - " const roundedY = this.roundToCellY(y);", - " if (Math.abs(roundedY - y) < epsilon) {", - " object.setY(roundedY);", - " this.targetDirectionY = 0;", - " that._yVelocity = 0;", - " }", - " }", - " }", - "", - " /**", - " * @returns {number} the braking distance according to an initial speed and a deceleration.", - " */", - " PixelPerfectTopDownMovement.prototype.getBreakingDistanceX = function () {", - " const that = this.topDownBehavior;", - " return (that._xVelocity * that._xVelocity) / (2 * that._deceleration);", - " }", - "", - " /**", - " * @returns {number} the braking distance according to an initial speed and a deceleration.", - " */", - " PixelPerfectTopDownMovement.prototype.getBreakingDistanceY = function () {", - " const that = this.topDownBehavior;", - " return (that._yVelocity * that._yVelocity) / (2 * that._deceleration);", - " }", - "", - " /**", - " * @param {number} displacement", - " * @returns {number} the speed necessary to cover a distance according to the deceleration.", - " */", - " PixelPerfectTopDownMovement.prototype.getSpeedToReach = function (displacement) {", - " const that = this.topDownBehavior;", - " return (", - " Math.sign(displacement) *", - " Math.sqrt(2 * Math.abs(displacement) * that._deceleration)", - " );", - " }", - "", - " /**", - " * @param {number} x", - " * @return {number}", - " */", - " PixelPerfectTopDownMovement.prototype.ceilToCellX = function (x) {", - " /** @type {number} */", - " const cellSize = this.pixelPerfectBehavior._getPixelSize();", - " /** @type {number} */", - " const gridOffsetX = this.pixelPerfectBehavior._getOffsetX();", - "", - " return (", - " gridOffsetX +", - " cellSize * Math.ceil((x - gridOffsetX) / cellSize)", - " );", - " }", - "", - " /**", - " * @param {number} x", - " * @return {number}", - " */", - " PixelPerfectTopDownMovement.prototype.roundToCellX = function (x) {", - " /** @type {number} */", - " const cellSize = this.pixelPerfectBehavior._getPixelSize();", - " /** @type {number} */", - " const gridOffsetX = this.pixelPerfectBehavior._getOffsetX();", - "", - " return (", - " gridOffsetX +", - " cellSize * Math.round((x - gridOffsetX) / cellSize)", - " );", - " }", - "", - " /**", - " * @param {number} x", - " * @return {number}", - " */", - " PixelPerfectTopDownMovement.prototype.floorToCellX = function (x) {", - " /** @type {number} */", - " const cellSize = this.pixelPerfectBehavior._getPixelSize();", - " /** @type {number} */", - " const gridOffsetX = this.pixelPerfectBehavior._getOffsetX();", - "", - " return (", - " gridOffsetX +", - " cellSize * Math.floor((x - gridOffsetX) / cellSize)", - " );", - " }", - "", - " /**", - " * @param {number} y", - " * @return {number}", - " */", - " PixelPerfectTopDownMovement.prototype.ceilToCellY = function (y) {", - " /** @type {number} */", - " const cellSize = this.pixelPerfectBehavior._getPixelSize();", - " /** @type {number} */", - " const gridOffsetY = this.pixelPerfectBehavior._getOffsetY();", - "", - " return (", - " gridOffsetY +", - " cellSize * Math.ceil((y - gridOffsetY) / cellSize)", - " );", - " }", - "", - " /**", - " * @param {number} y", - " * @return {number}", - " */", - " PixelPerfectTopDownMovement.prototype.roundToCellY = function (y) {", - " /** @type {number} */", - " const cellSize = this.pixelPerfectBehavior._getPixelSize();", - " /** @type {number} */", - " const gridOffsetY = this.pixelPerfectBehavior._getOffsetY();", - "", - " return (", - " gridOffsetY +", - " cellSize * Math.round((y - gridOffsetY) / cellSize)", - " );", - " }", - "", - " /**", - " * @param {number} y", - " * @return {number}", - " */", - " PixelPerfectTopDownMovement.prototype.floorToCellY = function (y) {", - " /** @type {number} */", - " const cellSize = this.pixelPerfectBehavior._getPixelSize();", - " /** @type {number} */", - " const gridOffsetY = this.pixelPerfectBehavior._getOffsetY();", - "", - " return (", - " gridOffsetY +", - " cellSize * Math.floor((y - gridOffsetY) / cellSize)", - " );", - " }", - "", - " return PixelPerfectTopDownMovement;", - "}());", - "", - "" - ], - "parameterObjects": "", - "useStrict": true, - "eventsSheetExpanded": true - } - ] + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": true } ], "parameters": [], @@ -754,7 +731,6 @@ "extraInformation": [ "TopDownMovementBehavior::TopDownMovementBehavior" ], - "hidden": false, "name": "TopDownMovement" }, { @@ -764,7 +740,6 @@ "description": "", "group": "", "extraInformation": [], - "hidden": false, "name": "PixelSize" }, { @@ -774,7 +749,6 @@ "description": "", "group": "", "extraInformation": [], - "hidden": false, "name": "OffsetX" }, { @@ -784,7 +758,6 @@ "description": "", "group": "", "extraInformation": [], - "hidden": false, "name": "OffsetY" } ], @@ -821,8 +794,7 @@ "textG": 0, "textR": 0 }, - "comment": "We don't know if the deceleration was already applied or not this step, but if the speed drifted from more than 1%, another extension is probably modifying the speed and it must not be overridden.", - "comment2": "" + "comment": "We don't know if the deceleration was already applied or not this step, but if the speed drifted from more than 1%, another extension is probably modifying the speed and it must not be overridden." }, { "type": "BuiltinCommonInstructions::Standard", @@ -841,7 +813,7 @@ "value": "BuiltinCommonInstructions::CompareNumbers" }, "parameters": [ - "abs(Object.PlatformerCharacter::CurrentSpeed() - Object.Behavior::PropertyPreviousSpeedX())", + "abs(Object.PlatformerCharacter::CurrentSpeed() - PreviousSpeedX)", "<", "Object.PlatformerCharacter::CurrentSpeed() * 0.01 + Object.PlatformerCharacter::Deceleration() * TimeDelta()" ] @@ -859,8 +831,7 @@ "textG": 0, "textR": 0 }, - "comment": "Find how far to go to reach a pixel.", - "comment2": "" + "comment": "Find how far to go to reach a pixel." }, { "type": "BuiltinCommonInstructions::Standard", @@ -898,7 +869,7 @@ "Object", "Behavior", "=", - "Object.Behavior::PropertyOffsetX() + Object.Behavior::PropertyPixelSize() * ceil((Object.X() + PixelPerfectMovement::BrakingDistance(Object.PlatformerCharacter::CurrentSpeed(), Object.PlatformerCharacter::Deceleration()) - Object.Behavior::PropertyOffsetX()) / Object.Behavior::PropertyPixelSize())" + "OffsetX + PixelSize * ceil((Object.X() + PixelPerfectMovement::BrakingDistance(Object.PlatformerCharacter::CurrentSpeed(), Object.PlatformerCharacter::Deceleration()) - OffsetX) / PixelSize)" ] }, { @@ -924,7 +895,7 @@ "value": "DebuggerTools::ConsoleLog" }, "parameters": [ - "\"Target: \" + ToString(Object.X()) + \"-->\" + ToString(Object.Behavior::PropertyTargetX())", + "\"Target: \" + ToString(Object.X()) + \"-->\" + TargetX", "", "" ] @@ -957,7 +928,7 @@ "Object", "Behavior", "=", - "Object.Behavior::PropertyOffsetX() + Object.Behavior::PropertyPixelSize() * floor((Object.X() - PixelPerfectMovement::BrakingDistance(Object.PlatformerCharacter::CurrentSpeed(), Object.PlatformerCharacter::Deceleration()) - Object.Behavior::PropertyOffsetX()) / Object.Behavior::PropertyPixelSize())" + "OffsetX + PixelSize * floor((Object.X() - PixelPerfectMovement::BrakingDistance(Object.PlatformerCharacter::CurrentSpeed(), Object.PlatformerCharacter::Deceleration()) - OffsetX) / PixelSize)" ] }, { @@ -983,7 +954,7 @@ "value": "DebuggerTools::ConsoleLog" }, "parameters": [ - "\"Target: \" + ToString(Object.X()) + \"-->\" + ToString(Object.Behavior::PropertyTargetX())", + "\"Target: \" + ToString(Object.X()) + \"-->\" + TargetX", "", "" ] @@ -1004,8 +975,7 @@ "textG": 0, "textR": 0 }, - "comment": "Move to the target as the movement behavior would do.", - "comment2": "" + "comment": "Move to the target as the movement behavior would do." }, { "type": "BuiltinCommonInstructions::Standard", @@ -1017,7 +987,7 @@ "parameters": [ "Object", "<", - "Object.Behavior::PropertyTargetX()" + "TargetX" ] }, { @@ -1041,7 +1011,7 @@ "Object", "PlatformerCharacter", "=", - "min(Object.PlatformerCharacter:: CurrentSpeed() + Object.PlatformerCharacter::Acceleration(), min(Object.PlatformerCharacter::MaxSpeed(), PixelPerfectMovement::SpeedToReach(Object.Behavior::PropertyTargetX() - Object.X(), Object.PlatformerCharacter::Deceleration())))" + "min(Object.PlatformerCharacter::CurrentSpeed() + Object.PlatformerCharacter::Acceleration(), min(Object.PlatformerCharacter::MaxSpeed(), PixelPerfectMovement::SpeedToReach(TargetX - Object.X(), Object.PlatformerCharacter::Deceleration())))" ] } ] @@ -1056,7 +1026,7 @@ "parameters": [ "Object", ">", - "Object.Behavior::PropertyTargetX()" + "TargetX" ] }, { @@ -1080,7 +1050,7 @@ "Object", "PlatformerCharacter", "=", - "max(Object.PlatformerCharacter:: CurrentSpeed() - Object.PlatformerCharacter::Acceleration(), max(-Object.PlatformerCharacter::MaxSpeed(), PixelPerfectMovement::SpeedToReach(Object.Behavior::PropertyTargetX() - Object.X(), Object.PlatformerCharacter::Deceleration())))" + "max(Object.PlatformerCharacter::CurrentSpeed() - Object.PlatformerCharacter::Acceleration(), max(-Object.PlatformerCharacter::MaxSpeed(), PixelPerfectMovement::SpeedToReach(TargetX - Object.X(), Object.PlatformerCharacter::Deceleration())))" ] } ] @@ -1107,7 +1077,7 @@ "parameters": [ "Object", ">=", - "Object.Behavior::PropertyTargetX()" + "TargetX" ] }, { @@ -1136,7 +1106,7 @@ "parameters": [ "Object", "<=", - "Object.Behavior::PropertyTargetX()" + "TargetX" ] }, { @@ -1163,7 +1133,7 @@ "parameters": [ "Object", "=", - "Object.Behavior::PropertyOffsetX() + Object.Behavior::PropertyPixelSize() * round((Object.X() - Object.Behavior::PropertyOffsetX()) / Object.Behavior::PropertyPixelSize())" + "OffsetX + PixelSize * round((Object.X() - OffsetX) / PixelSize)" ] }, { @@ -1248,8 +1218,7 @@ "textG": 0, "textR": 0 }, - "comment": "Find how far to go to reach a pixel.", - "comment2": "" + "comment": "Find how far to go to reach a pixel." }, { "type": "BuiltinCommonInstructions::Standard", @@ -1298,7 +1267,7 @@ "Object", "Behavior", "=", - "Object.Behavior::PropertyOffsetY() + Object.Behavior::PropertyPixelSize() * ceil((Object.Y() - Object.Behavior::PropertyOffsetY()) / Object.Behavior::PropertyPixelSize())" + "OffsetY + PixelSize * ceil((Object.Y() - OffsetY) / PixelSize)" ] }, { @@ -1324,7 +1293,7 @@ "value": "DebuggerTools::ConsoleLog" }, "parameters": [ - "\"Target: \" + ToString(Object.Y()) + \"-->\" + ToString(Object.Behavior::PropertyTargetY())", + "\"Target: \" + ToString(Object.Y()) + \"-->\" + TargetY", "", "" ] @@ -1382,7 +1351,7 @@ "Object", "Behavior", "=", - "Object.Behavior::PropertyOffsetY() + Object.Behavior::PropertyPixelSize() * floor((Object.Y() - Object.Behavior::PropertyOffsetY()) / Object.Behavior::PropertyPixelSize())" + "OffsetY + PixelSize * floor((Object.Y() - OffsetY) / PixelSize)" ] }, { @@ -1408,7 +1377,7 @@ "value": "DebuggerTools::ConsoleLog" }, "parameters": [ - "\"Target: \" + ToString(Object.Y()) + \"-->\" + ToString(Object.Behavior::PropertyTargetY())", + "\"Target: \" + ToString(Object.Y()) + \"-->\" + TargetY", "", "" ] @@ -1429,8 +1398,7 @@ "textG": 0, "textR": 0 }, - "comment": "Move to the target as the movement behavior would do.", - "comment2": "" + "comment": "Move to the target as the movement behavior would do." }, { "type": "BuiltinCommonInstructions::Standard", @@ -1470,7 +1438,7 @@ "parameters": [ "Object", "<", - "Object.Behavior::PropertyTargetY()" + "TargetY" ] }, { @@ -1508,7 +1476,7 @@ "parameters": [ "Object", ">", - "Object.Behavior::PropertyTargetY()" + "TargetY" ] }, { @@ -1558,7 +1526,7 @@ "parameters": [ "Object", ">=", - "Object.Behavior::PropertyTargetY()" + "TargetY" ] }, { @@ -1587,7 +1555,7 @@ "parameters": [ "Object", "<=", - "Object.Behavior::PropertyTargetY()" + "TargetY" ] }, { @@ -1614,7 +1582,7 @@ "parameters": [ "Object", "=", - "Object.Behavior::PropertyOffsetY() + Object.Behavior::PropertyPixelSize() * round((Object.Y() - Object.Behavior::PropertyOffsetY()) / Object.Behavior::PropertyPixelSize())" + "OffsetY + PixelSize * round((Object.Y() - OffsetY) / PixelSize)" ] }, { @@ -1707,7 +1675,7 @@ "value": "DebuggerTools::ConsoleLog" }, "parameters": [ - "ToString(abs(Object.Behavior::PropertyPreviousSpeedX()) - Object.PlatformerCharacter::Deceleration() * TimeDelta() - abs(Object.PlatformerCharacter::CurrentSpeed()))", + "ToString(abs(PreviousSpeedX) - Object.PlatformerCharacter::Deceleration() * TimeDelta() - abs(Object.PlatformerCharacter::CurrentSpeed()))", "", "" ] @@ -1724,8 +1692,7 @@ "textG": 0, "textR": 0 }, - "comment": "Check if the character is decelerating.\nIt's done in doStepPostEvent because there is no way to know if the doStepPreEvents of this behavior is executed before or after the one of PlatformerCharcter.\nAs TimeDelta is used, we have to be sure the last PlatformerCharcter.doStepPreEvents call used the same TimeDelta. Which means this must be done after PlatformerCharcter.doStepPreEvents.", - "comment2": "" + "comment": "Check if the character is decelerating.\nIt's done in doStepPostEvent because there is no way to know if the doStepPreEvents of this behavior is executed before or after the one of PlatformerCharcter.\nAs TimeDelta is used, we have to be sure the last PlatformerCharcter.doStepPreEvents call used the same TimeDelta. Which means this must be done after PlatformerCharcter.doStepPreEvents." }, { "type": "BuiltinCommonInstructions::Standard", @@ -1770,7 +1737,7 @@ "parameters": [ "abs(Object.PlatformerCharacter::CurrentSpeed())", "=", - "abs(Object.Behavior::PropertyPreviousSpeedX()) - Object.PlatformerCharacter::Deceleration() * TimeDelta()" + "abs(PreviousSpeedX) - Object.PlatformerCharacter::Deceleration() * TimeDelta()" ] } ] @@ -1799,8 +1766,7 @@ "textG": 0, "textR": 0 }, - "comment": "Save the speed to detect speed changes from outside.", - "comment2": "" + "comment": "Save the speed to detect speed changes from outside." }, { "type": "BuiltinCommonInstructions::Standard", @@ -1846,7 +1812,6 @@ "extraInformation": [ "PlatformBehavior::PlatformerObjectBehavior" ], - "hidden": false, "name": "PlatformerCharacter" }, { @@ -1856,7 +1821,6 @@ "description": "", "group": "", "extraInformation": [], - "hidden": false, "name": "PixelSize" }, { @@ -1866,7 +1830,6 @@ "description": "", "group": "", "extraInformation": [], - "hidden": false, "name": "OffsetX" }, { @@ -1876,7 +1839,6 @@ "description": "", "group": "", "extraInformation": [], - "hidden": false, "name": "OffsetY" }, {