I know this has come up in the past, but it seemed like it was focused on non-rectangular or non-square shapes. In my case, I’d like to use rectangular/circular collisions, but I just want to limit the subset of the tile that counts as a collision area.
Currently, I have a bunch of tilesets, where tiles that should be collided with have a “collides” boolean set to true. That bit works fine as expected. I’d like to change the behavior to allow me to specify a subset of the tile I want to collide with. It looks like tiled is picking up on the collision groups from Tiled (the call to tile.getCollisionGroup
returns appropriate data). I have used setCollisionfromCollisionGroup
, but it just seems to mark the entire tile as collidable, not the specified section. I would expect/hope that Phaser would use the provided collision groups when calculating whether a collision occurred, but it apparently doesn’t. I currently have an addTilemap
function (so I can dynamically load maps around the player), which looks something like this:
addTilemap(map, mapX, mapY) {
const tilesets = [];
for (const key in this._TILED_TILESETS) {
const opts = this._TILED_TILESETS[key];
const { name, width, height, extrusion, spacing } = opts;
tilesets.push(
map.addTilesetImage(name, key, width, height, extrusion, spacing)
);
}
for (const i in this._TILED_LAYERS) {
const [name, collide, type = "tile"] = this._TILED_LAYERS[i];
let layer;
if (type === "tile") {
layer = map.createLayer(name, tilesets, mapX, mapY);
if (layer === null) {
console.error("failed to make layer", name);
continue;
}
//I have tried both of these. They behave the same
//if (collide) layer.setCollisionByProperty({ collides: true });
if (collide) layer.setCollisionFromCollisionGroup();
layer.forEachTile((tile) => {
//console.log(tile)
const collisionGroup = tile.getCollisionGroup()
if (collisionGroup) {
console.log(collisionGroup)
}
})
//this.matter.world.convertTilemapLayer(layer)
}
if (type === "object") {
const group = this.add.group();
layer = map.getObjectLayer(name);
layer.objects.forEach((object) => {
const { x, y, width, height } = object;
const sprite = this.make.sprite({ x: mapX + x, y: mapY + y });
const offset = {
x: sprite.originX * sprite.displayWidth,
y: sprite.originY * sprite.displayHeight,
};
if (width) sprite.displayWidth = width;
if (height) sprite.displayHeight = height;
sprite.x += offset.x;
sprite.y += offset.y;
const data = object.properties
? object.properties.reduce((props, { name, value }) => {
props[name] = value;
return props;
}, {})
: {};
sprite.setAlpha(0);
sprite.setData(data);
group.add(sprite);
this.physics.world.enable(sprite);
//this.matter.world.enable(sprite);
sprite.body.setImmovable();
});
layer = group;
}
layer.setDepth(i);
layer._collider = this.physics.add.collider(
//layer._collider = this.matter.add.collider(
this.collidable,
layer,
onCollide
);
}
this.sys.animatedTiles.init(map);
}
Short of creating a sprite for every tile with a collision group, is there an option to tell Phaser to use the tile’s collision group vs. just the collision property?