From 22cb41dc29c15b54285a09fbd1f26c701ef4b048 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Fri, 16 Apr 2021 21:29:05 +0200 Subject: [PATCH 1/2] Adding the ability to display "Text" objects from Tiled I honestly don't believe text objects look good on map, and in real maps, I think text should be written on tiles. However, for a variety of use cases (like in test maps in the /maps/test directory, it can be useful to be able to display some text easily on a map. This PR adds the ability to display this text. Note: the "font" support cannot work correctly, as Tiled is listing fonts from the local system, and those fonts are not available in a browser. --- front/src/Phaser/Components/TextUtils.ts | 45 ++++++ front/src/Phaser/Game/GameScene.ts | 9 ++ front/src/Phaser/Map/ITiledMap.ts | 14 ++ maps/tests/text_object.json | 179 +++++++++++++++++++++++ 4 files changed, 247 insertions(+) create mode 100644 front/src/Phaser/Components/TextUtils.ts create mode 100644 maps/tests/text_object.json diff --git a/front/src/Phaser/Components/TextUtils.ts b/front/src/Phaser/Components/TextUtils.ts new file mode 100644 index 00000000..0161f52d --- /dev/null +++ b/front/src/Phaser/Components/TextUtils.ts @@ -0,0 +1,45 @@ +import {ITiledMapObject} from "../Map/ITiledMap"; +import Text = Phaser.GameObjects.Text; +import {GameScene} from "../Game/GameScene"; +import TextStyle = Phaser.GameObjects.TextStyle; + +export class TextUtils { + public static createTextFromITiledMapObject(scene: GameScene, object: ITiledMapObject): void { + if (object.text === undefined) { + throw new Error('This object has not textual representation.'); + } + const options: {font?: string} = {}; + let font = ''; + if (object.text.italic) { + font += 'italic '; + } + // Note: there is no support for "strikeout" and "underline" + let fontSize: number = 16; + if (object.text.pixelsize) { + font += object.text.pixelsize+'px '; + fontSize = object.text.pixelsize; + } else { + font += '16px '; + } + if (object.text.fontfamily) { + font += '"'+object.text.fontfamily+'"'; + } + if (font !== '') { + options.font = font; + } + const textElem = scene.add.text(object.x, object.y, object.text.text, options); + textElem.setFontSize(fontSize); + let color = '#000000'; + if (object.text.color !== undefined) { + color = object.text.color; + } + textElem.setColor(color); + if (object.text.wrap) { + textElem.setWordWrapWidth(textElem.width); + } + textElem.setAngle(object.rotation); + if (object.text.halign !== undefined) { + textElem.setAlign(object.text.halign); + } + } +} diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 806fc32e..464c3ca4 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -23,6 +23,7 @@ import { ITiledMapLayer, ITiledMapLayerProperty, ITiledMapObject, + ITiledText, ITiledMapTileLayer, ITiledTileSet } from "../Map/ITiledMap"; @@ -84,6 +85,7 @@ import DOMElement = Phaser.GameObjects.DOMElement; import {Subscription} from "rxjs"; import {worldFullMessageStream} from "../../Connexion/WorldFullMessageStream"; import { lazyLoadCompanionResource } from "../Companion/CompanionTexturesLoadingManager"; +import {TextUtils} from "../Components/TextUtils"; import {LayersIterator} from "../Map/LayersIterator"; import {touchScreenManager} from "../../Touch/TouchScreenManager"; import {PinchManager} from "../UserInput/PinchManager"; @@ -412,6 +414,13 @@ export class GameScene extends ResizableScene implements CenterListener { if (layer.type === 'objectgroup' && layer.name === 'floorLayer') { depth = 10000; } + if (layer.type === 'objectgroup') { + for (const object of layer.objects) { + if (object.text) { + TextUtils.createTextFromITiledMapObject(this, object); + } + } + } } if (depth === -2) { throw new Error('Your map MUST contain a layer of type "objectgroup" whose name is "floorLayer" that represents the layer characters are drawn at. This layer cannot be contained in a group.'); diff --git a/front/src/Phaser/Map/ITiledMap.ts b/front/src/Phaser/Map/ITiledMap.ts index 359b8e52..c4828911 100644 --- a/front/src/Phaser/Map/ITiledMap.ts +++ b/front/src/Phaser/Map/ITiledMap.ts @@ -136,6 +136,20 @@ export interface ITiledMapObject { * Polyline points */ polyline: {x: number, y: number}[]; + + text?: ITiledText +} + +export interface ITiledText { + text: string, + wrap?: boolean, + fontfamily?: string, + pixelsize?: number, + color?: string, + underline?: boolean, + italic?: boolean, + strikeout?: boolean, + halign?: "center"|"right"|"justify"|"left" } export interface ITiledTileSet { diff --git a/maps/tests/text_object.json b/maps/tests/text_object.json new file mode 100644 index 00000000..2c3612f0 --- /dev/null +++ b/maps/tests/text_object.json @@ -0,0 +1,179 @@ +{ "compressionlevel":-1, + "height":10, + "infinite":false, + "layers":[ + { + "data":[1, 1, 1, 1, 1, 1, 23, 23, 23, 23, 1, 1, 1, 1, 1, 1, 23, 23, 23, 23, 1, 1, 1, 1, 1, 1, 23, 23, 23, 23, 1, 1, 1, 1, 1, 1, 23, 23, 23, 23, 1, 1, 1, 1, 1, 1, 23, 23, 23, 23, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + "height":10, + "id":1, + "name":"floor", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":2, + "name":"start", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "draworder":"topdown", + "id":3, + "name":"floorLayer", + "objects":[ + { + "height":154.708861498919, + "id":1, + "name":"", + "rotation":0, + "text": + { + "color":"#ffff00", + "fontfamily":"Sans Serif", + "text":"A yellow text that wraps automatically.\n\nIt is 16px high.", + "wrap":true + }, + "type":"", + "visible":true, + "width":127.701300455634, + "x":192.052147832817, + "y":5.45414451778726 + }, + { + "height":19, + "id":3, + "name":"", + "rotation":0, + "text": + { + "text":"Default text", + "wrap":true + }, + "type":"", + "visible":true, + "width":113.494863163736, + "x":1.76065884397454, + "y":8.44497342134471 + }, + { + "height":19, + "id":5, + "name":"", + "rotation":0, + "text": + { + "text":"A very long text with no world wrap so it keeps going" + }, + "type":"", + "visible":true, + "width":349.4375, + "x":1.01295161808517, + "y":168.828173374613 + }, + { + "height":19, + "id":6, + "name":"", + "rotation":45, + "text": + { + "text":"A rotated text" + }, + "type":"", + "visible":true, + "width":117.607252906128, + "x":62.3249441410129, + "y":41.3440913604766 + }, + { + "height":48.1605818096851, + "id":7, + "name":"", + "rotation":0, + "text": + { + "fontfamily":"Sans Serif", + "italic":true, + "pixelsize":27, + "strikeout":true, + "text":"Italic 27px", + "underline":true + }, + "type":"", + "visible":true, + "width":337.807030930545, + "x":6.6207558122554, + "y":209.952070798528 + }, + { + "height":40, + "id":9, + "name":"", + "rotation":0, + "text": + { + "fontfamily":"Sans Serif", + "halign":"center", + "pixelsize":15, + "text":"This text should appear below the plant and be centered", + "wrap":true + }, + "type":"", + "visible":true, + "width":317.4375, + "x":0.78125, + "y":269.5 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + }, + { + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 78, 79, 80, 0, 0, 0, 0, 0, 0, 0, 89, 90, 91, 0, 0, 0, 0, 0, 0, 0, 100, 101, 102, 0, 0, 0, 0], + "height":10, + "id":8, + "name":"over", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }], + "nextlayerid":9, + "nextobjectid":10, + "orientation":"orthogonal", + "renderorder":"right-down", + "tiledversion":"2021.03.23", + "tileheight":32, + "tilesets":[ + { + "columns":11, + "firstgid":1, + "image":"tileset1.png", + "imageheight":352, + "imagewidth":352, + "margin":0, + "name":"tileset1", + "spacing":0, + "tilecount":121, + "tileheight":32, + "tilewidth":32 + }], + "tilewidth":32, + "type":"map", + "version":1.5, + "width":10 +} \ No newline at end of file From 08ca95b143f05d4483daecd572d7a01c8906c3ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Sat, 17 Apr 2021 18:55:39 +0200 Subject: [PATCH 2/2] Fixing WorkWrap --- front/src/Phaser/Components/TextUtils.ts | 42 ++++++++++++++---------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/front/src/Phaser/Components/TextUtils.ts b/front/src/Phaser/Components/TextUtils.ts index 0161f52d..beee840a 100644 --- a/front/src/Phaser/Components/TextUtils.ts +++ b/front/src/Phaser/Components/TextUtils.ts @@ -8,38 +8,46 @@ export class TextUtils { if (object.text === undefined) { throw new Error('This object has not textual representation.'); } - const options: {font?: string} = {}; - let font = ''; + const options: { + fontStyle?: string, + fontSize?: string, + fontFamily?: string, + color?: string, + align?: string, + wordWrap?: { + width: number, + useAdvancedWrap?: boolean + } + } = {}; if (object.text.italic) { - font += 'italic '; + options.fontStyle = 'italic'; } // Note: there is no support for "strikeout" and "underline" let fontSize: number = 16; if (object.text.pixelsize) { - font += object.text.pixelsize+'px '; fontSize = object.text.pixelsize; - } else { - font += '16px '; } + options.fontSize = fontSize + 'px'; if (object.text.fontfamily) { - font += '"'+object.text.fontfamily+'"'; + options.fontFamily = '"'+object.text.fontfamily+'"'; } - if (font !== '') { - options.font = font; - } - const textElem = scene.add.text(object.x, object.y, object.text.text, options); - textElem.setFontSize(fontSize); let color = '#000000'; if (object.text.color !== undefined) { color = object.text.color; } - textElem.setColor(color); - if (object.text.wrap) { - textElem.setWordWrapWidth(textElem.width); + options.color = color; + if (object.text.wrap === true) { + options.wordWrap = { + width: object.width, + //useAdvancedWrap: true + } } - textElem.setAngle(object.rotation); if (object.text.halign !== undefined) { - textElem.setAlign(object.text.halign); + options.align = object.text.halign; } + + console.warn(options); + const textElem = scene.add.text(object.x, object.y, object.text.text, options); + textElem.setAngle(object.rotation); } }