Fix the collision mask of rotated tiles that were sometimes misplaced (#4181)

This commit is contained in:
D8H
2022-08-05 18:10:06 +02:00
committed by GitHub
parent 504443dea4
commit cfa538ec3d
15 changed files with 491 additions and 206 deletions

View File

@@ -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

View File

@@ -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"}

View File

@@ -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

View File

@@ -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);
});
});
});

View File

@@ -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.

View File

@@ -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
}

View File

@@ -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

View File

@@ -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
}

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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);
});
});
});