mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Fix the collision mask of rotated tiles that were sometimes misplaced (#4181)
This commit is contained in:
@@ -714,7 +714,8 @@ namespace gdjs {
|
||||
tileTransformation.flipY(height / 2);
|
||||
}
|
||||
if (this.layer.isFlippedDiagonally(this.x, this.y)) {
|
||||
tileTransformation.flipDiagonally();
|
||||
tileTransformation.flipX(width / 2);
|
||||
tileTransformation.rotateAround(Math.PI / 2, width / 2, height / 2);
|
||||
}
|
||||
tileTransformation.preConcatenate(layerTransformation);
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
{"version":3,"file":"TileMapPixiHelper.d.ts","sourceRoot":"","sources":["../../src/render/TileMapPixiHelper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAEL,eAAe,EAEhB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC;AAGpC,qBAAa,iBAAiB;IAC5B;;;;;;;OAOG;IACH,MAAM,CAAC,UAAU,CACf,QAAQ,EAAE,QAAQ,EAClB,YAAY,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,IAAI,EACpD,UAAU,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,GACnE,gBAAgB,GAAG,IAAI;IA6F1B;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,iBAAiB,CACtB,kBAAkB,EAAE,GAAG,EACvB,OAAO,EAAE,eAAe,EACxB,YAAY,EAAE,gBAAgB,EAC9B,WAAW,EAAE,OAAO,GAAG,SAAS,GAAG,KAAK,EACxC,UAAU,EAAE,MAAM,GACjB,IAAI;IAiFP;;OAEG;IACH,MAAM,CAAC,uBAAuB,CAC5B,YAAY,EAAE,IAAI,CAAC,QAAQ,EAC3B,OAAO,EAAE,eAAe,EACxB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,OAAO,EACpB,YAAY,EAAE,OAAO,EACrB,cAAc,EAAE,KAAK,EACrB,SAAS,EAAE,OAAO,EAClB,WAAW,EAAE,KAAK,GACjB,IAAI;CA+DR"}
|
||||
{"version":3,"file":"TileMapPixiHelper.d.ts","sourceRoot":"","sources":["../../src/render/TileMapPixiHelper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAEL,eAAe,EAEhB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC;AAGpC,qBAAa,iBAAiB;IAC5B;;;;;;;OAOG;IACH,MAAM,CAAC,UAAU,CACf,QAAQ,EAAE,QAAQ,EAClB,YAAY,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,IAAI,EACpD,UAAU,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,GACnE,gBAAgB,GAAG,IAAI;IA6F1B;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,iBAAiB,CACtB,kBAAkB,EAAE,GAAG,EACvB,OAAO,EAAE,eAAe,EACxB,YAAY,EAAE,gBAAgB,EAC9B,WAAW,EAAE,OAAO,GAAG,SAAS,GAAG,KAAK,EACxC,UAAU,EAAE,MAAM,GACjB,IAAI;IAiFP;;OAEG;IACH,MAAM,CAAC,uBAAuB,CAC5B,YAAY,EAAE,IAAI,CAAC,QAAQ,EAC3B,OAAO,EAAE,eAAe,EACxB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,OAAO,EACpB,YAAY,EAAE,OAAO,EACrB,cAAc,EAAE,KAAK,EACrB,SAAS,EAAE,OAAO,EAClB,WAAW,EAAE,KAAK,GACjB,IAAI;CAiER"}
|
@@ -178,7 +178,7 @@ export declare type TiledTileset = {
|
||||
/** The number of tile columns in the tileset */
|
||||
columns: integer;
|
||||
/** GID corresponding to the first tile in the set */
|
||||
firstgid: integer;
|
||||
firstgid?: integer;
|
||||
/** (optional) */
|
||||
grid?: TiledGrid;
|
||||
/** Image used for tiles in this set */
|
||||
|
File diff suppressed because one or more lines are too long
@@ -15,6 +15,14 @@ describe('gdjs.TileMapCollisionMaskRuntimeObject', function () {
|
||||
userAdded: true,
|
||||
alwaysLoaded: true,
|
||||
},
|
||||
{
|
||||
file: 'base/tests-utils/simple-tiled-map/FlippingTiledMap.json',
|
||||
kind: 'json',
|
||||
metadata: '',
|
||||
name: 'FlippingTiledMap.json',
|
||||
userAdded: true,
|
||||
alwaysLoaded: true,
|
||||
},
|
||||
{
|
||||
file: 'base/tests-utils/simple-tiled-map/MiniTiledSet.json',
|
||||
kind: 'json',
|
||||
@@ -63,14 +71,14 @@ describe('gdjs.TileMapCollisionMaskRuntimeObject', function () {
|
||||
};
|
||||
};
|
||||
|
||||
const addTileMapCollisionMask = (runtimeScene) => {
|
||||
const addTileMapCollisionMask = (runtimeScene, tileMapJsonFile) => {
|
||||
const tileMap = new gdjs.TileMapCollisionMaskRuntimeObject(runtimeScene, {
|
||||
name: 'tilemap',
|
||||
type: 'TileMap::CollisionMask',
|
||||
behaviors: [],
|
||||
effects: [],
|
||||
content: {
|
||||
tilemapJsonFile: 'SmallTiledMap.json',
|
||||
tilemapJsonFile: tileMapJsonFile,
|
||||
tilesetJsonFile: 'MiniTiledSet.json',
|
||||
layerIndex: 0,
|
||||
collisionMaskTag: 'obstacle',
|
||||
@@ -101,138 +109,241 @@ describe('gdjs.TileMapCollisionMaskRuntimeObject', function () {
|
||||
|
||||
const delay = (ms) => new Promise((res) => setTimeout(res, ms));
|
||||
|
||||
let runtimeScene;
|
||||
/**
|
||||
* @type {gdjs.TileMapCollisionMaskRuntimeObject}
|
||||
*/
|
||||
let tileMap;
|
||||
beforeEach(async function () {
|
||||
runtimeScene = createScene();
|
||||
tileMap = addTileMapCollisionMask(runtimeScene);
|
||||
// TODO find a clean way to wait for the json to be read.
|
||||
for (
|
||||
let index = 0;
|
||||
index < 200 && tileMap._collisionTileMap.getDimensionX() === 0;
|
||||
index++
|
||||
) {
|
||||
await delay(5);
|
||||
}
|
||||
if (tileMap._collisionTileMap.getDimensionX() === 0) {
|
||||
throw new Error('Timeout reading the tile map JSON file.');
|
||||
}
|
||||
describe('Basic cases', function () {
|
||||
let runtimeScene;
|
||||
/**
|
||||
* @type {gdjs.TileMapCollisionMaskRuntimeObject}
|
||||
*/
|
||||
let tileMap;
|
||||
beforeEach(async function () {
|
||||
runtimeScene = createScene();
|
||||
tileMap = addTileMapCollisionMask(runtimeScene, 'SmallTiledMap.json');
|
||||
// TODO find a clean way to wait for the json to be read.
|
||||
for (
|
||||
let index = 0;
|
||||
index < 200 && tileMap._collisionTileMap.getDimensionX() === 0;
|
||||
index++
|
||||
) {
|
||||
await delay(5);
|
||||
}
|
||||
if (tileMap._collisionTileMap.getDimensionX() === 0) {
|
||||
throw new Error('Timeout reading the tile map JSON file.');
|
||||
}
|
||||
});
|
||||
|
||||
it('can be measured', function () {
|
||||
tileMap.setPosition(100, 200);
|
||||
|
||||
expect(tileMap.getWidth()).to.be(32);
|
||||
expect(tileMap.getHeight()).to.be(16);
|
||||
expect(tileMap.getCenterX()).to.be(16);
|
||||
expect(tileMap.getCenterY()).to.be(8);
|
||||
});
|
||||
|
||||
/**
|
||||
* insideObject usually use the AABB of the object.
|
||||
* But, in case of a tile map, it makes more sense to look each tile individually.
|
||||
* It returns true when there is an hitbox in the tile.
|
||||
*/
|
||||
it('can detect a point inside the collision mask', function () {
|
||||
tileMap.setPosition(100, 200);
|
||||
|
||||
// The point is in the black square with an hitbox.
|
||||
expect(tileMap.insideObject(104, 204)).to.be(true);
|
||||
expect(tileMap.isCollidingWithPoint(104, 204)).to.be(true);
|
||||
|
||||
// The point is in wite square without any hitbox.
|
||||
expect(tileMap.insideObject(112, 212)).to.be(false);
|
||||
expect(tileMap.isCollidingWithPoint(112, 212)).to.be(false);
|
||||
|
||||
// The point is in the top black triangle that has an hitbox.
|
||||
expect(tileMap.insideObject(120, 202)).to.be(true);
|
||||
expect(tileMap.isCollidingWithPoint(120, 202)).to.be(true);
|
||||
|
||||
// The point is in the left white triangle that has an hitbox.
|
||||
expect(tileMap.insideObject(118, 204)).to.be(true);
|
||||
expect(tileMap.isCollidingWithPoint(118, 204)).to.be(false);
|
||||
});
|
||||
|
||||
it('can detect collisions with an object', function () {
|
||||
tileMap.setPosition(100, 200);
|
||||
|
||||
const object = addObject(runtimeScene);
|
||||
|
||||
object.setPosition(96, 196);
|
||||
expect(gdjs.RuntimeObject.collisionTest(object, tileMap, true)).to.be(
|
||||
true
|
||||
);
|
||||
|
||||
object.setPosition(90, 190);
|
||||
expect(gdjs.RuntimeObject.collisionTest(object, tileMap, true)).to.be(
|
||||
false
|
||||
);
|
||||
|
||||
object.setPosition(115, 207);
|
||||
expect(gdjs.RuntimeObject.collisionTest(object, tileMap, true)).to.be(
|
||||
true
|
||||
);
|
||||
|
||||
object.setPosition(116, 208);
|
||||
expect(gdjs.RuntimeObject.collisionTest(object, tileMap, true)).to.be(
|
||||
false
|
||||
);
|
||||
});
|
||||
|
||||
it('can check collisions with an object on empty tiles without any issue', function () {
|
||||
tileMap.setPosition(100, 200);
|
||||
|
||||
const object = addObject(runtimeScene);
|
||||
|
||||
object.setPosition(116, 208);
|
||||
expect(gdjs.RuntimeObject.collisionTest(object, tileMap, true)).to.be(
|
||||
false
|
||||
);
|
||||
});
|
||||
|
||||
it('can detect collisions with an object on vertically flipped tiles', function () {
|
||||
tileMap.setPosition(100, 200);
|
||||
|
||||
const object = addObject(runtimeScene);
|
||||
|
||||
// The object is over the black triangle.
|
||||
object.setPosition(118, 214);
|
||||
expect(gdjs.RuntimeObject.collisionTest(object, tileMap, true)).to.be(
|
||||
true
|
||||
);
|
||||
|
||||
// The object is over the red triangle without touching a black polygon.
|
||||
object.setPosition(130, 204);
|
||||
expect(gdjs.RuntimeObject.collisionTest(object, tileMap, true)).to.be(
|
||||
false
|
||||
);
|
||||
});
|
||||
|
||||
it("can detect collisions with an object when it's rotated", function () {
|
||||
tileMap.setPosition(100, 200);
|
||||
tileMap.setAngle(90);
|
||||
|
||||
const object = addObject(runtimeScene);
|
||||
|
||||
object.setPosition(123, 185);
|
||||
expect(gdjs.RuntimeObject.collisionTest(object, tileMap, true)).to.be(
|
||||
true
|
||||
);
|
||||
|
||||
object.setPosition(124, 184);
|
||||
expect(gdjs.RuntimeObject.collisionTest(object, tileMap, true)).to.be(
|
||||
false
|
||||
);
|
||||
});
|
||||
|
||||
it('can detect collisions with an object when it has a custom size', function () {
|
||||
tileMap.setPosition(100, 200);
|
||||
tileMap.setWidth(2 * tileMap.getWidth());
|
||||
tileMap.setHeight(2 * tileMap.getHeight());
|
||||
|
||||
const object = addObject(runtimeScene);
|
||||
|
||||
object.setPosition(163, 231);
|
||||
expect(gdjs.RuntimeObject.collisionTest(object, tileMap, true)).to.be(
|
||||
true
|
||||
);
|
||||
|
||||
object.setPosition(164, 232);
|
||||
expect(gdjs.RuntimeObject.collisionTest(object, tileMap, true)).to.be(
|
||||
false
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('can be measured', function () {
|
||||
tileMap.setPosition(100, 200);
|
||||
describe('Flipping cases', function () {
|
||||
let runtimeScene;
|
||||
/**
|
||||
* @type {gdjs.TileMapCollisionMaskRuntimeObject}
|
||||
*/
|
||||
let tileMap;
|
||||
beforeEach(async function () {
|
||||
runtimeScene = createScene();
|
||||
tileMap = addTileMapCollisionMask(runtimeScene, 'FlippingTiledMap.json');
|
||||
// TODO find a clean way to wait for the json to be read.
|
||||
for (
|
||||
let index = 0;
|
||||
index < 200 && tileMap._collisionTileMap.getDimensionX() === 0;
|
||||
index++
|
||||
) {
|
||||
await delay(5);
|
||||
}
|
||||
if (tileMap._collisionTileMap.getDimensionX() === 0) {
|
||||
throw new Error('Timeout reading the tile map JSON file.');
|
||||
}
|
||||
});
|
||||
|
||||
expect(tileMap.getWidth()).to.be(32);
|
||||
expect(tileMap.getHeight()).to.be(16);
|
||||
expect(tileMap.getCenterX()).to.be(16);
|
||||
expect(tileMap.getCenterY()).to.be(8);
|
||||
});
|
||||
// 4 rotations
|
||||
|
||||
/**
|
||||
* insideObject usually use the AABB of the object.
|
||||
* But, in case of a tile map, it makes more sense to look each tile individually.
|
||||
* It returns true when there is an hitbox in the tile.
|
||||
*/
|
||||
it('can detect a point inside the collision mask', function () {
|
||||
tileMap.setPosition(100, 200);
|
||||
it('can detect a point inside (vertical: false, horizontal: false, diagonal: false)', function () {
|
||||
tileMap.setPosition(100, 200);
|
||||
|
||||
// The point is in the black square with an hitbox.
|
||||
expect(tileMap.insideObject(104, 204)).to.be(true);
|
||||
expect(tileMap.isCollidingWithPoint(104, 204)).to.be(true);
|
||||
const x = 100;
|
||||
const y = 200;
|
||||
expect(tileMap.isCollidingWithPoint(x + 3, y + 1)).to.be(true);
|
||||
});
|
||||
|
||||
// The point is in wite square without any hitbox.
|
||||
expect(tileMap.insideObject(112, 212)).to.be(false);
|
||||
expect(tileMap.isCollidingWithPoint(112, 212)).to.be(false);
|
||||
it('can detect a point inside (vertical: false, horizontal: true, diagonal: true)', function () {
|
||||
tileMap.setPosition(100, 200);
|
||||
|
||||
// The point is in black triangle part of the square that has an hitbox.
|
||||
expect(tileMap.insideObject(102, 210)).to.be(true);
|
||||
expect(tileMap.isCollidingWithPoint(102, 210)).to.be(true);
|
||||
const x = 108;
|
||||
const y = 200;
|
||||
expect(tileMap.isCollidingWithPoint(x + 7, y + 3)).to.be(true);
|
||||
});
|
||||
|
||||
// The point is in white triangle part of the square that has no hitbox.
|
||||
expect(tileMap.insideObject(106, 214)).to.be(true);
|
||||
expect(tileMap.isCollidingWithPoint(106, 214)).to.be(false);
|
||||
});
|
||||
it('can detect a point inside (vertical: true, horizontal: true, diagonal: false)', function () {
|
||||
tileMap.setPosition(100, 200);
|
||||
|
||||
it('can detect collisions with an object', function () {
|
||||
tileMap.setPosition(100, 200);
|
||||
const x = 108;
|
||||
const y = 208;
|
||||
expect(tileMap.isCollidingWithPoint(x + 5, y + 7)).to.be(true);
|
||||
});
|
||||
|
||||
const object = addObject(runtimeScene);
|
||||
it('can detect a point inside (vertical: true, horizontal: false, diagonal: true)', function () {
|
||||
tileMap.setPosition(100, 200);
|
||||
|
||||
object.setPosition(96, 196);
|
||||
expect(gdjs.RuntimeObject.collisionTest(object, tileMap, true)).to.be(true);
|
||||
const x = 100;
|
||||
const y = 208;
|
||||
expect(tileMap.isCollidingWithPoint(x + 1, y + 5)).to.be(true);
|
||||
});
|
||||
|
||||
object.setPosition(90, 190);
|
||||
expect(gdjs.RuntimeObject.collisionTest(object, tileMap, true)).to.be(
|
||||
false
|
||||
);
|
||||
// 4 rotations but diagonal is negated
|
||||
|
||||
object.setPosition(115, 207);
|
||||
expect(gdjs.RuntimeObject.collisionTest(object, tileMap, true)).to.be(true);
|
||||
it('can detect a point inside (vertical: false, horizontal: false, diagonal: true)', function () {
|
||||
tileMap.setPosition(100, 200);
|
||||
|
||||
object.setPosition(116, 208);
|
||||
expect(gdjs.RuntimeObject.collisionTest(object, tileMap, true)).to.be(
|
||||
false
|
||||
);
|
||||
});
|
||||
const x = 116;
|
||||
const y = 200;
|
||||
expect(tileMap.isCollidingWithPoint(x + 1, y + 3)).to.be(true);
|
||||
});
|
||||
|
||||
it('can check collisions with an object on empty tiles without any issue', function () {
|
||||
tileMap.setPosition(100, 200);
|
||||
it('can detect a point inside (vertical: false, horizontal: true, diagonal: false)', function () {
|
||||
tileMap.setPosition(100, 200);
|
||||
|
||||
const object = addObject(runtimeScene);
|
||||
const x = 124;
|
||||
const y = 200;
|
||||
expect(tileMap.isCollidingWithPoint(x + 5, y + 1)).to.be(true);
|
||||
});
|
||||
|
||||
object.setPosition(116, 208);
|
||||
expect(gdjs.RuntimeObject.collisionTest(object, tileMap, true)).to.be(
|
||||
false
|
||||
);
|
||||
});
|
||||
it('can detect a point inside (vertical: true, horizontal: true, diagonal: true)', function () {
|
||||
tileMap.setPosition(100, 200);
|
||||
|
||||
it('can detect collisions with an object on flipped tiles', function () {
|
||||
tileMap.setPosition(100, 200);
|
||||
const x = 124;
|
||||
const y = 208;
|
||||
expect(tileMap.isCollidingWithPoint(x + 7, y + 5)).to.be(true);
|
||||
});
|
||||
|
||||
const object = addObject(runtimeScene);
|
||||
it('can detect a point inside (vertical: true, horizontal: false, diagonal: false)', function () {
|
||||
tileMap.setPosition(100, 200);
|
||||
|
||||
// The object is over the black triangle.
|
||||
object.setPosition(118, 214);
|
||||
expect(gdjs.RuntimeObject.collisionTest(object, tileMap, true)).to.be(true);
|
||||
|
||||
// The object is over the red triangle without touching a black polygon.
|
||||
object.setPosition(130, 204);
|
||||
expect(gdjs.RuntimeObject.collisionTest(object, tileMap, true)).to.be(
|
||||
false
|
||||
);
|
||||
});
|
||||
|
||||
it("can detect collisions with an object when it's rotated", function () {
|
||||
tileMap.setPosition(100, 200);
|
||||
tileMap.setAngle(90);
|
||||
|
||||
const object = addObject(runtimeScene);
|
||||
|
||||
object.setPosition(123, 185);
|
||||
expect(gdjs.RuntimeObject.collisionTest(object, tileMap, true)).to.be(true);
|
||||
|
||||
object.setPosition(124, 184);
|
||||
expect(gdjs.RuntimeObject.collisionTest(object, tileMap, true)).to.be(
|
||||
false
|
||||
);
|
||||
});
|
||||
|
||||
it('can detect collisions with an object when it has a custom size', function () {
|
||||
tileMap.setPosition(100, 200);
|
||||
tileMap.setWidth(2 * tileMap.getWidth());
|
||||
tileMap.setHeight(2 * tileMap.getHeight());
|
||||
|
||||
const object = addObject(runtimeScene);
|
||||
|
||||
object.setPosition(163, 231);
|
||||
expect(gdjs.RuntimeObject.collisionTest(object, tileMap, true)).to.be(true);
|
||||
|
||||
object.setPosition(164, 232);
|
||||
expect(gdjs.RuntimeObject.collisionTest(object, tileMap, true)).to.be(
|
||||
false
|
||||
);
|
||||
const x = 116;
|
||||
const y = 208;
|
||||
expect(tileMap.isCollidingWithPoint(x + 3, y + 7)).to.be(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -347,27 +347,6 @@ namespace gdjs {
|
||||
this.translate(0, -anchorY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenate a flip between X and Y.
|
||||
*/
|
||||
flipDiagonally() {
|
||||
const matrix = this.matrix;
|
||||
|
||||
const m0 = matrix[0];
|
||||
const m1 = matrix[1];
|
||||
const m2 = matrix[2];
|
||||
const m3 = matrix[3];
|
||||
const m4 = matrix[4];
|
||||
const m5 = matrix[5];
|
||||
|
||||
matrix[0] = m1;
|
||||
matrix[1] = m0;
|
||||
matrix[2] = m3;
|
||||
matrix[3] = m2;
|
||||
matrix[4] = m5;
|
||||
matrix[5] = m4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenate a transformation after this one.
|
||||
* @param other The transformation to concatenate.
|
||||
|
@@ -0,0 +1,33 @@
|
||||
{ "compressionlevel":-1,
|
||||
"height":2,
|
||||
"infinite":false,
|
||||
"layers":[
|
||||
{
|
||||
"data":[3, 2684354563, 536870915, 2147483651,
|
||||
1610612739, 3221225475, 1073741827, 3758096387],
|
||||
"height":2,
|
||||
"id":1,
|
||||
"name":"Tile Layer 1",
|
||||
"opacity":1,
|
||||
"type":"tilelayer",
|
||||
"visible":true,
|
||||
"width":4,
|
||||
"x":0,
|
||||
"y":0
|
||||
}],
|
||||
"nextlayerid":2,
|
||||
"nextobjectid":1,
|
||||
"orientation":"orthogonal",
|
||||
"renderorder":"right-down",
|
||||
"tiledversion":"1.9.0",
|
||||
"tileheight":8,
|
||||
"tilesets":[
|
||||
{
|
||||
"firstgid":1,
|
||||
"source":"MiniTiledSet.json"
|
||||
}],
|
||||
"tilewidth":8,
|
||||
"type":"map",
|
||||
"version":"1.9",
|
||||
"width":4
|
||||
}
|
@@ -6,10 +6,11 @@
|
||||
"name":"new tileset",
|
||||
"spacing":0,
|
||||
"tilecount":6,
|
||||
"tiledversion":"1.7.2",
|
||||
"tiledversion":"1.9.0",
|
||||
"tileheight":8,
|
||||
"tiles":[
|
||||
{
|
||||
"class":"obstacle",
|
||||
"id":0,
|
||||
"objectgroup":
|
||||
{
|
||||
@@ -17,11 +18,11 @@
|
||||
"name":"",
|
||||
"objects":[
|
||||
{
|
||||
"class":"",
|
||||
"height":8,
|
||||
"id":1,
|
||||
"name":"",
|
||||
"rotation":0,
|
||||
"class":"",
|
||||
"visible":true,
|
||||
"width":8,
|
||||
"x":0,
|
||||
@@ -32,50 +33,11 @@
|
||||
"visible":true,
|
||||
"x":0,
|
||||
"y":0
|
||||
},
|
||||
"class":"obstacle"
|
||||
}
|
||||
},
|
||||
{
|
||||
"class":"obstacle",
|
||||
"id":2,
|
||||
"objectgroup":
|
||||
{
|
||||
"draworder":"index",
|
||||
"name":"",
|
||||
"objects":[
|
||||
{
|
||||
"height":0,
|
||||
"id":1,
|
||||
"name":"",
|
||||
"polygon":[
|
||||
{
|
||||
"x":0,
|
||||
"y":0
|
||||
},
|
||||
{
|
||||
"x":8,
|
||||
"y":-8
|
||||
},
|
||||
{
|
||||
"x":0,
|
||||
"y":-8
|
||||
}],
|
||||
"rotation":0,
|
||||
"class":"",
|
||||
"visible":true,
|
||||
"width":0,
|
||||
"x":0,
|
||||
"y":8
|
||||
}],
|
||||
"opacity":1,
|
||||
"type":"objectgroup",
|
||||
"visible":true,
|
||||
"x":0,
|
||||
"y":0
|
||||
},
|
||||
"class":"obstacle"
|
||||
},
|
||||
{
|
||||
"id":3,
|
||||
"objectgroup":
|
||||
{
|
||||
"draworder":"index",
|
||||
@@ -83,6 +45,50 @@
|
||||
"name":"",
|
||||
"objects":[
|
||||
{
|
||||
"class":"",
|
||||
"height":0,
|
||||
"id":9,
|
||||
"name":"",
|
||||
"polygon":[
|
||||
{
|
||||
"x":2,
|
||||
"y":0
|
||||
},
|
||||
{
|
||||
"x":4,
|
||||
"y":0
|
||||
},
|
||||
{
|
||||
"x":4,
|
||||
"y":2
|
||||
},
|
||||
{
|
||||
"x":2,
|
||||
"y":2
|
||||
}],
|
||||
"rotation":0,
|
||||
"visible":true,
|
||||
"width":0,
|
||||
"x":0,
|
||||
"y":0
|
||||
}],
|
||||
"opacity":1,
|
||||
"type":"objectgroup",
|
||||
"visible":true,
|
||||
"x":0,
|
||||
"y":0
|
||||
}
|
||||
},
|
||||
{
|
||||
"class":"obstacle",
|
||||
"id":3,
|
||||
"objectgroup":
|
||||
{
|
||||
"draworder":"index",
|
||||
"name":"",
|
||||
"objects":[
|
||||
{
|
||||
"class":"",
|
||||
"height":0,
|
||||
"id":1,
|
||||
"name":"",
|
||||
@@ -100,13 +106,13 @@
|
||||
"y":0
|
||||
}],
|
||||
"rotation":0,
|
||||
"class":"",
|
||||
"visible":true,
|
||||
"width":0,
|
||||
"x":0,
|
||||
"y":0
|
||||
},
|
||||
{
|
||||
"class":"",
|
||||
"height":0,
|
||||
"id":3,
|
||||
"name":"",
|
||||
@@ -124,7 +130,6 @@
|
||||
"y":0
|
||||
}],
|
||||
"rotation":180,
|
||||
"class":"",
|
||||
"visible":true,
|
||||
"width":0,
|
||||
"x":8,
|
||||
@@ -135,18 +140,17 @@
|
||||
"visible":true,
|
||||
"x":0,
|
||||
"y":0
|
||||
},
|
||||
"class":"obstacle"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id":4,
|
||||
"objectgroup":
|
||||
{
|
||||
"draworder":"index",
|
||||
"id":2,
|
||||
"name":"",
|
||||
"objects":[
|
||||
{
|
||||
"class":"obstacle",
|
||||
"height":0,
|
||||
"id":1,
|
||||
"name":"",
|
||||
@@ -164,13 +168,13 @@
|
||||
"y":0
|
||||
}],
|
||||
"rotation":0,
|
||||
"class":"obstacle",
|
||||
"visible":true,
|
||||
"width":0,
|
||||
"x":0,
|
||||
"y":0
|
||||
},
|
||||
{
|
||||
"class":"lava",
|
||||
"height":0,
|
||||
"id":2,
|
||||
"name":"",
|
||||
@@ -188,7 +192,6 @@
|
||||
"y":0
|
||||
}],
|
||||
"rotation":180,
|
||||
"class":"lava",
|
||||
"visible":true,
|
||||
"width":0,
|
||||
"x":8,
|
||||
@@ -202,19 +205,19 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"class":"lava",
|
||||
"id":5,
|
||||
"objectgroup":
|
||||
{
|
||||
"draworder":"index",
|
||||
"id":2,
|
||||
"name":"",
|
||||
"objects":[
|
||||
{
|
||||
"class":"",
|
||||
"height":8,
|
||||
"id":1,
|
||||
"name":"",
|
||||
"rotation":0,
|
||||
"class":"",
|
||||
"visible":true,
|
||||
"width":8,
|
||||
"x":0,
|
||||
@@ -225,10 +228,9 @@
|
||||
"visible":true,
|
||||
"x":0,
|
||||
"y":0
|
||||
},
|
||||
"class":"lava"
|
||||
}
|
||||
}],
|
||||
"tilewidth":8,
|
||||
"type":"tileset",
|
||||
"version":"1.6"
|
||||
"version":"1.8"
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 246 B After Width: | Height: | Size: 152 B |
@@ -3,7 +3,8 @@
|
||||
"infinite":false,
|
||||
"layers":[
|
||||
{
|
||||
"data":[1, 3, 4, 5, 3, 2, 0, 1073741829],
|
||||
"data":[1, 2147483651, 4, 5,
|
||||
3, 2, 0, 1073741829],
|
||||
"height":2,
|
||||
"id":1,
|
||||
"name":"Tile Layer 1",
|
||||
@@ -18,7 +19,7 @@
|
||||
"nextobjectid":1,
|
||||
"orientation":"orthogonal",
|
||||
"renderorder":"right-down",
|
||||
"tiledversion":"1.7.2",
|
||||
"tiledversion":"1.9.0",
|
||||
"tileheight":8,
|
||||
"tilesets":[
|
||||
{
|
||||
@@ -27,6 +28,6 @@
|
||||
}],
|
||||
"tilewidth":8,
|
||||
"type":"map",
|
||||
"version":"1.6",
|
||||
"version":"1.9",
|
||||
"width":4
|
||||
}
|
@@ -266,17 +266,19 @@ export class PixiTileMapHelper {
|
||||
for (let index = 0; index < vertices.length; index++) {
|
||||
let vertexX = vertices[index][0];
|
||||
let vertexY = vertices[index][1];
|
||||
// It's important to do the diagonal flipping first,
|
||||
// because the other flipping "move" the origin.
|
||||
if (isFlippedDiagonally) {
|
||||
const swap = vertexX;
|
||||
vertexX = vertexY;
|
||||
vertexY = swap;
|
||||
}
|
||||
if (isFlippedHorizontally) {
|
||||
vertexX = tileWidth - vertexX;
|
||||
}
|
||||
if (isFlippedVertically) {
|
||||
vertexY = tileHeight - vertexY;
|
||||
}
|
||||
if (isFlippedDiagonally) {
|
||||
const swap = vertexX;
|
||||
vertexX = vertexY;
|
||||
vertexY = swap;
|
||||
}
|
||||
if (index === 0) {
|
||||
pixiGraphics.moveTo(xPos + vertexX, yPos + vertexY);
|
||||
} else {
|
||||
|
@@ -261,7 +261,7 @@ export type TiledTileset = {
|
||||
columns: integer;
|
||||
|
||||
/** GID corresponding to the first tile in the set */
|
||||
firstgid: integer;
|
||||
firstgid?: integer;
|
||||
|
||||
/** (optional) */
|
||||
grid?: TiledGrid;
|
||||
|
@@ -513,4 +513,160 @@ describe("TiledTileMapLoader", function () {
|
||||
expect(tileMap.pointIsInsideTile(12, 12, "obstacle")).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("with a collision mask", function () {
|
||||
// Built from an actual json file exported by Tiled.
|
||||
const tiledMap: TiledMap = {
|
||||
compressionlevel: -1,
|
||||
height: 2,
|
||||
infinite: false,
|
||||
layers: [
|
||||
{
|
||||
data: [
|
||||
3,
|
||||
2684354563,
|
||||
536870915,
|
||||
2147483651,
|
||||
1610612739,
|
||||
3221225475,
|
||||
1073741827,
|
||||
3758096387,
|
||||
],
|
||||
height: 2,
|
||||
id: 1,
|
||||
name: "Tile Layer 1",
|
||||
opacity: 1,
|
||||
type: "tilelayer",
|
||||
visible: true,
|
||||
width: 4,
|
||||
x: 0,
|
||||
y: 0,
|
||||
},
|
||||
],
|
||||
nextlayerid: 2,
|
||||
nextobjectid: 1,
|
||||
orientation: "orthogonal",
|
||||
renderorder: "right-down",
|
||||
tiledversion: "1.9.0",
|
||||
tileheight: 8,
|
||||
tilesets: [
|
||||
{
|
||||
columns: 1,
|
||||
image: "MiniTiledSet.png",
|
||||
imageheight: 8,
|
||||
imagewidth: 8,
|
||||
margin: 0,
|
||||
name: "new tileset",
|
||||
spacing: 0,
|
||||
tilecount: 1,
|
||||
tiledversion: "1.9.0",
|
||||
tileheight: 8,
|
||||
tiles: [
|
||||
{
|
||||
class: "obstacle",
|
||||
id: 2,
|
||||
objectgroup: {
|
||||
draworder: "index",
|
||||
id: 2,
|
||||
name: "",
|
||||
objects: [
|
||||
{
|
||||
class: "",
|
||||
height: 0,
|
||||
id: 9,
|
||||
name: "",
|
||||
polygon: [
|
||||
{
|
||||
x: 0,
|
||||
y: 0,
|
||||
},
|
||||
{
|
||||
x: 4,
|
||||
y: 0,
|
||||
},
|
||||
{
|
||||
x: 4,
|
||||
y: 4,
|
||||
},
|
||||
{
|
||||
x: 0,
|
||||
y: 4,
|
||||
},
|
||||
],
|
||||
rotation: 0,
|
||||
visible: true,
|
||||
width: 0,
|
||||
x: 0,
|
||||
y: 0,
|
||||
},
|
||||
],
|
||||
opacity: 1,
|
||||
type: "objectgroup",
|
||||
visible: true,
|
||||
x: 0,
|
||||
y: 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
tilewidth: 8,
|
||||
type: "tileset",
|
||||
version: "1.8",
|
||||
},
|
||||
],
|
||||
tilewidth: 8,
|
||||
type: "map",
|
||||
version: "1.9",
|
||||
width: 4,
|
||||
};
|
||||
|
||||
const tileMap: EditableTileMap = TiledTileMapLoader.load(null, tiledMap);
|
||||
|
||||
it("can load flipped tiles", function () {
|
||||
const layers = new Array(...tileMap.getLayers());
|
||||
expect(layers.length).to.be(1);
|
||||
const layer = layers[0] as EditableTileMapLayer;
|
||||
expect(layer.id).to.be(1);
|
||||
expect(layer.isVisible()).to.be(true);
|
||||
|
||||
expect(layer.get(0, 0)).to.be(2);
|
||||
expect(layer.isFlippedVertically(0, 0)).to.be(false);
|
||||
expect(layer.isFlippedHorizontally(0, 0)).to.be(false);
|
||||
expect(layer.isFlippedDiagonally(0, 0)).to.be(false);
|
||||
|
||||
expect(layer.get(1, 0)).to.be(2);
|
||||
expect(layer.isFlippedVertically(1, 0)).to.be(false);
|
||||
expect(layer.isFlippedHorizontally(1, 0)).to.be(true);
|
||||
expect(layer.isFlippedDiagonally(1, 0)).to.be(true);
|
||||
|
||||
expect(layer.get(1, 1)).to.be(2);
|
||||
expect(layer.isFlippedVertically(1, 1)).to.be(true);
|
||||
expect(layer.isFlippedHorizontally(1, 1)).to.be(true);
|
||||
expect(layer.isFlippedDiagonally(1, 1)).to.be(false);
|
||||
|
||||
expect(layer.get(0, 1)).to.be(2);
|
||||
expect(layer.isFlippedVertically(0, 1)).to.be(true);
|
||||
expect(layer.isFlippedHorizontally(0, 1)).to.be(false);
|
||||
expect(layer.isFlippedDiagonally(0, 1)).to.be(true);
|
||||
|
||||
expect(layer.get(2, 0)).to.be(2);
|
||||
expect(layer.isFlippedVertically(2, 0)).to.be(false);
|
||||
expect(layer.isFlippedHorizontally(2, 0)).to.be(false);
|
||||
expect(layer.isFlippedDiagonally(2, 0)).to.be(true);
|
||||
|
||||
expect(layer.get(3, 0)).to.be(2);
|
||||
expect(layer.isFlippedVertically(3, 0)).to.be(false);
|
||||
expect(layer.isFlippedHorizontally(3, 0)).to.be(true);
|
||||
expect(layer.isFlippedDiagonally(3, 0)).to.be(false);
|
||||
|
||||
expect(layer.get(3, 1)).to.be(2);
|
||||
expect(layer.isFlippedVertically(3, 1)).to.be(true);
|
||||
expect(layer.isFlippedHorizontally(3, 1)).to.be(true);
|
||||
expect(layer.isFlippedDiagonally(3, 1)).to.be(true);
|
||||
|
||||
expect(layer.get(2, 1)).to.be(2);
|
||||
expect(layer.isFlippedVertically(2, 1)).to.be(true);
|
||||
expect(layer.isFlippedHorizontally(2, 1)).to.be(false);
|
||||
expect(layer.isFlippedDiagonally(2, 1)).to.be(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Reference in New Issue
Block a user