From 115a96a08f61c7fe9088716332f1c0720be4ba56 Mon Sep 17 00:00:00 2001 From: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com> Date: Mon, 16 Sep 2024 11:34:13 +0200 Subject: [PATCH 01/12] Do not paint on the tilemap if tileset badly configured --- newIDE/app/src/InstancesEditor/TileMapPaintingPreview.js | 2 +- newIDE/app/src/InstancesEditor/index.js | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/newIDE/app/src/InstancesEditor/TileMapPaintingPreview.js b/newIDE/app/src/InstancesEditor/TileMapPaintingPreview.js index bf127b3d211a..48b6bb63501a 100644 --- a/newIDE/app/src/InstancesEditor/TileMapPaintingPreview.js +++ b/newIDE/app/src/InstancesEditor/TileMapPaintingPreview.js @@ -77,7 +77,7 @@ export const getTileSet = (object: gdObject) => { return { rowCount, columnCount, tileSize, atlasImage }; }; -const isTileSetBadlyConfigured = ({ +export const isTileSetBadlyConfigured = ({ rowCount, columnCount, tileSize, diff --git a/newIDE/app/src/InstancesEditor/index.js b/newIDE/app/src/InstancesEditor/index.js index 77e6c095a7be..698d95434bf0 100644 --- a/newIDE/app/src/InstancesEditor/index.js +++ b/newIDE/app/src/InstancesEditor/index.js @@ -45,6 +45,7 @@ import Background from './Background'; import TileMapPaintingPreview, { getTileSet, getTilesGridCoordinatesFromPointerSceneCoordinates, + isTileSetBadlyConfigured, updateSceneToTileMapTransformation, } from './TileMapPaintingPreview'; import { @@ -827,6 +828,12 @@ export default class InstancesEditor extends Component { console.warn('Trying to paint on a tilemap without an atlas image.'); return; } + if (isTileSetBadlyConfigured(tileSet)) { + console.warn( + 'Trying to paint on a tilemap with a badly configured tileset.' + ); + return; + } const tileMapGridCoordinates = getTilesGridCoordinatesFromPointerSceneCoordinates( { coordinates: sceneCoordinates, From f9b16eb912ccd8a5db2a5e64fa7d4dac280ef970 Mon Sep 17 00:00:00 2001 From: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com> Date: Mon, 16 Sep 2024 11:36:27 +0200 Subject: [PATCH 02/12] Use tiled sprite to paint invalid textures --- newIDE/app/src/InstancesEditor/TileMapPaintingPreview.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/newIDE/app/src/InstancesEditor/TileMapPaintingPreview.js b/newIDE/app/src/InstancesEditor/TileMapPaintingPreview.js index 48b6bb63501a..9be5f756ad51 100644 --- a/newIDE/app/src/InstancesEditor/TileMapPaintingPreview.js +++ b/newIDE/app/src/InstancesEditor/TileMapPaintingPreview.js @@ -345,7 +345,7 @@ class TileMapPaintingPreview { spritesCoordinatesInTileMapGrid.forEach(({ x, y }) => { let sprite; - if (tileMapTileSelection.kind === 'single' || isBadlyConfigured) { + if (tileMapTileSelection.kind === 'single') { // TODO: Find a way not to regenerate the sprites on each render. sprite = new PIXI.Sprite(texture); if (tileMapTileSelection.flipHorizontally) { @@ -355,6 +355,7 @@ class TileMapPaintingPreview { sprite.scale.y *= -1; } } else { + // If the tileset is badly configured, use tiled sprite with the invalid texture. sprite = new PIXI.TilingSprite(texture, 2, 2); sprite.tileScale.x = this.viewPosition.toCanvasScale(scaleX); sprite.tileScale.y = this.viewPosition.toCanvasScale(scaleY); From a94c2d2b5032c5a7c615366fce37fdcba8a48b31 Mon Sep 17 00:00:00 2001 From: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com> Date: Mon, 16 Sep 2024 16:15:03 +0200 Subject: [PATCH 03/12] Use tiled sprite to paint any tile --- .../InstancesEditor/TileMapPaintingPreview.js | 67 ++++++++++--------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/newIDE/app/src/InstancesEditor/TileMapPaintingPreview.js b/newIDE/app/src/InstancesEditor/TileMapPaintingPreview.js index 9be5f756ad51..18fc55a57b39 100644 --- a/newIDE/app/src/InstancesEditor/TileMapPaintingPreview.js +++ b/newIDE/app/src/InstancesEditor/TileMapPaintingPreview.js @@ -98,7 +98,7 @@ export const isTileSetBadlyConfigured = ({ /** * Returns the list of tiles corresponding to the user selection. - * If only one coordinate is present, only one tile is places at the slot the + * If only one coordinate is present, only one tile is placed at the slot the * pointer points to. * If two coordinates are present, tiles are displayed to form a rectangle with the * two coordinates being the top left and bottom right corner of the rectangle. @@ -339,43 +339,46 @@ class TileMapPaintingPreview { sceneToTileMapTransformation: this.sceneToTileMapTransformation, } ); + if (spritesCoordinatesInTileMapGrid.length === 0) { + console.warn("Could't get coordinates to render in tile map grid."); + return; + } const workingPoint = [0, 0]; - spritesCoordinatesInTileMapGrid.forEach(({ x, y }) => { - let sprite; + const sprite = new PIXI.TilingSprite(texture); + + sprite.tileScale.x = + (tileMapTileSelection.flipHorizontally ? -1 : +1) * + this.viewPosition.toCanvasScale(scaleX); + sprite.tileScale.y = + (tileMapTileSelection.flipVertically ? -1 : +1) * + this.viewPosition.toCanvasScale(scaleY); + sprite.width = spriteWidth; + sprite.height = spriteHeight; + + const allXCoordinates = spritesCoordinatesInTileMapGrid.map(({ x }) => x); + const allYCoordinates = spritesCoordinatesInTileMapGrid.map(({ y }) => y); + const minX = Math.min(...allXCoordinates); + const maxX = Math.max(...allXCoordinates); + const minY = Math.min(...allYCoordinates); + const maxY = Math.max(...allYCoordinates); + + this.tileMapToSceneTransformation.transform( + [minX * tileSize, minY * tileSize], + workingPoint + ); - if (tileMapTileSelection.kind === 'single') { - // TODO: Find a way not to regenerate the sprites on each render. - sprite = new PIXI.Sprite(texture); - if (tileMapTileSelection.flipHorizontally) { - sprite.scale.x *= -1; - } - if (tileMapTileSelection.flipVertically) { - sprite.scale.y *= -1; - } - } else { - // If the tileset is badly configured, use tiled sprite with the invalid texture. - sprite = new PIXI.TilingSprite(texture, 2, 2); - sprite.tileScale.x = this.viewPosition.toCanvasScale(scaleX); - sprite.tileScale.y = this.viewPosition.toCanvasScale(scaleY); - } - sprite.anchor.x = 0.5; - sprite.anchor.y = 0.5; - sprite.width = spriteWidth; - sprite.height = spriteHeight; - - this.tileMapToSceneTransformation.transform( - [x * tileSize + tileSize / 2, y * tileSize + tileSize / 2], - workingPoint - ); + sprite.x = this.viewPosition.toCanvasScale(workingPoint[0]); + sprite.y = this.viewPosition.toCanvasScale(workingPoint[1]); + sprite.width = + (maxX - minX + 1) * this.viewPosition.toCanvasScale(tileSize) * scaleX; + sprite.height = + (maxY - minY + 1) * this.viewPosition.toCanvasScale(tileSize) * scaleY; - sprite.x = this.viewPosition.toCanvasScale(workingPoint[0]); - sprite.y = this.viewPosition.toCanvasScale(workingPoint[1]); - sprite.angle = instance.getAngle(); + sprite.angle = instance.getAngle(); - this.preview.addChild(sprite); - }); + this.preview.addChild(sprite); const canvasCoordinates = this.viewPosition.toCanvasCoordinates(0, 0); this.preview.position.x = canvasCoordinates[0]; From 2cda1fa9314be9a3eee3d5ca304e9e8acd0e8eb3 Mon Sep 17 00:00:00 2001 From: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com> Date: Mon, 16 Sep 2024 16:28:21 +0200 Subject: [PATCH 04/12] Fix tilemap preview when there is angle --- .../InstancesEditor/TileMapPaintingPreview.js | 68 +++++++++++-------- 1 file changed, 38 insertions(+), 30 deletions(-) diff --git a/newIDE/app/src/InstancesEditor/TileMapPaintingPreview.js b/newIDE/app/src/InstancesEditor/TileMapPaintingPreview.js index 18fc55a57b39..fdef19685c4d 100644 --- a/newIDE/app/src/InstancesEditor/TileMapPaintingPreview.js +++ b/newIDE/app/src/InstancesEditor/TileMapPaintingPreview.js @@ -134,45 +134,53 @@ export const getTilesGridCoordinatesFromPointerSceneCoordinates = ({ }); } if (coordinates.length === 2) { - const topLeftCornerCoordinatesInTileMap = [0, 0]; - const bottomRightCornerCoordinatesInTileMap = [0, 0]; - + const firstPointCoordinatesInTileMap = [0, 0]; sceneToTileMapTransformation.transform( - [ - Math.min(coordinates[0].x, coordinates[1].x), - Math.min(coordinates[0].y, coordinates[1].y), - ], - topLeftCornerCoordinatesInTileMap - ); - topLeftCornerCoordinatesInTileMap[0] = Math.floor( - topLeftCornerCoordinatesInTileMap[0] / tileSize - ); - topLeftCornerCoordinatesInTileMap[1] = Math.floor( - topLeftCornerCoordinatesInTileMap[1] / tileSize + [coordinates[0].x, coordinates[0].y], + firstPointCoordinatesInTileMap ); - + const secondPointCoordinatesInTileMap = [0, 0]; sceneToTileMapTransformation.transform( - [ - Math.max(coordinates[0].x, coordinates[1].x), - Math.max(coordinates[0].y, coordinates[1].y), - ], - bottomRightCornerCoordinatesInTileMap - ); - bottomRightCornerCoordinatesInTileMap[0] = Math.floor( - bottomRightCornerCoordinatesInTileMap[0] / tileSize - ); - bottomRightCornerCoordinatesInTileMap[1] = Math.floor( - bottomRightCornerCoordinatesInTileMap[1] / tileSize + [coordinates[1].x, coordinates[1].y], + secondPointCoordinatesInTileMap ); + const topLeftCornerCoordinatesInTileMap = [ + Math.min( + firstPointCoordinatesInTileMap[0], + secondPointCoordinatesInTileMap[0] + ), + Math.min( + firstPointCoordinatesInTileMap[1], + secondPointCoordinatesInTileMap[1] + ), + ]; + const bottomRightCornerCoordinatesInTileMap = [ + Math.max( + firstPointCoordinatesInTileMap[0], + secondPointCoordinatesInTileMap[0] + ), + Math.max( + firstPointCoordinatesInTileMap[1], + secondPointCoordinatesInTileMap[1] + ), + ]; + const topLeftCornerCoordinatesInTileMapGrid = [ + Math.floor(topLeftCornerCoordinatesInTileMap[0] / tileSize), + Math.floor(topLeftCornerCoordinatesInTileMap[1] / tileSize), + ]; + const bottomRightCornerCoordinatesInTileMapGrid = [ + Math.floor(bottomRightCornerCoordinatesInTileMap[0] / tileSize), + Math.floor(bottomRightCornerCoordinatesInTileMap[1] / tileSize), + ]; for ( - let columnIndex = topLeftCornerCoordinatesInTileMap[0]; - columnIndex <= bottomRightCornerCoordinatesInTileMap[0]; + let columnIndex = topLeftCornerCoordinatesInTileMapGrid[0]; + columnIndex <= bottomRightCornerCoordinatesInTileMapGrid[0]; columnIndex++ ) { for ( - let rowIndex = topLeftCornerCoordinatesInTileMap[1]; - rowIndex <= bottomRightCornerCoordinatesInTileMap[1]; + let rowIndex = topLeftCornerCoordinatesInTileMapGrid[1]; + rowIndex <= bottomRightCornerCoordinatesInTileMapGrid[1]; rowIndex++ ) { tilesCoordinatesInTileMapGrid.push({ x: columnIndex, y: rowIndex }); From 1ff5813205926ff073e566fb61e47a18a17dc2aa Mon Sep 17 00:00:00 2001 From: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com> Date: Mon, 16 Sep 2024 17:19:40 +0200 Subject: [PATCH 05/12] Allow tilemaps with atlas dimensions not exactly a tile size multiple --- Extensions/TileMap/JsExtension.js | 21 +++++- .../src/InstancesEditor/TileSetVisualizer.js | 74 ++++++++++++------- .../Editors/SimpleTileMapEditor.js | 18 ++--- 3 files changed, 71 insertions(+), 42 deletions(-) diff --git a/Extensions/TileMap/JsExtension.js b/Extensions/TileMap/JsExtension.js index e80702f63363..3ef3dfcec2c3 100644 --- a/Extensions/TileMap/JsExtension.js +++ b/Extensions/TileMap/JsExtension.js @@ -630,7 +630,12 @@ const defineSimpleTileMap = function (extension, _, gd) { objectProperties.set( 'columnCount', - new gd.PropertyDescriptor((objectContent.columnCount || 4).toString()) + new gd.PropertyDescriptor( + (typeof objectContent.columnCount === 'undefined' + ? 4 + : objectContent.columnCount + ).toString() + ) .setType('number') .setLabel(_('Columns')) .setDescription(_('Number of columns.')) @@ -638,7 +643,12 @@ const defineSimpleTileMap = function (extension, _, gd) { ); objectProperties.set( 'rowCount', - new gd.PropertyDescriptor((objectContent.rowCount || 4).toString()) + new gd.PropertyDescriptor( + (typeof objectContent.rowCount === 'undefined' + ? 4 + : objectContent.rowCount + ).toString() + ) .setType('number') .setLabel(_('Rows')) .setDescription(_('Number of rows.')) @@ -646,7 +656,12 @@ const defineSimpleTileMap = function (extension, _, gd) { ); objectProperties.set( 'tileSize', - new gd.PropertyDescriptor((objectContent.tileSize || 8).toString()) + new gd.PropertyDescriptor( + (typeof objectContent.tileSize === 'undefined' + ? 8 + : objectContent.tileSize + ).toString() + ) .setType('number') .setLabel(_('Tile size')) .setDescription(_('Tile size in pixels.')) diff --git a/newIDE/app/src/InstancesEditor/TileSetVisualizer.js b/newIDE/app/src/InstancesEditor/TileSetVisualizer.js index 7b1e068a8a1a..ee98eb1913a1 100644 --- a/newIDE/app/src/InstancesEditor/TileSetVisualizer.js +++ b/newIDE/app/src/InstancesEditor/TileSetVisualizer.js @@ -16,6 +16,7 @@ import useForceUpdate from '../Utils/UseForceUpdate'; import { useLongTouch, type ClientCoordinates } from '../Utils/UseLongTouch'; import Text from '../UI/Text'; import EmptyMessage from '../UI/EmptyMessage'; +import { isTileSetBadlyConfigured } from './TileMapPaintingPreview'; const styles = { tilesetAndTooltipsContainer: { @@ -251,18 +252,22 @@ const TileSetVisualizer = ({ x: number, y: number, |}>(null); + const objectConfigurationProperties = objectConfiguration.getProperties(); const columnCount = parseFloat( - objectConfiguration - .getProperties() - .get('columnCount') - .getValue() + objectConfigurationProperties.get('columnCount').getValue() ); const rowCount = parseFloat( - objectConfiguration - .getProperties() - .get('rowCount') - .getValue() + objectConfigurationProperties.get('rowCount').getValue() ); + const tileSize = parseFloat( + objectConfigurationProperties.get('tileSize').getValue() + ); + const isBadlyConfigured = isTileSetBadlyConfigured({ + atlasImage: '', + columnCount, + rowCount, + tileSize, + }); const [clickStartCoordinates, setClickStartCoordinates] = React.useState { + if (onAtlasImageLoaded) onAtlasImageLoaded(e, atlasResourceName); + }, + [onAtlasImageLoaded, atlasResourceName] + ); const displayTileIdTooltip = React.useCallback( (e: ClientCoordinates) => { setShouldCancelClick(true); - if (!displayedTileSize) return; + if (!displayedTileSize || isBadlyConfigured) return; const imageCoordinates = getImageCoordinatesFromPointerEvent(e); if (!imageCoordinates) return; @@ -320,7 +336,7 @@ const TileSetVisualizer = ({ label: getTileIdFromGridCoordinates({ x, y, columnCount }).toString(), }); }, - [displayedTileSize, columnCount, rowCount] + [displayedTileSize, columnCount, rowCount, isBadlyConfigured] ); const longTouchProps = useLongTouch(displayTileIdTooltip); @@ -334,21 +350,26 @@ const TileSetVisualizer = ({ [forceUpdate] ); - const onPointerDown = React.useCallback((event: PointerEvent) => { - if (event.pointerType === 'touch') { - setTouchStartCoordinates({ x: event.pageX, y: event.pageY }); - } - const imageCoordinates = getImageCoordinatesFromPointerEvent(event); - if (!imageCoordinates) return; - setClickStartCoordinates({ - x: imageCoordinates.mouseX, - y: imageCoordinates.mouseY, - }); - }, []); + const onPointerDown = React.useCallback( + (event: PointerEvent) => { + if (isBadlyConfigured) return; + if (event.pointerType === 'touch') { + setTouchStartCoordinates({ x: event.pageX, y: event.pageY }); + } + const imageCoordinates = getImageCoordinatesFromPointerEvent(event); + if (!imageCoordinates) return; + setClickStartCoordinates({ + x: imageCoordinates.mouseX, + y: imageCoordinates.mouseY, + }); + }, + [isBadlyConfigured] + ); const onPointerMove = React.useCallback( (event: PointerEvent) => { if ( + isBadlyConfigured || !clickStartCoordinates || !displayedTileSize || !allowMultipleSelection || @@ -386,6 +407,7 @@ const TileSetVisualizer = ({ }); }, [ + isBadlyConfigured, displayedTileSize, columnCount, rowCount, @@ -397,7 +419,7 @@ const TileSetVisualizer = ({ const onPointerUp = React.useCallback( (event: PointerEvent) => { try { - if (!displayedTileSize) return; + if (!displayedTileSize || isBadlyConfigured) return; if (shouldCancelClick) { setShouldCancelClick(false); return; @@ -503,6 +525,7 @@ const TileSetVisualizer = ({ } }, [ + isBadlyConfigured, displayedTileSize, columnCount, rowCount, @@ -741,10 +764,7 @@ const TileSetVisualizer = ({ atlasResourceName, {} )} - onLoad={e => { - if (onAtlasImageLoaded) - onAtlasImageLoaded(e, atlasResourceName); - }} + onLoad={_onAtlasImageLoaded} /> {interactive && hoveredTile && displayedTileSize && ( diff --git a/newIDE/app/src/ObjectEditor/Editors/SimpleTileMapEditor.js b/newIDE/app/src/ObjectEditor/Editors/SimpleTileMapEditor.js index 3513f78aff67..430f6ab81a66 100644 --- a/newIDE/app/src/ObjectEditor/Editors/SimpleTileMapEditor.js +++ b/newIDE/app/src/ObjectEditor/Editors/SimpleTileMapEditor.js @@ -67,12 +67,13 @@ const SimpleTileMapEditor = ({ |}, tileSize: number ) => { - const newRowCount = dimensions.height / tileSize; - const newColumnCount = dimensions.width / tileSize; + const newRowCount = Math.floor(dimensions.height / tileSize); + const newColumnCount = Math.floor(dimensions.width / tileSize); if (rowCount === newRowCount && columnCount === newColumnCount) { return; } + setError(null); objectConfiguration.updateProperty('rowCount', newRowCount.toString()); objectConfiguration.updateProperty( 'columnCount', @@ -92,7 +93,6 @@ const SimpleTileMapEditor = ({ if (!value) { return; } - setError(null); objectConfiguration.updateProperty('tileSize', value.toString()); if (loadedAtlasImageDimensions) { recomputeTileSet(loadedAtlasImageDimensions, value); @@ -140,17 +140,11 @@ const SimpleTileMapEditor = ({ React.useEffect( () => { if (!loadedAtlasImageDimensions) return; - const _rowCount = loadedAtlasImageDimensions.height / tileSize; - const _columnCount = loadedAtlasImageDimensions.width / tileSize; - if (!Number.isInteger(_rowCount) || !Number.isInteger(_columnCount)) { - setError( - - The new atlas image size is not compatible with the tile size. - - ); + if (rowCount <= 0 || columnCount <= 0) { + setError(The atlas image is smaller than the tile size.); } }, - [tileSize, loadedAtlasImageDimensions] + [rowCount, columnCount, loadedAtlasImageDimensions] ); const onAtlasImageLoaded = React.useCallback( From 4e4af17862d98a109f9050591ce3bb8225c3c9d5 Mon Sep 17 00:00:00 2001 From: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com> Date: Mon, 16 Sep 2024 17:31:54 +0200 Subject: [PATCH 06/12] Fix react warning --- newIDE/app/src/CompactPropertiesEditor/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/newIDE/app/src/CompactPropertiesEditor/index.js b/newIDE/app/src/CompactPropertiesEditor/index.js index a135da98f4ed..0955518a95df 100644 --- a/newIDE/app/src/CompactPropertiesEditor/index.js +++ b/newIDE/app/src/CompactPropertiesEditor/index.js @@ -618,6 +618,7 @@ const CompactPropertiesEditor = ({ compactSelectField = ( { instances.forEach(i => setValue(i, parseFloat(newValue) || 0)); @@ -640,6 +641,7 @@ const CompactPropertiesEditor = ({ field, defaultValue: '(Multiple values)', })} + key={field.name} id={field.name} onChange={(newValue: string) => { instances.forEach(i => setValue(i, newValue || '')); From c3d3fc86804d3b09b442bb6092789e045248f148 Mon Sep 17 00:00:00 2001 From: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com> Date: Mon, 16 Sep 2024 17:44:43 +0200 Subject: [PATCH 07/12] Make error case not bugging --- Extensions/TileMap/JsExtension.js | 4 +++- .../src/InstancesEditor/TileMapPaintingPreview.js | 12 +++++++----- .../src/ObjectEditor/Editors/SimpleTileMapEditor.js | 1 + 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Extensions/TileMap/JsExtension.js b/Extensions/TileMap/JsExtension.js index 3ef3dfcec2c3..7101ad1f7703 100644 --- a/Extensions/TileMap/JsExtension.js +++ b/Extensions/TileMap/JsExtension.js @@ -2338,7 +2338,9 @@ module.exports = { ? this._editableTileMap.isEmpty() : false; let objectToChange; - if (isTileMapEmpty || !atlasImageResourceName) { + if (this.errorPixiObject) { + objectToChange = this.errorPixiObject; + } else if (isTileMapEmpty || !atlasImageResourceName) { this.tileMapPixiObject.visible = false; this._placeholderPixiObject.visible = true; this._placeholderTextPixiObject.text = !atlasImageResourceName diff --git a/newIDE/app/src/InstancesEditor/TileMapPaintingPreview.js b/newIDE/app/src/InstancesEditor/TileMapPaintingPreview.js index fdef19685c4d..c730d700c86d 100644 --- a/newIDE/app/src/InstancesEditor/TileMapPaintingPreview.js +++ b/newIDE/app/src/InstancesEditor/TileMapPaintingPreview.js @@ -25,14 +25,16 @@ export const updateSceneToTileMapTransformation = ( scaleY = 1; if (instance.hasCustomSize()) { const editableTileMap = renderedInstance.getEditableTileMap(); - if (!editableTileMap) { + if (editableTileMap) { + scaleX = instance.getCustomWidth() / editableTileMap.getWidth(); + scaleY = instance.getCustomHeight() / editableTileMap.getHeight(); + } else { console.error( - `Could not find the editable tile map for instance of object ${instance.getObjectName()}.` + `Could not find the editable tile map for instance of object ${instance.getObjectName()}. Make sure the tile map object is correctly configured.` ); - return; + // Do not early return on error to make the preview still working to not give + // a sense of something broken. } - scaleX = instance.getCustomWidth() / editableTileMap.getWidth(); - scaleY = instance.getCustomHeight() / editableTileMap.getHeight(); } const absScaleX = Math.abs(scaleX); const absScaleY = Math.abs(scaleY); diff --git a/newIDE/app/src/ObjectEditor/Editors/SimpleTileMapEditor.js b/newIDE/app/src/ObjectEditor/Editors/SimpleTileMapEditor.js index 430f6ab81a66..dc5e6a4354a6 100644 --- a/newIDE/app/src/ObjectEditor/Editors/SimpleTileMapEditor.js +++ b/newIDE/app/src/ObjectEditor/Editors/SimpleTileMapEditor.js @@ -131,6 +131,7 @@ const SimpleTileMapEditor = ({ const onChangeAtlasImage = React.useCallback( () => { if (onObjectUpdated) onObjectUpdated(); + setError(null); onSizeUpdated(); forceUpdate(); }, From 5172201da94ba1aa13b50142133ea719845c7b54 Mon Sep 17 00:00:00 2001 From: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com> Date: Mon, 16 Sep 2024 17:52:40 +0200 Subject: [PATCH 08/12] Avoid crash in preview when tilemap badly configured --- Extensions/TileMap/simpletilemapruntimeobject.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Extensions/TileMap/simpletilemapruntimeobject.ts b/Extensions/TileMap/simpletilemapruntimeobject.ts index 9ac1f68ceab8..c9887fd81979 100644 --- a/Extensions/TileMap/simpletilemapruntimeobject.ts +++ b/Extensions/TileMap/simpletilemapruntimeobject.ts @@ -218,6 +218,12 @@ namespace gdjs { tileMapLoadingCallback: (tileMap: TileMapHelper.EditableTileMap) => void ): void { if (!this._initialTileMapAsJsObject) return; + if (this._columnCount <= 0 || this._rowCount <= 0) { + console.error( + `Tilemap object ${this.name} is not configured properly.` + ); + return; + } this._tileMapManager.getOrLoadSimpleTileMap( this._initialTileMapAsJsObject, From 3dc78c652785261ed4947b96930f1ccb38a765b3 Mon Sep 17 00:00:00 2001 From: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com> Date: Mon, 16 Sep 2024 17:59:51 +0200 Subject: [PATCH 09/12] Add missing parameter in tilemap sentences --- Extensions/TileMap/JsExtension.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Extensions/TileMap/JsExtension.js b/Extensions/TileMap/JsExtension.js index 7101ad1f7703..fe66fa982804 100644 --- a/Extensions/TileMap/JsExtension.js +++ b/Extensions/TileMap/JsExtension.js @@ -830,7 +830,7 @@ const defineSimpleTileMap = function (extension, _, gd) { 'TileIdAtPosition', _('Tile (at position)'), _('the id of the tile at the scene coordinates'), - _('the tile id at scene coordinates _PARAM3_ ; _PARAM4_'), + _('the tile id at scene coordinates _PARAM3_ ; _PARAM4_ of _PARAM0_'), '', 'JsPlatform/Extensions/tile_map.svg' ) @@ -847,7 +847,7 @@ const defineSimpleTileMap = function (extension, _, gd) { _('Flip tile vertically (at position)'), _('Flip tile vertically at scene coordinates.'), _( - 'Flip tile vertically at scene coordinates _PARAM1_ ; _PARAM2_: _PARAM3_' + 'Flip tile vertically at scene coordinates _PARAM1_ ; _PARAM2_: _PARAM3_ of _PARAM0_' ), _('Effects'), 'res/actions/flipY24.png', @@ -866,7 +866,7 @@ const defineSimpleTileMap = function (extension, _, gd) { _('Flip tile horizontally (at position)'), _('Flip tile horizontally at scene coordinates.'), _( - 'Flip tile horizontally at scene coordinates _PARAM1_ ; _PARAM2_: _PARAM3_' + 'Flip tile horizontally at scene coordinates _PARAM1_ ; _PARAM2_: _PARAM3_ of _PARAM0_' ), _('Effects'), 'res/actions/flipX24.png', @@ -918,7 +918,7 @@ const defineSimpleTileMap = function (extension, _, gd) { _('Flip tile vertically (on the grid)'), _('Flip tile vertically at grid coordinates.'), _( - 'Flip tile vertically at grid coordinates _PARAM1_ ; _PARAM2_: _PARAM3_' + 'Flip tile vertically at grid coordinates _PARAM1_ ; _PARAM2_: _PARAM3_ of _PARAM0_' ), _('Effects'), 'res/actions/flipY24.png', @@ -937,7 +937,7 @@ const defineSimpleTileMap = function (extension, _, gd) { _('Flip tile horizontally (on the grid)'), _('Flip tile horizontally at grid coordinates.'), _( - 'Flip tile horizontally at grid coordinates _PARAM1_ ; _PARAM2_: _PARAM3_' + 'Flip tile horizontally at grid coordinates _PARAM1_ ; _PARAM2_: _PARAM3_ of _PARAM0_' ), _('Effects'), 'res/actions/flipX24.png', @@ -955,7 +955,7 @@ const defineSimpleTileMap = function (extension, _, gd) { 'RemoveTileAtGridCoordinates', _('Remove tile (on the grid)'), _('Remove the tile at the grid coordinates.'), - _('Remove tile at grid coordinates _PARAM1_ ; _PARAM2_'), + _('Remove tile at grid coordinates _PARAM1_ ; _PARAM2_ of _PARAM0_'), '', 'JsPlatform/Extensions/tile_map.svg', 'JsPlatform/Extensions/tile_map.svg' @@ -972,7 +972,7 @@ const defineSimpleTileMap = function (extension, _, gd) { _('Tile flipped horizontally (at position)'), _('Check if tile at scene coordinates is flipped horizontally.'), _( - 'The tile at scene coordinates _PARAM1_ ; _PARAM2_ is flipped horizontally' + 'The tile at scene coordinates _PARAM1_ ; _PARAM2_ of _PARAM0_ is flipped horizontally' ), _('Effects'), 'res/actions/flipX24.png', @@ -990,7 +990,7 @@ const defineSimpleTileMap = function (extension, _, gd) { _('Tile flipped vertically (at position)'), _('Check if tile at scene coordinates is flipped vertically.'), _( - 'The tile at scene coordinates _PARAM1_ ; _PARAM2_ is flipped vertically' + 'The tile at scene coordinates _PARAM1_ ; _PARAM2_ of _PARAM0_ is flipped vertically' ), _('Effects'), 'res/actions/flipY24.png', @@ -1008,7 +1008,7 @@ const defineSimpleTileMap = function (extension, _, gd) { _('Tile flipped horizontally (on the grid)'), _('Check if tile at grid coordinates is flipped horizontally.'), _( - 'The tile at grid coordinates _PARAM1_ ; _PARAM2_ is flipped horizontally' + 'The tile at grid coordinates _PARAM1_ ; _PARAM2_ of _PARAM0_ is flipped horizontally' ), _('Effects'), 'res/actions/flipX24.png', @@ -1026,7 +1026,7 @@ const defineSimpleTileMap = function (extension, _, gd) { _('Tile flipped vertically (on the grid)'), _('Check if tile at grid coordinates is flipped vertically.'), _( - 'The tile at grid coordinates _PARAM1_ ; _PARAM2_ is flipped vertically' + 'The tile at grid coordinates _PARAM1_ ; _PARAM2_ of _PARAM0_ is flipped vertically' ), _('Effects'), 'res/actions/flipY24.png', From acde4230a9e62aed814571240f4e307bff4f4551 Mon Sep 17 00:00:00 2001 From: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com> Date: Tue, 17 Sep 2024 09:39:43 +0200 Subject: [PATCH 10/12] Fix sentences --- Extensions/TileMap/JsExtension.js | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Extensions/TileMap/JsExtension.js b/Extensions/TileMap/JsExtension.js index fe66fa982804..eaf77b877dda 100644 --- a/Extensions/TileMap/JsExtension.js +++ b/Extensions/TileMap/JsExtension.js @@ -750,7 +750,7 @@ const defineSimpleTileMap = function (extension, _, gd) { .addExpression( 'TilesetColumnCount', _('Tileset column count'), - _('Get the number of column in the tileset.'), + _('Get the number of columns in the tileset.'), '', 'JsPlatform/Extensions/tile_map.svg' ) @@ -761,7 +761,7 @@ const defineSimpleTileMap = function (extension, _, gd) { .addExpression( 'TilesetRowCount', _('Tileset row count'), - _('Get the number of row in the tileset.'), + _('Get the number of rows in the tileset.'), '', 'JsPlatform/Extensions/tile_map.svg' ) @@ -830,7 +830,7 @@ const defineSimpleTileMap = function (extension, _, gd) { 'TileIdAtPosition', _('Tile (at position)'), _('the id of the tile at the scene coordinates'), - _('the tile id at scene coordinates _PARAM3_ ; _PARAM4_ of _PARAM0_'), + _('the tile id in _PARAM0_ at scene coordinates _PARAM3_ ; _PARAM4_'), '', 'JsPlatform/Extensions/tile_map.svg' ) @@ -847,7 +847,7 @@ const defineSimpleTileMap = function (extension, _, gd) { _('Flip tile vertically (at position)'), _('Flip tile vertically at scene coordinates.'), _( - 'Flip tile vertically at scene coordinates _PARAM1_ ; _PARAM2_: _PARAM3_ of _PARAM0_' + 'Flip tile vertically in _PARAM0_ at scene coordinates _PARAM1_ ; _PARAM2_: _PARAM3_' ), _('Effects'), 'res/actions/flipY24.png', @@ -866,7 +866,7 @@ const defineSimpleTileMap = function (extension, _, gd) { _('Flip tile horizontally (at position)'), _('Flip tile horizontally at scene coordinates.'), _( - 'Flip tile horizontally at scene coordinates _PARAM1_ ; _PARAM2_: _PARAM3_ of _PARAM0_' + 'Flip tile horizontally in _PARAM0_ at scene coordinates _PARAM1_ ; _PARAM2_: _PARAM3_' ), _('Effects'), 'res/actions/flipX24.png', @@ -884,7 +884,7 @@ const defineSimpleTileMap = function (extension, _, gd) { 'RemoveTileAtPosition', _('Remove tile (at position)'), _('Remove the tile at the scene coordinates.'), - _('Remove tile at scene coordinates _PARAM1_ ; _PARAM2_'), + _('Remove tile in _PARAM0_ at scene coordinates _PARAM1_ ; _PARAM2_'), '', 'JsPlatform/Extensions/tile_map.svg', 'JsPlatform/Extensions/tile_map.svg' @@ -918,7 +918,7 @@ const defineSimpleTileMap = function (extension, _, gd) { _('Flip tile vertically (on the grid)'), _('Flip tile vertically at grid coordinates.'), _( - 'Flip tile vertically at grid coordinates _PARAM1_ ; _PARAM2_: _PARAM3_ of _PARAM0_' + 'Flip tile vertically in _PARAM0_ at grid coordinates _PARAM1_ ; _PARAM2_: _PARAM3_' ), _('Effects'), 'res/actions/flipY24.png', @@ -937,7 +937,7 @@ const defineSimpleTileMap = function (extension, _, gd) { _('Flip tile horizontally (on the grid)'), _('Flip tile horizontally at grid coordinates.'), _( - 'Flip tile horizontally at grid coordinates _PARAM1_ ; _PARAM2_: _PARAM3_ of _PARAM0_' + 'Flip tile horizontally in _PARAM0_ at grid coordinates _PARAM1_ ; _PARAM2_: _PARAM3_' ), _('Effects'), 'res/actions/flipX24.png', @@ -955,7 +955,7 @@ const defineSimpleTileMap = function (extension, _, gd) { 'RemoveTileAtGridCoordinates', _('Remove tile (on the grid)'), _('Remove the tile at the grid coordinates.'), - _('Remove tile at grid coordinates _PARAM1_ ; _PARAM2_ of _PARAM0_'), + _('Remove tile in _PARAM0_ at grid coordinates _PARAM1_ ; _PARAM2_'), '', 'JsPlatform/Extensions/tile_map.svg', 'JsPlatform/Extensions/tile_map.svg' @@ -972,7 +972,7 @@ const defineSimpleTileMap = function (extension, _, gd) { _('Tile flipped horizontally (at position)'), _('Check if tile at scene coordinates is flipped horizontally.'), _( - 'The tile at scene coordinates _PARAM1_ ; _PARAM2_ of _PARAM0_ is flipped horizontally' + 'The tile in _PARAM0_ at scene coordinates _PARAM1_ ; _PARAM2_ is flipped horizontally' ), _('Effects'), 'res/actions/flipX24.png', @@ -990,7 +990,7 @@ const defineSimpleTileMap = function (extension, _, gd) { _('Tile flipped vertically (at position)'), _('Check if tile at scene coordinates is flipped vertically.'), _( - 'The tile at scene coordinates _PARAM1_ ; _PARAM2_ of _PARAM0_ is flipped vertically' + 'The tile in _PARAM0_ at scene coordinates _PARAM1_ ; _PARAM2_ is flipped vertically' ), _('Effects'), 'res/actions/flipY24.png', @@ -1008,7 +1008,7 @@ const defineSimpleTileMap = function (extension, _, gd) { _('Tile flipped horizontally (on the grid)'), _('Check if tile at grid coordinates is flipped horizontally.'), _( - 'The tile at grid coordinates _PARAM1_ ; _PARAM2_ of _PARAM0_ is flipped horizontally' + 'The tile in _PARAM0_ at grid coordinates _PARAM1_ ; _PARAM2_ is flipped horizontally' ), _('Effects'), 'res/actions/flipX24.png', @@ -1026,7 +1026,7 @@ const defineSimpleTileMap = function (extension, _, gd) { _('Tile flipped vertically (on the grid)'), _('Check if tile at grid coordinates is flipped vertically.'), _( - 'The tile at grid coordinates _PARAM1_ ; _PARAM2_ of _PARAM0_ is flipped vertically' + 'The tile in _PARAM0_ at grid coordinates _PARAM1_ ; _PARAM2_ is flipped vertically' ), _('Effects'), 'res/actions/flipY24.png', From 41d8458aab9e4ca7d3a8d94e94419ceaeda03e6f Mon Sep 17 00:00:00 2001 From: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com> Date: Tue, 17 Sep 2024 09:45:06 +0200 Subject: [PATCH 11/12] Improve max and min computation --- .../InstancesEditor/TileMapPaintingPreview.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/newIDE/app/src/InstancesEditor/TileMapPaintingPreview.js b/newIDE/app/src/InstancesEditor/TileMapPaintingPreview.js index c730d700c86d..56b530349870 100644 --- a/newIDE/app/src/InstancesEditor/TileMapPaintingPreview.js +++ b/newIDE/app/src/InstancesEditor/TileMapPaintingPreview.js @@ -367,12 +367,16 @@ class TileMapPaintingPreview { sprite.width = spriteWidth; sprite.height = spriteHeight; - const allXCoordinates = spritesCoordinatesInTileMapGrid.map(({ x }) => x); - const allYCoordinates = spritesCoordinatesInTileMapGrid.map(({ y }) => y); - const minX = Math.min(...allXCoordinates); - const maxX = Math.max(...allXCoordinates); - const minY = Math.min(...allYCoordinates); - const maxY = Math.max(...allYCoordinates); + let minX = Infinity; + let minY = Infinity; + let maxX = -Infinity; + let maxY = -Infinity; + for (const { x, y } of spritesCoordinatesInTileMapGrid) { + if (x < minX) minX = x; + if (y < minY) minY = y; + if (x > maxX) maxX = x; + if (y > maxY) maxY = y; + } this.tileMapToSceneTransformation.transform( [minX * tileSize, minY * tileSize], From 448ac7c82bd712528ae7521ee220eb725e136920 Mon Sep 17 00:00:00 2001 From: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com> Date: Tue, 17 Sep 2024 09:57:52 +0200 Subject: [PATCH 12/12] Hide selected instance buttons when painting --- newIDE/app/src/InstancesEditor/SelectedInstances.js | 8 +++++++- newIDE/app/src/InstancesEditor/index.js | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/newIDE/app/src/InstancesEditor/SelectedInstances.js b/newIDE/app/src/InstancesEditor/SelectedInstances.js index 277185da8faf..152c4f097055 100644 --- a/newIDE/app/src/InstancesEditor/SelectedInstances.js +++ b/newIDE/app/src/InstancesEditor/SelectedInstances.js @@ -18,6 +18,7 @@ import KeyboardShortcuts from '../UI/KeyboardShortcuts'; type Props = {| instancesSelection: InstancesSelection, instanceMeasurer: InstanceMeasurer, + shouldDisplayHandles: () => boolean, onResize: ( deltaX: number, deltaY: number, @@ -72,6 +73,7 @@ const resizeGrabbingIconNames = { export default class SelectedInstances { instancesSelection: InstancesSelection; instanceMeasurer: InstanceMeasurer; + shouldDisplayHandles: () => boolean; onResize: ( deltaX: number, deltaY: number, @@ -105,6 +107,7 @@ export default class SelectedInstances { constructor({ instancesSelection, instanceMeasurer, + shouldDisplayHandles, onResize, onResizeEnd, onRotate, @@ -118,6 +121,7 @@ export default class SelectedInstances { }: Props) { this.instanceMeasurer = instanceMeasurer; this.onResize = onResize; + this.shouldDisplayHandles = shouldDisplayHandles; this.onResizeEnd = onResizeEnd; this.onRotate = onRotate; this.onRotateEnd = onRotateEnd; @@ -303,6 +307,7 @@ export default class SelectedInstances { buttonPadding, hitAreaPadding, } = getButtonSizes(this._screenType); + const displayHandle = this.shouldDisplayHandles(); const selection = this.instancesSelection.getSelectedInstances(); let x1 = 0; let y1 = 0; @@ -368,7 +373,8 @@ export default class SelectedInstances { // If there are no unlocked instances, hide the resize buttons. const show = - selection.filter(instance => !instance.isLocked()).length !== 0; + selection.filter(instance => !instance.isLocked()).length !== 0 && + displayHandle; // Position the resize buttons. for (const grabbingLocation of resizeGrabbingLocationValues) { diff --git a/newIDE/app/src/InstancesEditor/index.js b/newIDE/app/src/InstancesEditor/index.js index 698d95434bf0..6ee6d2f99e2b 100644 --- a/newIDE/app/src/InstancesEditor/index.js +++ b/newIDE/app/src/InstancesEditor/index.js @@ -505,6 +505,7 @@ export default class InstancesEditor extends Component { }); this.selectedInstances = new SelectedInstances({ instancesSelection: this.props.instancesSelection, + shouldDisplayHandles: this.shouldDisplayClickableHandles, onResize: this._onResize, onResizeEnd: this._onResizeEnd, onRotate: this._onRotate, @@ -733,6 +734,8 @@ export default class InstancesEditor extends Component { return { color: isLocked ? 0xbc5753 : 0x6868e8, alpha: 1 }; }; + shouldDisplayClickableHandles = () => !this.props.tileMapTileSelection; + getZoomFactor = () => { return this.props.instancesEditorSettings.zoomFactor; };