mirror of
https://github.com/Heretek-AI/GDevelop.git
synced 2026-07-23 10:35:35 -04:00
484 lines
14 KiB
JavaScript
484 lines
14 KiB
JavaScript
const makeTestRuntimeScene = () => {
|
|
const runtimeGame = new gdjs.RuntimeGame({
|
|
variables: [],
|
|
resources: {
|
|
resources: [],
|
|
},
|
|
properties: { windowWidth: 800, windowHeight: 600 },
|
|
});
|
|
const runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
|
runtimeScene.loadFromScene({
|
|
layers: [{ name: '', visibility: true, effects: [] }],
|
|
variables: [],
|
|
behaviorsSharedData: [],
|
|
objects: [],
|
|
instances: [],
|
|
});
|
|
runtimeScene._timeManager.getElapsedTime = function() {
|
|
return (1 / 60) * 1000;
|
|
};
|
|
return runtimeScene;
|
|
};
|
|
|
|
const addPlatformObject = runtimeScene => {
|
|
var platform = new gdjs.RuntimeObject(runtimeScene, {
|
|
name: 'obj2',
|
|
type: '',
|
|
behaviors: [
|
|
{
|
|
type: 'PlatformBehavior::PlatformBehavior',
|
|
canBeGrabbed: true,
|
|
},
|
|
],
|
|
});
|
|
platform.getWidth = function() {
|
|
return 60;
|
|
};
|
|
platform.getHeight = function() {
|
|
return 32;
|
|
};
|
|
runtimeScene.addObject(platform);
|
|
|
|
return platform;
|
|
};
|
|
|
|
describe('gdjs.PlatformerObjectRuntimeBehavior', function() {
|
|
const runtimeScene = makeTestRuntimeScene();
|
|
|
|
//Put a platformer object in the air.
|
|
var object = new gdjs.RuntimeObject(runtimeScene, {
|
|
name: 'obj1',
|
|
type: '',
|
|
behaviors: [
|
|
{
|
|
type: 'PlatformBehavior::PlatformerObjectBehavior',
|
|
name: 'auto1',
|
|
gravity: 900,
|
|
maxFallingSpeed: 1500,
|
|
acceleration: 500,
|
|
deceleration: 1500,
|
|
maxSpeed: 500,
|
|
jumpSpeed: 1500,
|
|
canGrabPlatforms: true,
|
|
ignoreDefaultControls: true,
|
|
slopeMaxAngle: 60,
|
|
},
|
|
],
|
|
});
|
|
object.getWidth = function() {
|
|
return 10;
|
|
};
|
|
object.getHeight = function() {
|
|
return 20;
|
|
};
|
|
runtimeScene.addObject(object);
|
|
object.setPosition(0, -100);
|
|
|
|
//Put a platform
|
|
const platform = addPlatformObject(runtimeScene);
|
|
platform.setPosition(0, -10);
|
|
|
|
it('can fall when in the air', function() {
|
|
for (var i = 0; i < 30; ++i) {
|
|
runtimeScene.renderAndStep();
|
|
if (i < 10) expect(object.getBehavior('auto1').isFalling()).to.be(true);
|
|
}
|
|
|
|
//Check the platform stopped the platformer object.
|
|
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').isMoving()).to.be(false);
|
|
|
|
for (var i = 0; i < 35; ++i) {
|
|
//Check that the platformer object can fall.
|
|
object.getBehavior('auto1').simulateRightKey();
|
|
runtimeScene.renderAndStep();
|
|
}
|
|
expect(object.getX()).to.be.within(87.5, 87.51);
|
|
expect(object.getY()).to.be(-24.75);
|
|
expect(object.getBehavior('auto1').isFalling()).to.be(true);
|
|
|
|
for (var i = 0; i < 100; ++i) {
|
|
//Let the speed on X axis go back to 0.
|
|
runtimeScene.renderAndStep();
|
|
}
|
|
});
|
|
|
|
it('can grab, and release, a platform', function() {
|
|
//Put the object near the right ledge of the platform.
|
|
object.setPosition(
|
|
platform.getX() + platform.getWidth() + 2,
|
|
platform.getY() - 10
|
|
);
|
|
|
|
for (var i = 0; i < 35; ++i) {
|
|
object.getBehavior('auto1').simulateLeftKey();
|
|
runtimeScene.renderAndStep();
|
|
}
|
|
|
|
//Check that the object grabbed the platform
|
|
expect(object.getX()).to.be.within(
|
|
platform.getX() + platform.getWidth() + 1,
|
|
platform.getX() + platform.getWidth() + 2
|
|
);
|
|
expect(object.getY()).to.be(platform.getY());
|
|
|
|
object.getBehavior('auto1').simulateReleaseKey();
|
|
for (var i = 0; i < 10; ++i) {
|
|
runtimeScene.renderAndStep();
|
|
}
|
|
|
|
//Check that the object is falling
|
|
expect(object.getY()).to.be(1.25);
|
|
});
|
|
|
|
it('can track object height changes', function() {
|
|
//Put the object near the right ledge of the platform.
|
|
object.setPosition(
|
|
platform.getX() + 10,
|
|
platform.getY() - object.getHeight() - 1
|
|
);
|
|
|
|
for (var i = 0; i < 15; ++i) {
|
|
runtimeScene.renderAndStep();
|
|
}
|
|
|
|
expect(object.getBehavior('auto1').isFalling()).to.be(false);
|
|
expect(object.getX()).to.be(10);
|
|
expect(object.getY()).to.be(-30); // -30 = -10 (platform y) + -20 (object height)
|
|
|
|
object.getHeight = function() {
|
|
return 9;
|
|
};
|
|
runtimeScene.renderAndStep();
|
|
expect(object.getBehavior('auto1').isFalling()).to.be(false);
|
|
expect(object.getY()).to.be(-19); // -19 = -10 (platform y) + -9 (object height)
|
|
|
|
for (var i = 0; i < 10; ++i) {
|
|
object.getBehavior('auto1').simulateRightKey();
|
|
runtimeScene.renderAndStep();
|
|
expect(object.getBehavior('auto1').isFalling()).to.be(false);
|
|
}
|
|
expect(object.getY()).to.be(-19);
|
|
expect(object.getX()).to.be.within(17.638, 17.639);
|
|
|
|
object.getHeight = function() {
|
|
return 20;
|
|
};
|
|
runtimeScene.renderAndStep();
|
|
expect(object.getY()).to.be(-30); // -30 = -10 (platform y) + -20 (object height)
|
|
});
|
|
});
|
|
|
|
describe('gdjs.PlatformerObjectRuntimeBehavior, jump and jump sustain (round coordinates on)', function() {
|
|
const runtimeScene = makeTestRuntimeScene();
|
|
|
|
//Put a platformer object on a platform
|
|
var object = new gdjs.RuntimeObject(runtimeScene, {
|
|
name: 'obj1',
|
|
type: '',
|
|
behaviors: [
|
|
{
|
|
type: 'PlatformBehavior::PlatformerObjectBehavior',
|
|
name: 'auto1',
|
|
gravity: 1500,
|
|
maxFallingSpeed: 1500,
|
|
acceleration: 500,
|
|
deceleration: 1500,
|
|
maxSpeed: 500,
|
|
jumpSpeed: 900,
|
|
canGrabPlatforms: true,
|
|
ignoreDefaultControls: true,
|
|
slopeMaxAngle: 60,
|
|
jumpSustainTime: 0.2,
|
|
roundCoordinates: true,
|
|
},
|
|
],
|
|
});
|
|
object.getWidth = function() {
|
|
return 10;
|
|
};
|
|
object.getHeight = function() {
|
|
return 20;
|
|
};
|
|
runtimeScene.addObject(object);
|
|
object.setPosition(0, -32);
|
|
|
|
//Put a platform
|
|
const platform = addPlatformObject(runtimeScene);
|
|
platform.setPosition(0, -10);
|
|
|
|
it('can jump', function() {
|
|
// Ensure the object falls on the platform
|
|
for (var i = 0; i < 10; ++i) {
|
|
runtimeScene.renderAndStep();
|
|
}
|
|
|
|
//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').isMoving()).to.be(false);
|
|
|
|
// Jump without sustaining
|
|
object.getBehavior('auto1').simulateJumpKey();
|
|
for (var i = 0; i < 18; ++i) {
|
|
runtimeScene.renderAndStep();
|
|
}
|
|
|
|
// Check that we reached the maximum height
|
|
expect(object.getY()).to.be.within(-180, -179);
|
|
runtimeScene.renderAndStep();
|
|
expect(object.getY()).to.be(-180);
|
|
runtimeScene.renderAndStep();
|
|
expect(object.getY()).to.be.within(-180, -179);
|
|
|
|
// Then let the object fall
|
|
for (var i = 0; i < 60; ++i) {
|
|
runtimeScene.renderAndStep();
|
|
}
|
|
expect(object.getY()).to.be(-30);
|
|
});
|
|
|
|
it('can jump, sustaining the jump', function() {
|
|
//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').isMoving()).to.be(false);
|
|
|
|
// Jump with sustaining as much as possible, and
|
|
// even more (18 frames at 60fps is greater than 0.2s)
|
|
for (var i = 0; i < 18; ++i) {
|
|
object.getBehavior('auto1').simulateJumpKey();
|
|
runtimeScene.renderAndStep();
|
|
}
|
|
|
|
// Check the height reached
|
|
expect(object.getY()).to.be(-230);
|
|
runtimeScene.renderAndStep();
|
|
expect(object.getY()).to.be(-235);
|
|
for (var i = 0; i < 5; ++i) {
|
|
// Verify that pressing the jump key does not change anything
|
|
object.getBehavior('auto1').simulateJumpKey();
|
|
runtimeScene.renderAndStep();
|
|
}
|
|
|
|
// Check that we reached the maximum height
|
|
expect(object.getY()).to.be(-247.5);
|
|
runtimeScene.renderAndStep();
|
|
expect(object.getY()).to.be(-247.5);
|
|
runtimeScene.renderAndStep();
|
|
expect(object.getY()).to.be.within(-247, -246);
|
|
|
|
// Then let the object fall
|
|
for (var i = 0; i < 60; ++i) {
|
|
runtimeScene.renderAndStep();
|
|
}
|
|
expect(object.getY()).to.be(-30);
|
|
});
|
|
|
|
it('can jump, and only sustain the jump while key held', function() {
|
|
//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').isMoving()).to.be(false);
|
|
|
|
// Jump with sustaining a bit (5 frames at 60fps = 0.08s), then stop
|
|
for (var i = 0; i < 5; ++i) {
|
|
object.getBehavior('auto1').simulateJumpKey();
|
|
runtimeScene.renderAndStep();
|
|
}
|
|
expect(object.getY()).to.be.within(-101, -100);
|
|
|
|
// Stop holding the jump key
|
|
runtimeScene.renderAndStep();
|
|
|
|
for (var i = 0; i < 13; ++i) {
|
|
// then hold it again (but it's too late, jump sustain is gone for this jump)
|
|
object.getBehavior('auto1').simulateJumpKey();
|
|
runtimeScene.renderAndStep();
|
|
}
|
|
|
|
// Check that we reached the maximum height
|
|
expect(object.getY()).to.be.within(-206, -205);
|
|
runtimeScene.renderAndStep();
|
|
expect(object.getY()).to.be.within(-208, -207);
|
|
runtimeScene.renderAndStep();
|
|
expect(object.getY()).to.be.within(-208, -207);
|
|
runtimeScene.renderAndStep();
|
|
expect(object.getY()).to.be.within(-208, -207);
|
|
runtimeScene.renderAndStep();
|
|
expect(object.getY()).to.be.within(-206, -205);
|
|
runtimeScene.renderAndStep();
|
|
|
|
// Then let the object fall
|
|
for (var i = 0; i < 60; ++i) {
|
|
runtimeScene.renderAndStep();
|
|
}
|
|
expect(object.getY()).to.be(-30);
|
|
});
|
|
});
|
|
|
|
describe('gdjs.PlatformerObjectRuntimeBehavior, jumpthru', function() {
|
|
const runtimeScene = makeTestRuntimeScene();
|
|
|
|
//Put a platformer object in a platform.
|
|
var object = new gdjs.RuntimeObject(runtimeScene, {
|
|
name: 'obj1',
|
|
type: '',
|
|
behaviors: [
|
|
{
|
|
type: 'PlatformBehavior::PlatformerObjectBehavior',
|
|
name: 'auto1',
|
|
roundCoordinates: true,
|
|
gravity: 900,
|
|
maxFallingSpeed: 1500,
|
|
acceleration: 500,
|
|
deceleration: 1500,
|
|
maxSpeed: 500,
|
|
jumpSpeed: 500,
|
|
canGrabPlatforms: true,
|
|
ignoreDefaultControls: true,
|
|
slopeMaxAngle: 60,
|
|
},
|
|
],
|
|
});
|
|
object.getWidth = function() {
|
|
return 10;
|
|
};
|
|
object.getHeight = function() {
|
|
return 20;
|
|
};
|
|
runtimeScene.addObject(object);
|
|
object.setPosition(0, -30);
|
|
|
|
//Put a platform
|
|
const platform = addPlatformObject(runtimeScene);
|
|
platform.setPosition(0, -10);
|
|
|
|
// Put a jump thru, higher than the platform so that the object jump from under it
|
|
// and will land on it at the end of the jump.
|
|
var jumpthru = new gdjs.RuntimeObject(runtimeScene, {
|
|
name: 'obj2',
|
|
type: '',
|
|
behaviors: [
|
|
{
|
|
type: 'PlatformBehavior::PlatformBehavior',
|
|
canBeGrabbed: true,
|
|
platformType: 'Jumpthru',
|
|
},
|
|
],
|
|
});
|
|
jumpthru.getWidth = function() {
|
|
return 60;
|
|
};
|
|
jumpthru.getHeight = function() {
|
|
return 5;
|
|
};
|
|
runtimeScene.addObject(jumpthru);
|
|
jumpthru.setPosition(0, -33);
|
|
|
|
it('can jump through the jumpthru', function() {
|
|
//Check the platform stopped the platformer object.
|
|
for (var i = 0; i < 5; ++i) {
|
|
runtimeScene.renderAndStep();
|
|
}
|
|
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').isMoving()).to.be(false);
|
|
|
|
// Check that the jump starts properly, and is not stopped on the jumpthru
|
|
object.getBehavior('auto1').simulateJumpKey();
|
|
runtimeScene.renderAndStep();
|
|
expect(object.getY()).to.be.within(-39, -38);
|
|
runtimeScene.renderAndStep();
|
|
expect(object.getY()).to.be.within(-47, -46);
|
|
runtimeScene.renderAndStep();
|
|
// At this step, the object is almost on the jumpthru (-53 + 20 (object height) = -33 (jump thru Y position)),
|
|
// but the object should not stop.
|
|
expect(object.getY()).to.be.within(-54, -53);
|
|
runtimeScene.renderAndStep();
|
|
expect(object.getY()).to.be.within(-61, -60);
|
|
runtimeScene.renderAndStep();
|
|
expect(object.getY()).to.be.within(-67, -66);
|
|
expect(object.getBehavior('auto1').isJumping()).to.be(true);
|
|
|
|
// Continue the simulation and check that position is correct in the middle of the jump
|
|
for (var i = 0; i < 20; ++i) {
|
|
runtimeScene.renderAndStep();
|
|
}
|
|
expect(object.getY()).to.be.within(-89, -88);
|
|
|
|
// Continue simulation and check that we arrive on the jumpthru
|
|
for (var i = 0; i < 10; ++i) {
|
|
runtimeScene.renderAndStep();
|
|
}
|
|
expect(object.getY()).to.be.within(
|
|
jumpthru.getY() - object.getHeight(),
|
|
jumpthru.getY() - object.getHeight() + 1
|
|
);
|
|
expect(object.getBehavior('auto1').isFalling()).to.be(false);
|
|
});
|
|
});
|
|
|
|
describe('gdjs.PlatformerObjectRuntimeBehavior, rounded coordinates (moving platforms)', function() {
|
|
const runtimeScene = makeTestRuntimeScene();
|
|
|
|
//Put a platformer object on a platform.
|
|
var object = new gdjs.RuntimeObject(runtimeScene, {
|
|
name: 'obj1',
|
|
type: '',
|
|
behaviors: [
|
|
{
|
|
type: 'PlatformBehavior::PlatformerObjectBehavior',
|
|
name: 'auto1',
|
|
roundCoordinates: true,
|
|
gravity: 900,
|
|
maxFallingSpeed: 1500,
|
|
acceleration: 500,
|
|
deceleration: 1500,
|
|
maxSpeed: 500,
|
|
jumpSpeed: 1500,
|
|
canGrabPlatforms: true,
|
|
ignoreDefaultControls: true,
|
|
slopeMaxAngle: 60,
|
|
},
|
|
],
|
|
});
|
|
object.getWidth = function() {
|
|
return 10;
|
|
};
|
|
object.getHeight = function() {
|
|
return 20;
|
|
};
|
|
runtimeScene.addObject(object);
|
|
object.setPosition(0, -30);
|
|
|
|
//Put a platform
|
|
const platform = addPlatformObject(runtimeScene);
|
|
platform.setPosition(0, -10);
|
|
|
|
it('follows the platform', function() {
|
|
for (var i = 0; i < 30; ++i) {
|
|
runtimeScene.renderAndStep();
|
|
}
|
|
|
|
// Check the object has not moved.
|
|
expect(object.getY()).to.be(-30);
|
|
expect(object.getX()).to.be(0);
|
|
expect(object.getBehavior('auto1').isOnFloor()).to.be(true);
|
|
expect(object.getBehavior('auto1').isFalling()).to.be(false);
|
|
expect(object.getBehavior('auto1').isMoving()).to.be(false);
|
|
|
|
// Check that the object follow the platform, even if the
|
|
// movement is less than one pixel.
|
|
platform.setX(platform.getX() + 0.12);
|
|
runtimeScene.renderAndStep();
|
|
platform.setX(platform.getX() + 0.12);
|
|
runtimeScene.renderAndStep();
|
|
platform.setX(platform.getX() + 0.12);
|
|
runtimeScene.renderAndStep();
|
|
|
|
expect(object.getX()).to.be(0.36);
|
|
});
|
|
});
|