Add an action to forbid to jump again while in the air to the Platformer behavior. (#2872)

* This is useful if you want to allow to jump again in the air for a bit of time, and then forbid to jump again later (for example, to implement a "Coyote Time" feature to your player character)
This commit is contained in:
D8H
2021-08-04 12:29:38 +02:00
committed by GitHub
parent 9491a8ed45
commit 8beabbadef
4 changed files with 128 additions and 6 deletions

View File

@@ -5,8 +5,9 @@ Copyright (c) 2014-2016 Florian Rival (Florian.Rival@gmail.com)
This project is released under the MIT License.
*/
#include "GDCpp/Extensions/ExtensionBase.h"
#include "PlatformBehavior.h"
#include "GDCpp/Extensions/ExtensionBase.h"
#include "PlatformRuntimeBehavior.h"
#include "PlatformerObjectBehavior.h"
#include "PlatformerObjectRuntimeBehavior.h"
@@ -381,6 +382,19 @@ void DeclarePlatformBehaviorExtension(gd::PlatformExtension& extension) {
.SetFunctionName("SetCanJump")
.SetIncludeFile("PlatformBehavior/PlatformerObjectRuntimeBehavior.h");
aut.AddScopedAction(
"SetCanNotAirJump",
_("Forbid jumping again in the air"),
_("This revokes the effect of \"Allow jumping again\". The object "
"is made unable to jump while in mid air. This has no effect if "
"the object is not in the air."),
_("Forbid _PARAM0_ to air jump"),
_("Options"),
"CppPlatform/Extensions/platformerobjecticon24.png",
"CppPlatform/Extensions/platformerobjecticon16.png")
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "PlatformerObjectBehavior");
aut.AddCondition("CanJump",
_("Can jump"),
_("Check if the object can jump."),

View File

@@ -119,6 +119,7 @@ class PlatformBehaviorJsExtension : public gd::PlatformExtension {
"getCurrentJumpSpeed");
autExpressions["CurrentJumpSpeed"].SetFunctionName("getCurrentJumpSpeed");
autActions["PlatformBehavior::SetCanJump"].SetFunctionName("setCanJump");
autActions["PlatformBehavior::PlatformerObjectBehavior::SetCanNotAirJump"].SetFunctionName("setCanNotAirJump");
autConditions["PlatformBehavior::CanJump"].SetFunctionName(
"canJump");
autActions["PlatformBehavior::SimulateLeftKey"].SetFunctionName(

View File

@@ -236,7 +236,9 @@ namespace gdjs {
this._jumpKey = false;
//5) Track the movement
this._hasReallyMoved = Math.abs(object.getX() - oldX) >= 1;
this._hasReallyMoved =
Math.abs(object.getX() - oldX) >= 1 ||
Math.abs(object.getY() - oldY) >= 1;
this._lastDeltaY = object.getY() - oldY;
}
@@ -999,6 +1001,15 @@ namespace gdjs {
this._canJump = true;
}
/**
* Forbid the Platformer Object to air jump.
*/
setCanNotAirJump(): void {
if (this._state === this._jumping || this._state === this._falling) {
this._canJump = false;
}
}
/**
* Set if the Platformer Object can grab platforms.
* @param enable Enable / Disable grabbing of platforms.
@@ -1135,7 +1146,8 @@ namespace gdjs {
*/
isMoving(): boolean {
return (
(this._hasReallyMoved && this._currentSpeed !== 0) ||
(this._hasReallyMoved &&
(this._currentSpeed !== 0 || this._state === this._onLadder)) ||
this._jumping.getCurrentJumpSpeed() !== 0 ||
this._currentFallSpeed !== 0
);
@@ -1616,6 +1628,7 @@ namespace gdjs {
beforeMovingY(timeDelta: float, oldX: float) {
const behavior = this._behavior;
// TODO: we could consider supporting acceleration for ladder climbing in the future.
if (behavior._upKey) {
behavior._requestedDeltaY -= behavior._ladderClimbingSpeed * timeDelta;
}

View File

@@ -550,6 +550,11 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
);
expect(object.getBehavior('auto1').isMoving()).to.be(false);
// Forbid to jump
object.getBehavior('auto1').setCanNotAirJump();
// It has no impact as the object is on a platform.
expect(object.getBehavior('auto1').canJump()).to.be(true);
// Jump with sustaining as much as possible, and
// even more (18 frames at 60fps is greater than 0.2s)
for (let i = 0; i < 18; ++i) {
@@ -649,7 +654,7 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
);
expect(object.getBehavior('auto1').isMoving()).to.be(false);
// Fell from the platform
// Fall from the platform
for (let i = 0; i < 35; ++i) {
object.getBehavior('auto1').simulateLeftKey();
runtimeScene.renderAndStep(1000 / 60);
@@ -663,6 +668,96 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
expect(object.getBehavior('auto1').isFallingWithoutJumping()).to.be(true);
});
it('can be allowed to jump in mid air', function () {
// Ensure the object falls on the platform
for (let i = 0; i < 10; ++i) {
runtimeScene.renderAndStep(1000 / 60);
}
// Check the object is on the platform
expect(object.getY()).to.be(-30); // -30 = -10 (platform y) + -20 (object height)
expect(object.getBehavior('auto1').isFalling()).to.be(false);
expect(object.getBehavior('auto1').isFallingWithoutJumping()).to.be(
false
);
expect(object.getBehavior('auto1').isMoving()).to.be(false);
// Fall from the platform
for (let i = 0; i < 20; ++i) {
object.getBehavior('auto1').simulateLeftKey();
runtimeScene.renderAndStep(1000 / 60);
}
// Allow to jump in mid air
expect(object.getBehavior('auto1').isFalling()).to.be(true);
object.getBehavior('auto1').setCanJump();
expect(object.getBehavior('auto1').canJump()).to.be(true);
// Can jump in the air
object.getBehavior('auto1').simulateJumpKey();
runtimeScene.renderAndStep(1000 / 60);
expect(object.getBehavior('auto1').isJumping()).to.be(true);
expect(object.getBehavior('auto1').isFalling()).to.be(false);
expect(object.getBehavior('auto1').isFallingWithoutJumping()).to.be(
false
);
for (let i = 0; i < 40; ++i) {
object.getBehavior('auto1').simulateLeftKey();
runtimeScene.renderAndStep(1000 / 60);
}
expect(object.getBehavior('auto1').isJumping()).to.be(false);
// Can no longer to jump
object.getBehavior('auto1').simulateJumpKey();
runtimeScene.renderAndStep(1000 / 60);
expect(object.getBehavior('auto1').isJumping()).to.be(false);
expect(object.getBehavior('auto1').isFalling()).to.be(true);
expect(object.getBehavior('auto1').isFallingWithoutJumping()).to.be(true);
});
it('can allow coyote time', function () {
// Ensure the object falls on the platform
for (let i = 0; i < 10; ++i) {
runtimeScene.renderAndStep(1000 / 60);
}
// Check the object is on the platform
expect(object.getY()).to.be(-30); // -30 = -10 (platform y) + -20 (object height)
expect(object.getBehavior('auto1').isFalling()).to.be(false);
expect(object.getBehavior('auto1').isFallingWithoutJumping()).to.be(
false
);
expect(object.getBehavior('auto1').isMoving()).to.be(false);
// Fall from the platform
for (let i = 0; i < 20; ++i) {
object.getBehavior('auto1').simulateLeftKey();
runtimeScene.renderAndStep(1000 / 60);
}
// Allow to jump
expect(object.getBehavior('auto1').isFalling()).to.be(true);
object.getBehavior('auto1').setCanJump();
expect(object.getBehavior('auto1').canJump()).to.be(true);
// Still falling from the platform
for (let i = 0; i < 4; ++i) {
object.getBehavior('auto1').simulateLeftKey();
runtimeScene.renderAndStep(1000 / 60);
}
// Suppose that we miss an eventual time frame or some condition.
// So we forbid to jump again:
object.getBehavior('auto1').setCanNotAirJump();
expect(object.getBehavior('auto1').canJump()).to.be(false);
// Can no longer to jump in mid air
object.getBehavior('auto1').simulateJumpKey();
runtimeScene.renderAndStep(1000 / 60);
expect(object.getBehavior('auto1').isJumping()).to.be(false);
expect(object.getBehavior('auto1').isFalling()).to.be(true);
expect(object.getBehavior('auto1').isFallingWithoutJumping()).to.be(true);
});
it('should not grab a platform while in the ascending phase of a jump', function () {
const topPlatform = addPlatformObject(runtimeScene);
topPlatform.setPosition(12, -80);
@@ -1532,8 +1627,7 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
object.getBehavior('auto1').simulateUpKey();
runtimeScene.renderAndStep(1000 / 60);
expect(object.getBehavior('auto1').isOnLadder()).to.be(true);
//TODO Probably a bug, uncomment it after it's fixed
//expect(object.getBehavior('auto1').isMoving()).to.be(true);
expect(object.getBehavior('auto1').isMoving()).to.be(true);
expect(object.getY()).to.be.below(lastY);
}
};