[READ-ONLY] Mirror of https://github.com/excaliburjs/Excalibur. 🎮 Your friendly TypeScript 2D game engine for the web 🗡️ excaliburjs.com
excalibur excaliburjs game-development game-engine game-framework gamedev games html5-canvas typescript
2

Configure Feed

Select the types of activity you want to include in your feed.

fix: [#3060] SpriteFont measureText with scale (#3062)

Closes #3060

## Changes:

- Adds sandbox test with repro
- Updates spritefont to include scale

authored by

Erik Onarheim and committed by
GitHub
(May 14, 2024, 10:47 PM -0500) 5dcff5db 29fef3b1

+178 -8
+29 -7
CHANGELOG.md
··· 7 7 8 8 ### Breaking Changes 9 9 10 - - `ex.Action` now requires a unique `id` property 10 + - 11 11 12 12 ### Deprecated 13 13 ··· 18 18 ### Added 19 19 20 20 - `actor.oldGlobalPos` returns the globalPosition from the previous frame 21 - - Built in actions now have a unique `id` property 22 21 - create development builds of excalibur that bundlers can use in dev mode 23 22 - show warning in development when Entity hasn't been added to a scene after a few seconds 23 + 24 + ### Fixed 25 + 26 + - Fixed issue where `ex.SpriteFont` did not respect scale when measuring text 27 + 28 + ### Updates 29 + 30 + - 31 + 32 + ### Changed 33 + 34 + 35 + <!--------------------------------- DO NOT EDIT BELOW THIS LINE ---------------------------------> 36 + <!--------------------------------- DO NOT EDIT BELOW THIS LINE ---------------------------------> 37 + <!--------------------------------- DO NOT EDIT BELOW THIS LINE ---------------------------------> 38 + 39 + ## [v0.29.3] 40 + 41 + ### Breaking Changes 42 + 43 + - `ex.Action` now requires a unique `id` property 44 + 45 + ### Deprecated 46 + 47 + ### Added 48 + 49 + - Built in actions now have a unique `id` property 24 50 25 51 ### Fixed 26 52 ··· 33 59 34 60 ### Changed 35 61 36 - - `ex.Vector.toAngle()` now returns angles from [0 - 2 PI) 37 - 38 - <!--------------------------------- DO NOT EDIT BELOW THIS LINE ---------------------------------> 39 - <!--------------------------------- DO NOT EDIT BELOW THIS LINE ---------------------------------> 40 - <!--------------------------------- DO NOT EDIT BELOW THIS LINE ---------------------------------> 62 + - `ex.Vector.toAngle()` now returns angles from `[0 - 2 PI)` 41 63 42 64 ## [v0.29.2] 43 65
+39
src/spec/TextSpec.ts
··· 921 921 await expectAsync(canvasElement).toEqualImage('src/spec/images/GraphicsTextSpec/spritefont-text.png'); 922 922 }); 923 923 924 + it('can scale a spritefont', async () => { 925 + const spriteFontImage = new ex.ImageSource('src/spec/images/GraphicsTextSpec/spritefont.png'); 926 + 927 + await spriteFontImage.load(); 928 + 929 + const spriteFontSheet = ex.SpriteSheet.fromImageSource({ 930 + image: spriteFontImage, 931 + grid: { 932 + rows: 3, 933 + columns: 16, 934 + spriteWidth: 16, 935 + spriteHeight: 16 936 + } 937 + }); 938 + 939 + const spriteFont = new ex.SpriteFont({ 940 + alphabet: '0123456789abcdefghijklmnopqrstuvwxyz,!\'&."?- ', 941 + caseInsensitive: true, 942 + spacing: -5, 943 + spriteSheet: spriteFontSheet, 944 + scale: ex.vec(3, 3) 945 + }); 946 + 947 + const sut = new ex.Text({ 948 + text: 'Some Sprite Text!?', 949 + font: spriteFont 950 + }); 951 + 952 + const canvasElement = document.createElement('canvas'); 953 + canvasElement.width = 200; 954 + canvasElement.height = 100; 955 + const ctx = new ex.ExcaliburGraphicsContext2DCanvas({ canvasElement }); 956 + 957 + ctx.clear(); 958 + sut.draw(ctx, 0, 50); 959 + expect(spriteFont.measureText('some test')).toEqual(ex.BoundingBox.fromDimension((16 - 5) * 9 * 3, 16 * 3, ex.vec(0, 0))); 960 + await expectAsync(canvasElement).toEqualImage('src/spec/images/GraphicsTextSpec/spritefont-scaled.png'); 961 + }); 962 + 924 963 it('can have a custom lineHeight', async () => { 925 964 const spriteFontImage = new ex.ImageSource('src/spec/images/GraphicsTextSpec/spritefont.png'); 926 965
sandbox/tests/spritefont-measuring/font.png

This is a binary file and will not be displayed.

+13
sandbox/tests/spritefont-measuring/index.html
··· 1 + <!doctype html> 2 + <html lang="en"> 3 + <head> 4 + <meta charset="UTF-8" /> 5 + <meta http-equiv="X-UA-Compatible" content="IE=edge" /> 6 + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 7 + <title>Sprite Font Rendering</title> 8 + </head> 9 + <body> 10 + <script src="../../lib/excalibur.js"></script> 11 + <script src="index.js"></script> 12 + </body> 13 + </html>
+46
sandbox/tests/spritefont-measuring/index.ts
··· 1 + class TestFontMeasuringScene extends ex.Scene { 2 + font1: ex.SpriteFont; 3 + font2: ex.SpriteFont; 4 + async onInitialize(game: ex.Engine) { 5 + super.onInitialize(game); 6 + let loader = new ex.DefaultLoader(); 7 + let fontImage = new ex.ImageSource('font.png'); 8 + loader.addResource(fontImage); 9 + await game.start(loader); 10 + 11 + let fontSpriteSheet = ex.SpriteSheet.fromImageSource({ 12 + image: fontImage, 13 + grid: { columns: 1, rows: 45, spriteWidth: 10, spriteHeight: 10 } 14 + }); 15 + 16 + this.font1 = this.createFont(fontSpriteSheet); 17 + this.font2 = this.createFont(fontSpriteSheet); 18 + this.font2.scale = ex.vec(2, 2); 19 + } 20 + 21 + createFont(spriteSheet: ex.SpriteSheet) { 22 + return new ex.SpriteFont({ 23 + alphabet: '01234567890.- ©][ABCDEFGHIJKLMNOPQRSTUVWXYZ|/', 24 + caseInsensitive: true, 25 + spriteSheet 26 + }); 27 + } 28 + onActivate(ctx: ex.SceneActivationContext) { 29 + const text = 'brown fox jumps over the lazy dog'; 30 + let m1 = this.font1.measureText(text); 31 + console.log('font 1', m1.dimensions); //330,10, OK 32 + let m2 = this.font2.measureText(text); 33 + console.log('font 2', m2.dimensions); //330,10, should be 660,20 34 + } 35 + } 36 + 37 + var engineSpriteFont = new ex.Engine({ 38 + width: 600, 39 + height: 600, 40 + pixelArt: true, 41 + scenes: { 42 + start: TestFontMeasuringScene 43 + } 44 + }); 45 + 46 + engineSpriteFont.start('start');
sandbox/tests/spritefont-rendering/font.png

This is a binary file and will not be displayed.

+13
sandbox/tests/spritefont-rendering/index.html
··· 1 + <!doctype html> 2 + <html lang="en"> 3 + <head> 4 + <meta charset="UTF-8" /> 5 + <meta http-equiv="X-UA-Compatible" content="IE=edge" /> 6 + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 7 + <title>Sprite Font Rendering</title> 8 + </head> 9 + <body> 10 + <script src="../../lib/excalibur.js"></script> 11 + <script src="index.js"></script> 12 + </body> 13 + </html>
+37
sandbox/tests/spritefont-rendering/index.ts
··· 1 + class TestFontScene extends ex.Scene { 2 + async onInitialize(game: ex.Engine) { 3 + super.onInitialize(game); 4 + let loader = new ex.DefaultLoader(); 5 + let fontImage = new ex.ImageSource('./font.png'); 6 + loader.addResource(fontImage); 7 + await game.start(loader); 8 + let fontSpriteSheet = ex.SpriteSheet.fromImageSource({ 9 + image: fontImage, 10 + grid: { columns: 1, rows: 45, spriteWidth: 10, spriteHeight: 10 } 11 + }); 12 + let font = new ex.SpriteFont({ 13 + alphabet: '01234567890.- ©][ABCDEFGHIJKLMNOPQRSTUVWXYZ|/', 14 + caseInsensitive: true, 15 + spriteSheet: fontSpriteSheet, 16 + scale: ex.vec(4, 4) 17 + }); 18 + let lbl = new ex.Label({ 19 + pos: ex.vec(10, 10), 20 + anchor: ex.vec(0, 0), 21 + text: '-brown fox jumps \nover the lazy dog', 22 + spriteFont: font 23 + }); 24 + this.add(lbl); 25 + } 26 + } 27 + 28 + var engineSpriteFont = new ex.Engine({ 29 + width: 600, 30 + height: 600, 31 + pixelArt: true, 32 + scenes: { 33 + start: TestFontScene 34 + } 35 + }); 36 + 37 + engineSpriteFont.start('start');
+1 -1
src/engine/Graphics/SpriteFont.ts
··· 99 99 width += sprite.width + this.spacing; 100 100 height = Math.max(height, sprite.height); 101 101 } 102 - return BoundingBox.fromDimension(width, height * lines.length, Vector.Zero); 102 + return BoundingBox.fromDimension(width * this.scale.x, height * lines.length * this.scale.y, Vector.Zero); 103 103 } 104 104 105 105 protected _drawImage(ex: ExcaliburGraphicsContext, x: number, y: number, maxWidth?: number): void {
src/spec/images/GraphicsTextSpec/spritefont-scaled.png

This is a binary file and will not be displayed.