I'm making a game on Godot in GDScript. I've got "abilities" in my game, a lot of them, really a lot of them. I might end up putting their description in XMLs or something else and even the rest of their info on it, and they might be "keywords" to simplify some explanations or recurrent mechanics.
So the question is: Can you detect mouseover (or other mouse interactions too) over specifics texts/words in a RichTextLabel
, maybe thanks to some BBCode? Or maybe as said before there some text node more practical (even if I doubt it)?
From what I've seen, the RichTextLabel is the only to support text modifications and just "text difference" from the rest of the node, so might be the most able to, even if maybe very far, cuz of his ability to handle BBCode, but if what I'm thinking right now is the only solutions...
That would be to detect where certain BBCode balises in (X,Y) coordinates to place a "mouseover detect box" on those keywords, meaning you need to get (X,Y) coordinates of words in a paragraph, which isn't easily handled neither, you would need to calculate size of each character to calculate the position (X,Y) of a simple word... So yeah sound astoundingly hard to do.
Using RichTextLabel
is the easier approach here.
As you know, it works with BBCode. Now, there are to ways to populate it:
You can set the text
property with bbcode_enabled
enabled and it will parse it. See BBCode in RichTextLabel.
For example, this will be "hello" written in red:
var label:RichTextLabel = $RichTextLabel
label.text = "[color=red]hello[/color]"
If you don't want to set it, but to append it, it is more efficient to use append_text
(this way Godot does not have to parse the whole text, but only the new part):
var label:RichTextLabel = $RichTextLabel
label.append_text("[color=red]hello[/color]")
Or you can do it by token...
Setting the BBCode by tokens works like an stack machine. You push (open) tags, append text, and pop (close) tags.
For example, this will be "hello" written in red:
var label:RichTextLabel = $RichTextLabel
label.push_color(Color.RED)
label.add_text("hello")
label.pop()
Note: The clear
method does nor clear the text, instead it pops (closes) all currently pushed (open) tags.
Now, there is a particular tag that will allow you to do what you want.
text
use "[url=something]text[/url]"
.push_meta("something")
.This will kind of create an "hyperlink". More precisely, it makes an item indented to be interacted with, inside of which text will be formatted - by default - similar to an hyperlink in a browser.
You, of course, are in control of the formatting. You might want to set meta_underlined
to false
to disable the default underline.
What we are interested is the interactive part. While the tag does nothing by default, that is the point: we will define what it does. To do that, we need to handle some signals from the RichTextLabel
:
meta_hover_started
: When the mouse pointer begins hovering over the contents of one of the "hyperlink"s.meta_hover_ended
: When the mouse pointer stops hovering over the contents of one of the "hyperlink"s.meta_clicked
: When the use clicks one of the "hyperlink"s.And how do you know which "hyperlink"?
Well, these signals pass a value ("something"
in the examples above), which comes from the tag:
push_meta
you pass the value you want from the signals as an argument.Here push_meta
has an advantage over using text: the "url" attribute will only ever be an String
, but the parameter of push_meta
is a Variant, you can pass anything there, including a reference to an Object
, or a Dictionary
with multiple values.
The methods you connect to those signals would look something like this:
func _on_meta_clicked(meta):
prints(meta)
Refer to Using Signals to see how to make the connection.