mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Allow to filter external tile map collision per layer (#6998)
This commit is contained in:
@@ -1081,6 +1081,14 @@ const defineCollisionMask = function (extension, _, gd) {
|
||||
objectContent.collisionMaskTag = newValue;
|
||||
return true;
|
||||
}
|
||||
if (propertyName === 'layerIndex') {
|
||||
objectContent.layerIndex = parseFloat(newValue);
|
||||
return true;
|
||||
}
|
||||
if (propertyName === 'useAllLayers') {
|
||||
objectContent.useAllLayers = newValue === '1';
|
||||
return true;
|
||||
}
|
||||
if (propertyName === 'debugMode') {
|
||||
objectContent.debugMode = newValue === '1';
|
||||
return true;
|
||||
@@ -1149,6 +1157,28 @@ const defineCollisionMask = function (extension, _, gd) {
|
||||
)
|
||||
)
|
||||
);
|
||||
objectProperties.set(
|
||||
'layerIndex',
|
||||
new gd.PropertyDescriptor((objectContent.layerIndex || 1).toString())
|
||||
.setType('number')
|
||||
.setLabel(_('Layer index'))
|
||||
.setGroup(_('Layers'))
|
||||
.setAdvanced(true)
|
||||
);
|
||||
objectProperties.set(
|
||||
'useAllLayers',
|
||||
new gd.PropertyDescriptor(
|
||||
objectContent.useAllLayers ||
|
||||
objectContent.useAllLayers === undefined ||
|
||||
objectContent.useAllLayers === null
|
||||
? 'true'
|
||||
: 'false'
|
||||
)
|
||||
.setType('boolean')
|
||||
.setLabel(_('Use all layers'))
|
||||
.setGroup(_('Layers'))
|
||||
.setAdvanced(true)
|
||||
);
|
||||
objectProperties.set(
|
||||
'debugMode',
|
||||
new gd.PropertyDescriptor(objectContent.debugMode ? 'true' : 'false')
|
||||
@@ -1157,12 +1187,14 @@ const defineCollisionMask = function (extension, _, gd) {
|
||||
.setDescription(
|
||||
_('When activated, it displays the hitboxes in the given color.')
|
||||
)
|
||||
.setGroup(_('Appearance'))
|
||||
);
|
||||
objectProperties.set(
|
||||
'outlineColor',
|
||||
new gd.PropertyDescriptor(objectContent.outlineColor)
|
||||
.setType('color')
|
||||
.setLabel(_('Outline color'))
|
||||
.setGroup(_('Appearance'))
|
||||
);
|
||||
objectProperties.set(
|
||||
'outlineOpacity',
|
||||
@@ -1173,6 +1205,7 @@ const defineCollisionMask = function (extension, _, gd) {
|
||||
)
|
||||
.setType('number')
|
||||
.setLabel(_('Outline opacity (0-255)'))
|
||||
.setGroup(_('Appearance'))
|
||||
);
|
||||
objectProperties.set(
|
||||
'outlineSize',
|
||||
@@ -1183,12 +1216,14 @@ const defineCollisionMask = function (extension, _, gd) {
|
||||
)
|
||||
.setType('number')
|
||||
.setLabel(_('Outline size (in pixels)'))
|
||||
.setGroup(_('Appearance'))
|
||||
);
|
||||
objectProperties.set(
|
||||
'fillColor',
|
||||
new gd.PropertyDescriptor(objectContent.fillColor)
|
||||
.setType('color')
|
||||
.setLabel(_('Fill color'))
|
||||
.setGroup(_('Appearance'))
|
||||
);
|
||||
objectProperties.set(
|
||||
'fillOpacity',
|
||||
@@ -1199,6 +1234,7 @@ const defineCollisionMask = function (extension, _, gd) {
|
||||
)
|
||||
.setType('number')
|
||||
.setLabel(_('Fill opacity (0-255)'))
|
||||
.setGroup(_('Appearance'))
|
||||
);
|
||||
|
||||
return objectProperties;
|
||||
@@ -1207,6 +1243,8 @@ const defineCollisionMask = function (extension, _, gd) {
|
||||
tilemapJsonFile: '',
|
||||
tilesetJsonFile: '',
|
||||
collisionMaskTag: '',
|
||||
layerIndex: 1,
|
||||
useAllLayers: true,
|
||||
debugMode: false,
|
||||
fillColor: '255;255;255',
|
||||
outlineColor: '255;255;255',
|
||||
@@ -2381,6 +2419,7 @@ module.exports = {
|
||||
_tilemapJsonFile = '';
|
||||
_tilesetJsonFile = '';
|
||||
_collisionMaskTag = '';
|
||||
_layerIndex = null;
|
||||
_outlineColor = 0xffffff;
|
||||
_fillColor = 0xffffff;
|
||||
_outlineOpacity = 0;
|
||||
@@ -2481,6 +2520,7 @@ module.exports = {
|
||||
const tilemapJsonFile = this._tilemapJsonFile;
|
||||
const tilesetJsonFile = this._tilesetJsonFile;
|
||||
const collisionMaskTag = this._collisionMaskTag;
|
||||
const layerIndex = this._layerIndex;
|
||||
const outlineColor = this._outlineColor;
|
||||
const fillColor = this._fillColor;
|
||||
const outlineOpacity = this._outlineOpacity;
|
||||
@@ -2509,6 +2549,7 @@ module.exports = {
|
||||
this._pixiObject,
|
||||
tileMap,
|
||||
collisionMaskTag,
|
||||
layerIndex,
|
||||
outlineSize,
|
||||
outlineColor,
|
||||
outlineOpacity,
|
||||
@@ -2566,6 +2607,8 @@ module.exports = {
|
||||
const tilemapJsonFile = object.content.tilemapJsonFile;
|
||||
const tilesetJsonFile = object.content.tilesetJsonFile;
|
||||
const collisionMaskTag = object.content.collisionMaskTag;
|
||||
const useAllLayers = object.content.useAllLayers;
|
||||
const layerIndex = useAllLayers ? null : object.content.layerIndex;
|
||||
const outlineColor = objectsRenderingService.rgbOrHexToHexNumber(
|
||||
object.content.outlineColor
|
||||
);
|
||||
@@ -2580,6 +2623,7 @@ module.exports = {
|
||||
tilemapJsonFile !== this._tilemapJsonFile ||
|
||||
tilesetJsonFile !== this._tilesetJsonFile ||
|
||||
collisionMaskTag !== this._collisionMaskTag ||
|
||||
layerIndex !== this._layerIndex ||
|
||||
outlineColor !== this._outlineColor ||
|
||||
fillColor !== this._fillColor ||
|
||||
outlineOpacity !== this._outlineOpacity ||
|
||||
@@ -2589,6 +2633,7 @@ module.exports = {
|
||||
this._tilemapJsonFile = tilemapJsonFile;
|
||||
this._tilesetJsonFile = tilesetJsonFile;
|
||||
this._collisionMaskTag = collisionMaskTag;
|
||||
this._layerIndex = layerIndex;
|
||||
this._outlineColor = outlineColor;
|
||||
this._fillColor = fillColor;
|
||||
this._outlineOpacity = outlineOpacity;
|
||||
|
@@ -12,6 +12,7 @@ namespace gdjs {
|
||||
*/
|
||||
private _source: TileMapHelper.EditableTileMap;
|
||||
tag: string;
|
||||
private _layerIndex: integer | null;
|
||||
private _layers: Map<integer, TransformedCollisionTileMapLayer>;
|
||||
// TODO Tiled allows to offset the layers
|
||||
/**
|
||||
@@ -37,9 +38,14 @@ namespace gdjs {
|
||||
/**
|
||||
* @param source The model that describes the tile map.
|
||||
*/
|
||||
constructor(source: TileMapHelper.EditableTileMap, tag: string) {
|
||||
constructor(
|
||||
source: TileMapHelper.EditableTileMap,
|
||||
tag: string,
|
||||
layerIndex: number | null = null
|
||||
) {
|
||||
this._source = source;
|
||||
this.tag = tag;
|
||||
this._layerIndex = layerIndex;
|
||||
this._layers = new Map<integer, TransformedCollisionTileMapLayer>();
|
||||
this._buildLayersFromTileMap(source, this._layers);
|
||||
}
|
||||
@@ -55,17 +61,28 @@ namespace gdjs {
|
||||
tileMap: TileMapHelper.EditableTileMap,
|
||||
layers: Map<integer, TransformedCollisionTileMapLayer>
|
||||
) {
|
||||
for (const sourceLayer of tileMap.getLayers()) {
|
||||
// TODO A visitor could be used to avoid a cast.
|
||||
if (!(sourceLayer instanceof TileMapHelper.EditableTileMapLayer)) {
|
||||
// TODO Collision mask for object layers is not handled.
|
||||
continue;
|
||||
if (this._layerIndex) {
|
||||
const tileLayer = tileMap.getTileLayer(this._layerIndex);
|
||||
if (!tileLayer) {
|
||||
return;
|
||||
}
|
||||
const tileLayer = sourceLayer as TileMapHelper.EditableTileMapLayer;
|
||||
layers.set(
|
||||
tileLayer.id,
|
||||
new TransformedCollisionTileMapLayer(this, tileLayer)
|
||||
);
|
||||
} else {
|
||||
for (const sourceLayer of tileMap.getLayers()) {
|
||||
// TODO A visitor could be used to avoid a cast.
|
||||
if (!(sourceLayer instanceof TileMapHelper.EditableTileMapLayer)) {
|
||||
// TODO Collision mask for object layers is not handled.
|
||||
continue;
|
||||
}
|
||||
const tileLayer = sourceLayer as TileMapHelper.EditableTileMapLayer;
|
||||
layers.set(
|
||||
tileLayer.id,
|
||||
new TransformedCollisionTileMapLayer(this, tileLayer)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -60,6 +60,7 @@ export declare namespace PixiTileMapHelper {
|
||||
pixiGraphics: PIXI.Graphics,
|
||||
tileMap: EditableTileMap,
|
||||
typeFilter: string,
|
||||
layerIndex: integer | null,
|
||||
outlineSize: integer,
|
||||
outlineColor: integer,
|
||||
outlineOpacity: float,
|
||||
|
@@ -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,EAEL,eAAe,EAEhB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGtD,yBAAiB,iBAAiB,CAAC;IACjC;;;;;;;;OAQG;IACH,SAAgB,UAAU,CACxB,OAAO,EAAE,kBAAkB,EAC3B,UAAU,EAAE,MAAM,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,CAuBzB;IAED;;;;;;;;OAQG;IACH,SAAgB,uBAAuB,CACrC,YAAY,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,EAC7C,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,gBAAgB,CAqBlB;IAED;;;;;;;;;;;;OAYG;IACH,SAAgB,iBAAiB,CAC/B,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,CA0GN;IAED;;OAEG;IACH,SAAgB,uBAAuB,CACrC,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,CAgEN;CACF"}
|
||||
{"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,EAEL,eAAe,EAEhB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGtD,yBAAiB,iBAAiB,CAAC;IACjC;;;;;;;;OAQG;IACH,SAAgB,UAAU,CACxB,OAAO,EAAE,kBAAkB,EAC3B,UAAU,EAAE,MAAM,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,CAuBzB;IAED;;;;;;;;OAQG;IACH,SAAgB,uBAAuB,CACrC,YAAY,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,EAC7C,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,gBAAgB,CAqBlB;IAED;;;;;;;;;;;;OAYG;IACH,SAAgB,iBAAiB,CAC/B,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,CA0GN;IAED;;OAEG;IACH,SAAgB,uBAAuB,CACrC,YAAY,EAAE,IAAI,CAAC,QAAQ,EAC3B,OAAO,EAAE,eAAe,EACxB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,OAAO,GAAG,IAAI,EAC1B,WAAW,EAAE,OAAO,EACpB,YAAY,EAAE,OAAO,EACrB,cAAc,EAAE,KAAK,EACrB,SAAS,EAAE,OAAO,EAClB,WAAW,EAAE,KAAK,GACjB,IAAI,CA6BN;CA8DF"}
|
@@ -52,6 +52,7 @@ namespace gdjs {
|
||||
* For instance, platforms, jumpthru, ladder, spike, water...
|
||||
*/
|
||||
private _collisionMaskTag: string;
|
||||
private _layerIndex: integer | null;
|
||||
private _tileMapManager: gdjs.TileMap.TileMapRuntimeManager;
|
||||
|
||||
/**
|
||||
@@ -80,6 +81,11 @@ namespace gdjs {
|
||||
this._tilemapJsonFile = objectData.content.tilemapJsonFile;
|
||||
this._tilesetJsonFile = objectData.content.tilesetJsonFile;
|
||||
this._collisionMaskTag = objectData.content.collisionMaskTag;
|
||||
this._layerIndex = objectData.content.useAllLayers
|
||||
? null
|
||||
: Number.isFinite(objectData.content.layerIndex)
|
||||
? objectData.content.layerIndex
|
||||
: 1;
|
||||
this._debugMode = objectData.content.debugMode;
|
||||
this._fillColor = gdjs.rgbOrHexStringToNumber(
|
||||
objectData.content.fillColor
|
||||
@@ -108,7 +114,8 @@ namespace gdjs {
|
||||
);
|
||||
this._collisionTileMap = new gdjs.TileMap.TransformedCollisionTileMap(
|
||||
editableTileMap,
|
||||
this._collisionMaskTag
|
||||
this._collisionMaskTag,
|
||||
this._layerIndex
|
||||
);
|
||||
|
||||
this._renderer = new gdjs.TileMap.TileMapCollisionMaskRenderer(
|
||||
@@ -178,6 +185,7 @@ namespace gdjs {
|
||||
if (oldObjectData.outlineSize !== newObjectData.outlineSize) {
|
||||
this.setOutlineSize(newObjectData.outlineSize);
|
||||
}
|
||||
// TODO Handle changes to collisionMaskTag, useAllLayers and layerIndex.
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -254,7 +262,8 @@ namespace gdjs {
|
||||
|
||||
this._collisionTileMap = new gdjs.TileMap.TransformedCollisionTileMap(
|
||||
tileMap,
|
||||
this._collisionMaskTag
|
||||
this._collisionMaskTag,
|
||||
this._layerIndex
|
||||
);
|
||||
// The tile map polygons always keep the same references.
|
||||
// It works because the tilemap is never modified.
|
||||
|
@@ -221,6 +221,7 @@ export namespace PixiTileMapHelper {
|
||||
pixiGraphics: PIXI.Graphics,
|
||||
tileMap: EditableTileMap,
|
||||
typeFilter: string,
|
||||
layerIndex: integer | null,
|
||||
outlineSize: integer,
|
||||
outlineColor: integer,
|
||||
outlineOpacity: float,
|
||||
@@ -233,60 +234,86 @@ export namespace PixiTileMapHelper {
|
||||
pixiGraphics.lineStyle(outlineSize, outlineColor, outlineOpacity);
|
||||
pixiGraphics.drawRect(0, 0, tileMap.getWidth(), tileMap.getHeight());
|
||||
|
||||
for (const layer of tileMap.getLayers()) {
|
||||
const tileWidth = tileMap.getTileWidth();
|
||||
const tileHeight = tileMap.getTileHeight();
|
||||
if (layerIndex) {
|
||||
const tileMapLayer = tileMap.getTileLayer(layerIndex);
|
||||
drawCollisionLayer(
|
||||
pixiGraphics,
|
||||
tileMapLayer,
|
||||
typeFilter,
|
||||
fillColor,
|
||||
fillOpacity
|
||||
);
|
||||
} else {
|
||||
for (const layer of tileMap.getLayers()) {
|
||||
if (layer instanceof EditableTileMapLayer) {
|
||||
drawCollisionLayer(
|
||||
pixiGraphics,
|
||||
layer as EditableTileMapLayer,
|
||||
typeFilter,
|
||||
fillColor,
|
||||
fillOpacity
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (layer instanceof EditableTileMapLayer) {
|
||||
const tileLayer = layer as EditableTileMapLayer;
|
||||
function drawCollisionLayer(
|
||||
pixiGraphics: PIXI.Graphics,
|
||||
tileLayer: EditableTileMapLayer,
|
||||
typeFilter: string,
|
||||
fillColor: integer,
|
||||
fillOpacity: float
|
||||
): void {
|
||||
const tileMap = tileLayer.tileMap;
|
||||
const tileWidth = tileMap.getTileWidth();
|
||||
const tileHeight = tileMap.getTileHeight();
|
||||
|
||||
for (let y = 0; y < tileLayer.tileMap.getDimensionY(); y++) {
|
||||
for (let x = 0; x < tileLayer.tileMap.getDimensionX(); x++) {
|
||||
const xPos = tileWidth * x;
|
||||
const yPos = tileHeight * y;
|
||||
for (let y = 0; y < tileMap.getDimensionY(); y++) {
|
||||
for (let x = 0; x < tileMap.getDimensionX(); x++) {
|
||||
const xPos = tileWidth * x;
|
||||
const yPos = tileHeight * y;
|
||||
|
||||
const tileId = tileLayer.getTileId(x, y)!;
|
||||
const isFlippedHorizontally = tileLayer.isFlippedHorizontally(x, y);
|
||||
const isFlippedVertically = tileLayer.isFlippedVertically(x, y);
|
||||
const isFlippedDiagonally = tileLayer.isFlippedDiagonally(x, y);
|
||||
const tileDefinition = tileLayer.tileMap.getTileDefinition(tileId);
|
||||
if (!tileDefinition) {
|
||||
continue;
|
||||
const tileId = tileLayer.getTileId(x, y)!;
|
||||
const isFlippedHorizontally = tileLayer.isFlippedHorizontally(x, y);
|
||||
const isFlippedVertically = tileLayer.isFlippedVertically(x, y);
|
||||
const isFlippedDiagonally = tileLayer.isFlippedDiagonally(x, y);
|
||||
const tileDefinition = tileMap.getTileDefinition(tileId);
|
||||
if (!tileDefinition) {
|
||||
continue;
|
||||
}
|
||||
const hitboxes = tileDefinition.getHitBoxes(typeFilter);
|
||||
if (!hitboxes) {
|
||||
continue;
|
||||
}
|
||||
for (const vertices of hitboxes) {
|
||||
if (vertices.length === 0) continue;
|
||||
|
||||
pixiGraphics.beginFill(fillColor, fillOpacity);
|
||||
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;
|
||||
}
|
||||
const hitboxes = tileDefinition.getHitBoxes(typeFilter);
|
||||
if (!hitboxes) {
|
||||
continue;
|
||||
if (isFlippedHorizontally) {
|
||||
vertexX = tileWidth - vertexX;
|
||||
}
|
||||
for (const vertices of hitboxes) {
|
||||
if (vertices.length === 0) continue;
|
||||
|
||||
pixiGraphics.beginFill(fillColor, fillOpacity);
|
||||
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 (index === 0) {
|
||||
pixiGraphics.moveTo(xPos + vertexX, yPos + vertexY);
|
||||
} else {
|
||||
pixiGraphics.lineTo(xPos + vertexX, yPos + vertexY);
|
||||
}
|
||||
}
|
||||
pixiGraphics.closePath();
|
||||
pixiGraphics.endFill();
|
||||
if (isFlippedVertically) {
|
||||
vertexY = tileHeight - vertexY;
|
||||
}
|
||||
if (index === 0) {
|
||||
pixiGraphics.moveTo(xPos + vertexX, yPos + vertexY);
|
||||
} else {
|
||||
pixiGraphics.lineTo(xPos + vertexX, yPos + vertexY);
|
||||
}
|
||||
}
|
||||
pixiGraphics.closePath();
|
||||
pixiGraphics.endFill();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user