Defold-RichText

Wouldn’t it be great to be able to change the font of a flowing text or the colour of a word? This and more is now possible thanks to the Defold-RichText project!

With Defold-RichText it’s possible to turn this:

"<size=3>RichText</size>Lorem <color=0,0.5,0,1>ipsum </color>dolor <color=red>sit </color><color=#ff00ffff>amet, </color><size=1.15><font=Nanum>consectetur </font></size>adipiscing elit. <b>Nunc </b>tincidunt <b><i>mattis</i> libero</b> <i>non viverra</i>.\n\nNullam ornare accumsan rhoncus.\n\nNunc placerat nibh a purus auctor, id scelerisque massa rutrum."

Into this:

NOTE: There’s still some performance improvements to make, specifically around grouping multiple words with the same style into a single text node. Also still left to do is to apply layers to generated text nodes to reduce draw calls.

30 Likes

I was actually going to make a post saying how great the new label system is (or, releatively new… i don’t know when it was introduced). I will have a look at this next time.

5 Likes

This is really awesome! Cool work! I think I’ll use this for our game and I have a few PR ideas already:

  1. It would be cool if you could use something like <tag=my_tag>some text</tag> to tag some nodes with a tag and the function would return you a table with just the tagged nodes for each tag, so you could apply custom stuff like text shake on parts of the text.
  2. It would be great if the function would return the total width/height of the text. I’ll need this for my game as my text tends to reside in 9-slice dialog bubbles.
  3. Vertical / horizontal align.
1 Like

That’s a good idea.https://github.com/britzl/defold-richtext/issues/2

Hmm, how would the vertical align work?

Another useful thing would be to pass the text blob through a helper function, ignore the tags in length (but still return them properly), and use a counter to return text up to the number of characters in the counter. So dialogs can easily have properly styled text but appearing one character after another.

This could also be extended to produce per character effects like

34626819-0c96f898-f213-11e7-8fbc-6cb48926a123

8 Likes

so you could apply custom stuff like text shake on parts of the text

This would be awesome. Text shake is one of the things that I really enjoy about a game I have been playing recently - Celeste. It’s funny how much better a text shake/wave is at conveying emotion compared to the conventional boldness.

giphy

Oh and then there is the infamously funky JJ2 menu screen. :smiley:

giphy2

6 Likes

For horizontal align, you would subtract 0, line_width / 2, line_width from the X coord of all node positions of each line for left, center, right align respectively.

For vertical align you would add 0, total_block_height / 2, total_block_height to the Y coord of all node positions for bottom, middle, top align respectively.

Unfortunately you can’t do anything that’s not bottom left align in one single pass, as node positions depend on the metrics of all the other nodes, but it’s doable in two passes.

1 Like

Yup, got it. Horizontally center each line.

This is for aligning within each line right? In the case where you have different sized elements?

Fixed in Defold-RichText 1.4.0. richtext.create() now returns both nodes table and metrics table

5 Likes

No. I mean aligning the whole block of text relative to the origin of the container. Similar to how the North/Center/South pivots work for normal labels.

Ah, ok. If you pass in a parent node that the text nodes will be childed to then it should be trivial to vertically align the parent based on height of the entire text to achieve what you want.

Fair enough. You’d have an extra parent node to manage, though. I guess implementing this in the library vs letting the user implement this is just a matter of usage convenience vs separation of concerns.

Released 2.0.0 with support for getting tagged text (and custom nodes). Get all words with a <b> tag:

local words, metrics = richtext.create(...)
local bold_words = richtext.tagged(words, "b")
for _,bold_word in pairs(bold_words) do
	print(bold_word.text, bold_word.node)
end

And you can use custom tags as well:

local text = "Lorem ipsum dolor sit amet, <foo>consectetur adipiscing elit</foo>. Aliquam vehicula purus sit amet orci molestie vulputate."
local words, metrics = richtext.create(text, ...)
local foo_words = richtext.tagged(words, "foo")
for _,word in pairs(foo_words) do
	print(word.text, word.node)
end
6 Likes

I think this would be very useful for chat applications as well.

Any chance it can support smileys/images which can be inserted within the text?

1 Like

Yes, already planned: https://github.com/britzl/defold-richtext/issues/4

5 Likes

Added support for images in 2.1.0:

<img=texture:image></img>

Example:

"<size=3>RichText</size>Lorem <color=0,0.5,0,1>ipsum </color><img=smileys:zombie></img> dolor <color=red>sit </color><color=#ff00ffff>amet, </color><size=1.15><font=Nanum>consectetur </font></size>adipiscing elit. <b>Nunc </b>tincidunt <b><i>mattis</i> libero</b> <i>non viverra</i>.\n\nNullam ornare <img=smileys:hungry></img>accumsan rhoncus.\n\nNunc placerat nibh a purus auctor, id scelerisque massa <size=2>rutrum.</size>"

Result:

9 Likes

Empty tags are now supported:

<img=texture:image/>
<br/>
3 Likes

Nice job!!
Can the tags have multiple properties? like HTML? E.g. <img src='#joystick' anim='wiggle'/>

1 Like

I guess it should be possible to specify a flipbook anim from the atlas as “image” part in “texture:image”.

1 Like

Correct. <img=smileys:happy/> does this:

gui.set_texture(node, texture)
gui.play_flipbook(node, image)
4 Likes