Files
GDevelop/GDJS/tests/tests/runtimeobject.js
T

416 lines
12 KiB
JavaScript

// @ts-check
/**
* Common tests for gdjs game engine.
* See README.md for more information.
*/
describe('gdjs.RuntimeObject', () => {
const runtimeGame = gdjs.getPixiRuntimeGame();
const runtimeScene = new gdjs.RuntimeScene(runtimeGame);
it('should compute distances properly', () => {
const object = new gdjs.TestRuntimeObject(runtimeScene, {
name: 'obj1',
type: '',
variables: [],
behaviors: [],
effects: [],
});
object.setPosition(15, 20);
expect(object.getSqDistanceToPosition(-110, 200)).to.be(48025);
});
it('should compute angles properly', () => {
const object = new gdjs.TestRuntimeObject(runtimeScene, {
name: 'obj1',
type: '',
variables: [],
behaviors: [],
effects: [],
});
object.setPosition(15, 20);
expect(object.getAngleToPosition(-110, 200)).to.be(124.77783136636388);
});
it('should compute AABB properly', () => {
const object = new gdjs.TestRuntimeObject(runtimeScene, {
name: 'obj1',
type: '',
variables: [],
behaviors: [],
effects: [],
});
object.setCustomWidthAndHeight(10, 20);
expect(object.getAABB()).to.eql({
min: [0, 0],
max: [10, 20],
});
// Verify the shortcut functions too:
expect(object.getAABBLeft()).to.be(0);
expect(object.getAABBTop()).to.be(0);
expect(object.getAABBRight()).to.be(10);
expect(object.getAABBBottom()).to.be(20);
expect(object.getAABBCenterX()).to.be(5);
expect(object.getAABBCenterY()).to.be(10);
object.setPosition(15, 20);
expect(object.getAABB()).to.eql({
min: [15, 20],
max: [25, 40],
});
object.setAngle(90);
expect(object.getAABB()).to.eql({
min: [10, 25],
max: [30, 35],
});
object.setAngle(0);
object.setCustomCenter(0, 0);
expect(object.getAABB()).to.eql({
min: [15, 20],
max: [25, 40],
});
object.setPosition(15, 20);
object.setAngle(90);
expect(object.getAABB()).to.eql({
min: [-5, 20],
max: [15, 30],
});
// Verify the shortcut functions again too:
expect(object.getAABBLeft()).to.be(-5);
expect(object.getAABBTop()).to.be(20);
expect(object.getAABBRight()).to.be(15);
expect(object.getAABBBottom()).to.be(30);
expect(object.getAABBCenterX()).to.be(5);
expect(object.getAABBCenterY()).to.be(25);
});
it('handles collision', () => {
const object1 = new gdjs.TestRuntimeObject(runtimeScene, {
name: 'obj1',
type: '',
variables: [],
behaviors: [],
effects: [],
});
object1.setCustomWidthAndHeight(10, 20);
object1.setCustomCenter(0, 0);
const object2 = new gdjs.TestRuntimeObject(runtimeScene, {
name: 'obj1',
type: '',
variables: [],
behaviors: [],
effects: [],
});
object2.setCustomWidthAndHeight(10, 20);
object2.setCustomCenter(0, 0);
// Overlapping objects.
expect(gdjs.RuntimeObject.collisionTest(object1, object2, false)).to.be(
true
);
// Edge-touching objects.
object2.setPosition(10, 0); // Move object2 to be to the right of object1.
expect(gdjs.RuntimeObject.collisionTest(object1, object2, false)).to.be(
true
);
expect(gdjs.RuntimeObject.collisionTest(object1, object2, true)).to.be(
false
);
object2.setPosition(10, 6); // Move object2 to be to the right of object1, slightly under it but still edge touching.
expect(gdjs.RuntimeObject.collisionTest(object1, object2, false)).to.be(
true
);
expect(gdjs.RuntimeObject.collisionTest(object1, object2, true)).to.be(
false
);
// Rotated objects.
object2.setPosition(10, 0);
object1.setAngle(45); // Set both objects to be rotated
object2.setAngle(45);
expect(gdjs.RuntimeObject.collisionTest(object1, object2, false)).to.be(
true
);
expect(gdjs.RuntimeObject.collisionTest(object1, object2, true)).to.be(
true
);
object2.setPosition(10, 6); // Move object 2 to be slightly under object 1. They are not touching anymore then, because they are rotated.
expect(gdjs.RuntimeObject.collisionTest(object1, object2, false)).to.be(
false
);
expect(gdjs.RuntimeObject.collisionTest(object1, object2, true)).to.be(
false
);
// Objects not even close.
object2.setPosition(20, 0);
expect(gdjs.RuntimeObject.collisionTest(object1, object2, false)).to.be(
false
);
expect(gdjs.RuntimeObject.collisionTest(object1, object2, false)).to.be(
false
);
});
it('handles raycast', () => {
const object1 = new gdjs.TestRuntimeObject(runtimeScene, {
name: 'obj1',
type: '',
variables: [],
behaviors: [],
effects: [],
});
object1.setCustomWidthAndHeight(10, 20);
object1.setCustomCenter(10, 10);
// Raycast of length 0:
object1.setPosition(20, 30);
expect(object1.raycastTest(10, 10, 10, 10, true).collision).to.be(false);
// Raycast too short:
object1.setPosition(20, 30);
expect(object1.raycastTest(10, 10, 15, 15, true).collision).to.be(false);
// Raycast inside the object:
object1.setPosition(20, 30);
expect(object1.raycastTest(10, 10, 25, 35, true)).to.eql({
collision: true,
closeX: 22,
closeY: 30,
closeSqDist: 544,
farX: 22,
farY: 30,
farSqDist: 544,
});
// Raycast beyond the object, still colliding with it:
object1.setPosition(20, 30);
expect(object1.raycastTest(10, 10, 55, 55, true)).to.eql({
collision: true,
closeX: 30,
closeY: 30,
closeSqDist: 800,
farX: 30,
farY: 30,
farSqDist: 800,
});
// Raycast with an end point far beyond the object, still colliding with it:
object1.setPosition(20, 30);
expect(object1.raycastTest(10, 10, 5000, 5000, true)).to.eql({
collision: true,
closeX: 30,
closeY: 30,
closeSqDist: 800,
farX: 30,
farY: 30,
farSqDist: 800,
});
// Vertical raycast, far from the origin:
object1.setPosition(20, 300);
expect(object1.raycastTest(25, 500, 25, 250, true).collision).to.be(true);
// Vertical raycast, far from the origin, to the edge of the object:
object1.setPosition(20, 300);
expect(object1.raycastTest(25, 500, 25, 300 + 19, true).collision).to.be(
true
);
expect(object1.raycastTest(25, 500, 25, 300 + 20, true).collision).to.be(
true
);
expect(object1.raycastTest(25, 500, 25, 300 + 20.1, true).collision).to.be(
false
);
expect(object1.raycastTest(25, 500, 25, 300 + 20.5, true).collision).to.be(
false
);
expect(object1.raycastTest(25, 500, 25, 300 + 21, true).collision).to.be(
false
);
// Horizontal raycast, far from the origin:
object1.setPosition(200, 30);
expect(object1.raycastTest(500, 35, 190, 35, true).collision).to.be(true);
// Horizontal raycast, far from the origin, to the edge of the object:
object1.setPosition(200, 30);
expect(object1.raycastTest(500, 35, 200 + 9, 35, true).collision).to.be(
true
);
expect(object1.raycastTest(500, 35, 200 + 10, 35, true).collision).to.be(
true
);
expect(object1.raycastTest(500, 35, 200 + 10.1, 35, true).collision).to.be(
false
);
expect(object1.raycastTest(500, 35, 200 + 10.5, 35, true).collision).to.be(
false
);
expect(object1.raycastTest(500, 35, 200 + 11, 35, true).collision).to.be(
false
);
// Raycast not intersecting with the object
object1.setPosition(20, 30);
expect(object1.raycastTest(10, 10, 105, 55, true).collision).to.be(false);
});
it('handles raycast (object with multiple hitboxes)', () => {
const objectWithTwoHitboxes = new gdjs.TestSpriteRuntimeObject(
runtimeScene,
{
name: 'objectWithTwoHitboxes',
type: '',
behaviors: [],
effects: [],
animations: [
{
name: 'animation',
directions: [
{
sprites: [
{
originPoint: { x: 0, y: 0 },
centerPoint: { x: 50, y: 50 },
points: [
{ name: 'Center', x: 0, y: 0 },
{ name: 'Origin', x: 50, y: 50 },
],
hasCustomCollisionMask: true,
customCollisionMask: [
[
{ x: 75, y: 100 },
{ x: 0, y: 100 },
{ x: 0, y: 25 },
],
[
{ x: 25, y: 0 },
{ x: 100, y: 75 },
{ x: 100, y: 0 },
],
],
},
],
},
],
},
],
}
);
runtimeScene.addObject(objectWithTwoHitboxes);
objectWithTwoHitboxes.setUnscaledWidthAndHeight(100, 100);
objectWithTwoHitboxes.setCustomWidthAndHeight(100, 100);
// Ray going through the "tunnel" left by the two triangle hitboxes:
objectWithTwoHitboxes.setPosition(0, 0);
expect(
objectWithTwoHitboxes.raycastTest(0, 0, 300, 300, true).collision
).to.be(false);
expect(
objectWithTwoHitboxes.raycastTest(0, 10, 300, 300 + 10, true).collision
).to.be(false);
expect(
objectWithTwoHitboxes.raycastTest(10, 0, 300 + 10, 300, true).collision
).to.be(false);
const rayCastFromCenterToRightResult = objectWithTwoHitboxes.raycastTest(
50,
50,
300,
50,
true
);
expect(rayCastFromCenterToRightResult.collision).to.be(true);
expect(rayCastFromCenterToRightResult.closeX).to.be(75);
expect(rayCastFromCenterToRightResult.closeY).to.be(50);
const rayCastFromCenterToRightFarResult = objectWithTwoHitboxes.raycastTest(
50,
50,
300,
50,
false
);
expect(rayCastFromCenterToRightFarResult.collision).to.be(true);
expect(rayCastFromCenterToRightFarResult.farX).to.be(100);
expect(rayCastFromCenterToRightFarResult.farY).to.be(50);
const rayCastFromCenterToLeftResult = objectWithTwoHitboxes.raycastTest(
50,
50,
-300,
50,
true
);
expect(rayCastFromCenterToLeftResult.collision).to.be(true);
expect(rayCastFromCenterToLeftResult.closeX).to.be(25);
expect(rayCastFromCenterToLeftResult.closeY).to.be(50);
const rayCastFromCenterToLeftFarResult = objectWithTwoHitboxes.raycastTest(
50,
50,
-300,
50,
true
);
expect(rayCastFromCenterToLeftFarResult.collision).to.be(true);
expect(rayCastFromCenterToLeftFarResult.farX).to.be(0);
expect(rayCastFromCenterToLeftFarResult.farY).to.be(50);
const rayCastFromMiddleTopResult = objectWithTwoHitboxes.raycastTest(
50,
-20,
50,
300,
true
);
expect(rayCastFromMiddleTopResult.collision).to.be(true);
expect(rayCastFromMiddleTopResult.closeX).to.be(50);
expect(rayCastFromMiddleTopResult.closeY).to.be(0);
const rayCastFromMiddleTopFarResult = objectWithTwoHitboxes.raycastTest(
50,
-20,
50,
300,
false
);
expect(rayCastFromMiddleTopFarResult.collision).to.be(true);
expect(rayCastFromMiddleTopFarResult.farX).to.be(50);
expect(rayCastFromMiddleTopFarResult.farY).to.be(100);
const rayCastFromMiddleLeftResult = objectWithTwoHitboxes.raycastTest(
-20,
50,
300,
50,
true
);
expect(rayCastFromMiddleLeftResult.collision).to.be(true);
expect(rayCastFromMiddleLeftResult.closeX).to.be(0);
expect(rayCastFromMiddleLeftResult.closeY).to.be(50);
const rayCastFromMiddleLeftFarResult = objectWithTwoHitboxes.raycastTest(
-20,
50,
300,
50,
false
);
expect(rayCastFromMiddleLeftFarResult.collision).to.be(true);
expect(rayCastFromMiddleLeftFarResult.farX).to.be(100);
expect(rayCastFromMiddleLeftFarResult.farY).to.be(50);
});
});