mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
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:
@@ -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."),
|
||||
|
@@ -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(
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
};
|
||||
|
Reference in New Issue
Block a user