diff --git a/Extensions/BBText/JsExtension.js b/Extensions/BBText/JsExtension.js index dd76b4cb0f96..d3ed2e12fa61 100644 --- a/Extensions/BBText/JsExtension.js +++ b/Extensions/BBText/JsExtension.js @@ -666,7 +666,9 @@ module.exports = { this._pixiObject.dirty = true; } - if (this._instance.hasCustomSize() && this._pixiObject.width !== 0) { + const renderedWidth = this._pixiObject.width; + const centerX = this.getCenterX(); + if (this._instance.hasCustomSize() && renderedWidth !== 0) { const alignmentX = object.content.align === 'right' ? 1 @@ -675,28 +677,22 @@ module.exports = { : 0; const width = this.getCustomWidth(); + const leftOffset = (width - renderedWidth) * alignmentX; - // A vector from the custom size center to the renderer center. - const centerToCenterX = - (width - this._pixiObject.width) * (alignmentX - 0.5); - - this._pixiObject.position.x = this._instance.getX() + width / 2; - this._pixiObject.anchor.x = - 0.5 - centerToCenterX / this._pixiObject.width; + this._pixiObject.position.x = this._instance.getX(); + this._pixiObject.anchor.x = (centerX - leftOffset) / renderedWidth; + } else if (renderedWidth !== 0) { + this._pixiObject.position.x = this._instance.getX(); + this._pixiObject.anchor.x = centerX / renderedWidth; } else { - this._pixiObject.position.x = - this._instance.getX() + this._pixiObject.width / 2; - this._pixiObject.anchor.x = 0.5; + this._pixiObject.position.x = this._instance.getX(); + this._pixiObject.anchor.x = 0; } - const alignmentY = - object.content.verticalTextAlignment === 'bottom' - ? 1 - : object.content.verticalTextAlignment === 'center' - ? 0.5 - : 0; - this._pixiObject.position.y = - this._instance.getY() + this._pixiObject.height * (0.5 - alignmentY); - this._pixiObject.anchor.y = 0.5; + const renderedHeight = this._pixiObject.height; + const centerY = this.getCenterY(); + this._pixiObject.position.y = this._instance.getY(); + this._pixiObject.anchor.y = + renderedHeight !== 0 ? centerY / renderedHeight : 0; this._pixiObject.rotation = RenderedInstance.toRad( this._instance.getAngle() @@ -736,6 +732,14 @@ module.exports = { ? height / 2 : 0; } + + getCenterX() { + return 0; + } + + getCenterY() { + return this.getOriginY(); + } } objectsRenderingService.registerInstanceRenderer( diff --git a/Extensions/BBText/bbtextruntimeobject-pixi-renderer.ts b/Extensions/BBText/bbtextruntimeobject-pixi-renderer.ts index 09e1c7774cda..93170fa7458a 100644 --- a/Extensions/BBText/bbtextruntimeobject-pixi-renderer.ts +++ b/Extensions/BBText/bbtextruntimeobject-pixi-renderer.ts @@ -125,7 +125,10 @@ namespace gdjs { } updatePosition(): void { - if (this._object.isWrapping() && this._pixiObject.width !== 0) { + const renderedWidth = this._pixiObject.width; + const centerX = this._object.getCenterX(); + + if (this._object.isWrapping() && renderedWidth !== 0) { const alignmentX = this._object._textAlign === 'right' ? 1 @@ -134,29 +137,23 @@ namespace gdjs { : 0; const width = this._object.getWrappingWidth(); + const leftOffset = (width - renderedWidth) * alignmentX; - // A vector from the custom size center to the renderer center. - const centerToCenterX = - (width - this._pixiObject.width) * (alignmentX - 0.5); - - this._pixiObject.position.x = this._object.x + width / 2; - this._pixiObject.anchor.x = - 0.5 - centerToCenterX / this._pixiObject.width; + this._pixiObject.position.x = this._object.getDrawableX() + centerX; + this._pixiObject.anchor.x = (centerX - leftOffset) / renderedWidth; + } else if (renderedWidth !== 0) { + this._pixiObject.position.x = this._object.getDrawableX() + centerX; + this._pixiObject.anchor.x = centerX / renderedWidth; } else { - this._pixiObject.position.x = - this._object.x + this._pixiObject.width / 2; - this._pixiObject.anchor.x = 0.5; + this._pixiObject.position.x = this._object.getDrawableX() + centerX; + this._pixiObject.anchor.x = 0; } - const alignmentY = - this._object._verticalTextAlignment === 'bottom' - ? 1 - : this._object._verticalTextAlignment === 'center' - ? 0.5 - : 0; - this._pixiObject.position.y = - this._object.y + this._pixiObject.height * (0.5 - alignmentY); - this._pixiObject.anchor.y = 0.5; + const renderedHeight = this._pixiObject.height; + const centerY = this._object.getCenterY(); + this._pixiObject.position.y = this._object.getDrawableY() + centerY; + this._pixiObject.anchor.y = + renderedHeight !== 0 ? centerY / renderedHeight : 0; } updateAngle(): void { diff --git a/Extensions/BBText/bbtextruntimeobject.ts b/Extensions/BBText/bbtextruntimeobject.ts index 05437b713c38..3035fd9b50e7 100644 --- a/Extensions/BBText/bbtextruntimeobject.ts +++ b/Extensions/BBText/bbtextruntimeobject.ts @@ -404,6 +404,18 @@ namespace gdjs { this.setWrappingWidth(width); } + override getCenterX(): float { + return 0; + } + + override getCenterY(): float { + return this._verticalTextAlignment === 'bottom' + ? this.getHeight() + : this._verticalTextAlignment === 'center' + ? this.getHeight() / 2 + : 0; + } + override getDrawableY(): float { return ( this.getY() - diff --git a/Extensions/BitmapText/JsExtension.js b/Extensions/BitmapText/JsExtension.js index a298d722c974..703ed51a2d51 100644 --- a/Extensions/BitmapText/JsExtension.js +++ b/Extensions/BitmapText/JsExtension.js @@ -789,7 +789,9 @@ module.exports = { this._pixiObject.dirty = true; } - if (this._instance.hasCustomSize() && this.getDefaultWidth() !== 0) { + const renderedWidth = this.getDefaultWidth(); + const centerX = this.getCenterX(); + if (this._instance.hasCustomSize() && renderedWidth !== 0) { const alignmentX = object.content.align === 'right' ? 1 @@ -798,27 +800,22 @@ module.exports = { : 0; const width = this.getCustomWidth(); - const renderedWidth = this.getDefaultWidth(); + const leftOffset = (width - renderedWidth) * alignmentX; - // A vector from the custom size center to the renderer center. - const centerToCenterX = (width - renderedWidth) * (alignmentX - 0.5); - - this._pixiObject.position.x = this._instance.getX() + width / 2; - this._pixiObject.anchor.x = 0.5 - centerToCenterX / renderedWidth; + this._pixiObject.position.x = this._instance.getX(); + this._pixiObject.anchor.x = (centerX - leftOffset) / renderedWidth; + } else if (renderedWidth !== 0) { + this._pixiObject.position.x = this._instance.getX(); + this._pixiObject.anchor.x = centerX / renderedWidth; } else { - this._pixiObject.position.x = - this._instance.getX() + this.getDefaultWidth() / 2; - this._pixiObject.anchor.x = 0.5; + this._pixiObject.position.x = this._instance.getX(); + this._pixiObject.anchor.x = 0; } - const alignmentY = - object.content.verticalTextAlignment === 'bottom' - ? 1 - : object.content.verticalTextAlignment === 'center' - ? 0.5 - : 0; - this._pixiObject.position.y = - this._instance.getY() + this.getDefaultHeight() * (0.5 - alignmentY); - this._pixiObject.anchor.y = 0.5; + const renderedHeight = this.getDefaultHeight(); + const centerY = this.getCenterY(); + this._pixiObject.position.y = this._instance.getY(); + this._pixiObject.anchor.y = + renderedHeight !== 0 ? centerY / renderedHeight : 0; this._pixiObject.rotation = RenderedInstance.toRad( this._instance.getAngle() @@ -867,6 +864,14 @@ module.exports = { ? height / 2 : 0; } + + getCenterX() { + return 0; + } + + getCenterY() { + return this.getOriginY(); + } } objectsRenderingService.registerInstanceRenderer( diff --git a/Extensions/BitmapText/bitmaptextruntimeobject-pixi-renderer.ts b/Extensions/BitmapText/bitmaptextruntimeobject-pixi-renderer.ts index db056616b409..311870ab859e 100644 --- a/Extensions/BitmapText/bitmaptextruntimeobject-pixi-renderer.ts +++ b/Extensions/BitmapText/bitmaptextruntimeobject-pixi-renderer.ts @@ -156,7 +156,10 @@ namespace gdjs { } updatePosition(): void { - if (this._object.isWrapping() && this.getWidth() !== 0) { + const renderedWidth = this.getWidth(); + const centerX = this._object.getCenterX(); + + if (this._object.isWrapping() && renderedWidth !== 0) { const alignmentX = this._object._textAlign === 'right' ? 1 @@ -165,27 +168,23 @@ namespace gdjs { : 0; const width = this._object.getWrappingWidth(); - const renderedWidth = this.getWidth(); - - // A vector from the custom size center to the renderer center. - const centerToCenterX = (width - renderedWidth) * (alignmentX - 0.5); + const leftOffset = (width - renderedWidth) * alignmentX; - this._pixiObject.position.x = this._object.x + width / 2; - this._pixiObject.anchor.x = 0.5 - centerToCenterX / renderedWidth; + this._pixiObject.position.x = this._object.getDrawableX() + centerX; + this._pixiObject.anchor.x = (centerX - leftOffset) / renderedWidth; + } else if (renderedWidth !== 0) { + this._pixiObject.position.x = this._object.getDrawableX() + centerX; + this._pixiObject.anchor.x = centerX / renderedWidth; } else { - this._pixiObject.position.x = this._object.x + this.getWidth() / 2; - this._pixiObject.anchor.x = 0.5; + this._pixiObject.position.x = this._object.getDrawableX() + centerX; + this._pixiObject.anchor.x = 0; } - const alignmentY = - this._object._verticalTextAlignment === 'bottom' - ? 1 - : this._object._verticalTextAlignment === 'center' - ? 0.5 - : 0; - this._pixiObject.position.y = - this._object.y + this.getHeight() * (0.5 - alignmentY); - this._pixiObject.anchor.y = 0.5; + const renderedHeight = this.getHeight(); + const centerY = this._object.getCenterY(); + this._pixiObject.position.y = this._object.getDrawableY() + centerY; + this._pixiObject.anchor.y = + renderedHeight !== 0 ? centerY / renderedHeight : 0; } updateAngle(): void { diff --git a/Extensions/BitmapText/bitmaptextruntimeobject.ts b/Extensions/BitmapText/bitmaptextruntimeobject.ts index 9fdf1ce01e11..9905916a3e8b 100644 --- a/Extensions/BitmapText/bitmaptextruntimeobject.ts +++ b/Extensions/BitmapText/bitmaptextruntimeobject.ts @@ -449,6 +449,18 @@ namespace gdjs { this.setWrappingWidth(width); } + override getCenterX(): float { + return 0; + } + + override getCenterY(): float { + return this._verticalTextAlignment === 'bottom' + ? this.getHeight() + : this._verticalTextAlignment === 'center' + ? this.getHeight() / 2 + : 0; + } + override getDrawableY(): float { return ( this.getY() - diff --git a/Extensions/TextObject/textruntimeobject-pixi-renderer.ts b/Extensions/TextObject/textruntimeobject-pixi-renderer.ts index f8e73bc9a529..3b647b90e7a2 100644 --- a/Extensions/TextObject/textruntimeobject-pixi-renderer.ts +++ b/Extensions/TextObject/textruntimeobject-pixi-renderer.ts @@ -99,7 +99,10 @@ namespace gdjs { } updatePosition(): void { - if (this._object.isWrapping() && this._text.width !== 0) { + const renderedWidth = this._text.width; + const centerX = this._object.getCenterX(); + + if (this._object.isWrapping() && renderedWidth !== 0) { const alignmentX = this._object._textAlign === 'right' ? 1 @@ -108,26 +111,22 @@ namespace gdjs { : 0; const width = this._object.getWrappingWidth(); + const leftOffset = (width - renderedWidth) * alignmentX; - // A vector from the custom size center to the renderer center. - const centerToCenterX = (width - this._text.width) * (alignmentX - 0.5); - - this._text.position.x = this._object.x + width / 2; - this._text.anchor.x = 0.5 - centerToCenterX / this._text.width; + this._text.position.x = this._object.getDrawableX() + centerX; + this._text.anchor.x = (centerX - leftOffset) / renderedWidth; + } else if (renderedWidth !== 0) { + this._text.position.x = this._object.getDrawableX() + centerX; + this._text.anchor.x = centerX / renderedWidth; } else { - this._text.position.x = this._object.x + this._text.width / 2; - this._text.anchor.x = 0.5; + this._text.position.x = this._object.getDrawableX() + centerX; + this._text.anchor.x = 0; } - const alignmentY = - this._object._verticalTextAlignment === 'bottom' - ? 1 - : this._object._verticalTextAlignment === 'center' - ? 0.5 - : 0; - this._text.position.y = - this._object.y + this._text.height * (0.5 - alignmentY); - this._text.anchor.y = 0.5; + const renderedHeight = this._text.height; + const centerY = this._object.getCenterY(); + this._text.position.y = this._object.getDrawableY() + centerY; + this._text.anchor.y = renderedHeight !== 0 ? centerY / renderedHeight : 0; } updateAngle(): void { diff --git a/Extensions/TextObject/textruntimeobject.ts b/Extensions/TextObject/textruntimeobject.ts index 339c35938462..f36a0adb15e7 100644 --- a/Extensions/TextObject/textruntimeobject.ts +++ b/Extensions/TextObject/textruntimeobject.ts @@ -725,6 +725,18 @@ namespace gdjs { this.setWrappingWidth(width); } + override getCenterX(): float { + return 0; + } + + override getCenterY(): float { + return this._verticalTextAlignment === 'bottom' + ? this.getHeight() + : this._verticalTextAlignment === 'center' + ? this.getHeight() / 2 + : 0; + } + override getDrawableY(): float { return ( this.getY() - diff --git a/GDJS/tests/tests/textruntimeobject.pixiruntimegame.js b/GDJS/tests/tests/textruntimeobject.pixiruntimegame.js new file mode 100644 index 000000000000..f1949a08f49b --- /dev/null +++ b/GDJS/tests/tests/textruntimeobject.pixiruntimegame.js @@ -0,0 +1,71 @@ +// @ts-check +/** + * Tests for gdjs.TextRuntimeObject using the Pixi renderer. + */ + +describe('gdjs.TextRuntimeObject', () => { + /** @type {gdjs.RuntimeGame} */ + let runtimeGame; + /** @type {gdjs.TestRuntimeScene} */ + let runtimeScene; + + beforeEach(() => { + runtimeGame = gdjs.getPixiRuntimeGame(); + runtimeScene = new gdjs.TestRuntimeScene(runtimeGame); + }); + + const makeTextObjectData = (text) => ({ + name: 'Score', + type: 'TextObject::Text', + variables: [], + behaviors: [], + effects: [], + content: { + characterSize: 20, + font: '', + bold: false, + italic: false, + underlined: false, + color: '0;0;0', + text, + textAlignment: 'left', + verticalTextAlignment: 'top', + lineHeight: 0, + isOutlineEnabled: false, + outlineThickness: 0, + outlineColor: '0;0;0', + isShadowEnabled: false, + shadowColor: '0;0;0', + shadowOpacity: 127, + shadowDistance: 0, + shadowAngle: 0, + shadowBlurRadius: 0, + }, + }); + + it('keeps rotated text anchored when its content changes', () => { + const textObject = new gdjs.TextRuntimeObject( + runtimeScene, + makeTextObjectData('Score: 9') + ); + textObject.setPosition(10, 20); + textObject.setAngle(90); + textObject.updatePreRender(runtimeScene); + + const rendererObject = textObject.getRendererObject(); + expect(textObject.getCenterX()).to.be(0); + expect(textObject.getCenterY()).to.be(0); + expect(rendererObject.position.x).to.be(10); + expect(rendererObject.position.y).to.be(20); + expect(rendererObject.anchor.x).to.be(0); + expect(rendererObject.anchor.y).to.be(0); + + textObject.setText('Score: 100'); + textObject.updatePreRender(runtimeScene); + + expect(rendererObject.position.x).to.be(10); + expect(rendererObject.position.y).to.be(20); + expect(rendererObject.anchor.x).to.be(0); + expect(rendererObject.anchor.y).to.be(0); + }); +}); diff --git a/newIDE/app/scripts/import-libGD.js b/newIDE/app/scripts/import-libGD.js index 2accaaeac2f9..0ed5ce121952 100644 --- a/newIDE/app/scripts/import-libGD.js +++ b/newIDE/app/scripts/import-libGD.js @@ -66,7 +66,30 @@ if (shell.test('-f', path.join(sourceDirectory, 'libGD.js'))) { return branch; }; - // Try to download libGD.js from a specific commit on the current branch + const getCommitBranchesToTry = branch => { + const branches = []; + if (branch && branch !== 'unknown-branch') { + branches.push(branch); + } + if (branches.indexOf('master') === -1) { + branches.push('master'); + } + return branches; + }; + + const downloadCommitLibGdJsFromBranches = (branches, hash) => { + const branch = branches.shift(); + if (!branch) { + return Promise.reject(); + } + + return downloadLibGdJs( + `https://s3.amazonaws.com/gdevelop-gdevelop.js/${branch}/commit/${hash}` + ).catch(() => downloadCommitLibGdJsFromBranches(branches, hash)); + }; + + // Try to download libGD.js from a specific commit on the current branch, + // falling back to the master commit bucket for detached CI merge commits. const downloadCommitLibGdJs = (branch, gitRef) => new Promise((resolve, reject) => { shell.echo(`ℹ️ Trying to download libGD.js for ${gitRef}.`); @@ -75,8 +98,7 @@ if (shell.test('-f', path.join(sourceDirectory, 'libGD.js'))) { silent: true, }); const hash = (hashShellString.stdout || 'unknown-hash').trim(); - const branch = getBranchFromGitRef(gitRef); - if (hashShellString.stderr || hashShellString.code || !branch) { + if (hashShellString.stderr || hashShellString.code) { shell.echo( `⚠️ Can't find the hash or branch of the associated commit.` ); @@ -85,9 +107,7 @@ if (shell.test('-f', path.join(sourceDirectory, 'libGD.js'))) { } resolve( - downloadLibGdJs( - `https://s3.amazonaws.com/gdevelop-gdevelop.js/${branch}/commit/${hash}` - ) + downloadCommitLibGdJsFromBranches(getCommitBranchesToTry(branch), hash) ); }); diff --git a/newIDE/app/src/ObjectsRendering/Renderers/RenderedTextInstance.js b/newIDE/app/src/ObjectsRendering/Renderers/RenderedTextInstance.js index ac93c83f526b..2c71edb4c448 100644 --- a/newIDE/app/src/ObjectsRendering/Renderers/RenderedTextInstance.js +++ b/newIDE/app/src/ObjectsRendering/Renderers/RenderedTextInstance.js @@ -199,7 +199,9 @@ export default class RenderedTextInstance extends RenderedInstance { this._styleFontDirty = false; } - if (this._instance.hasCustomSize() && this._pixiObject.width !== 0) { + const renderedWidth = this._pixiObject.width; + const centerX = this.getCenterX(); + if (this._instance.hasCustomSize() && renderedWidth !== 0) { const alignmentX = this._textAlignment === 'right' ? 1 @@ -208,28 +210,22 @@ export default class RenderedTextInstance extends RenderedInstance { : 0; const width = this.getCustomWidth(); + const leftOffset = (width - renderedWidth) * alignmentX; - // A vector from the custom size center to the renderer center. - const centerToCenterX = - (width - this._pixiObject.width) * (alignmentX - 0.5); - - this._pixiObject.position.x = this._instance.getX() + width / 2; - this._pixiObject.anchor.x = - 0.5 - centerToCenterX / this._pixiObject.width; + this._pixiObject.position.x = this._instance.getX(); + this._pixiObject.anchor.x = (centerX - leftOffset) / renderedWidth; + } else if (renderedWidth !== 0) { + this._pixiObject.position.x = this._instance.getX(); + this._pixiObject.anchor.x = centerX / renderedWidth; } else { - this._pixiObject.position.x = - this._instance.getX() + this._pixiObject.width / 2; - this._pixiObject.anchor.x = 0.5; + this._pixiObject.position.x = this._instance.getX(); + this._pixiObject.anchor.x = 0; } - const alignmentY = - this._verticalTextAlignment === 'bottom' - ? 1 - : this._verticalTextAlignment === 'center' - ? 0.5 - : 0; - this._pixiObject.position.y = - this._instance.getY() + this._pixiObject.height * (0.5 - alignmentY); - this._pixiObject.anchor.y = 0.5; + const renderedHeight = this._pixiObject.height; + const centerY = this.getCenterY(); + this._pixiObject.position.y = this._instance.getY(); + this._pixiObject.anchor.y = + renderedHeight !== 0 ? centerY / renderedHeight : 0; this._pixiObject.rotation = RenderedInstance.toRad( this._instance.getAngle() @@ -260,4 +256,12 @@ export default class RenderedTextInstance extends RenderedInstance { ? height / 2 : 0; } + + getCenterX(): number { + return 0; + } + + getCenterY(): number { + return this.getOriginY(); + } }