Fade-in alpha of each individual letter successively in a RichTextLabel?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By elvisish

I’ve been trying to figure out a good way of doing this. Currently, I am just increasing the percent visible amount, but this makes the letter pop-in and I’d like them to fade quickly for a smooth look. Preferably, I’d like to be able to expand on this this and have them individually fade out start-to-end after specified amount of time too, which isn’t even possible with percentage visible (as it only works appearing from left-to-right).

Is this possible with RichTextEffects?

:bust_in_silhouette: Reply From: Yuminous

Sort of.

There is a BB Code text effect fade which will smoothly fade the alpha of your text, but it isn’t animated.

enter image description here
It’s possible to animate this with scripting (by replacing the bbcode with the start value incremented from a negative value like -10) and this would be fairly easy to do β€” but it is only rendered left-to-right and can’t fade the text from start-to-finish like you were wanting.

It’s still possible to do that with RichTextEffects but you would need to create a custom RichTextEffect. You can see the docs page for some more information on that: BBCode in RichTextLabel β€” Godot Engine (stable) documentation in English

It is quite a jump in complexity from using the existing bbcode, but once you have it coded you can simply type it like any other text [effect][/effect].

Edited Solution:

This example just uses the default fade bbcode with a script to animate the text.

var counter = -20

if text_animation == true:
	counter += 1
	if counter < 161:
		$RichTextLabel.set_bbcode("[fade start=" + str(counter) + " length=10]" + $RichTextLabel.text + "[/fade]")

To animate the fade-out transition from start-to-finish a 2nd RichTextLabel comprised of black squares β–ˆβ–ˆβ–ˆ and the same colour as the first label’s background is animated in exactly the same way but with the start β€˜counter’ value offset.

	$RichTextLabel2.set_bbcode("[fade start=" + str(counter-180) + " length=10]" + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" + "[/fade]")

Thanks! Yeah, that’s what I was looking at, but the custom RichTextEffects seem very complicated by comparison to write, and I’m having trouble figuring out where to begin with this :cry:

elvisish | 2021-07-10 08:45

Unfortunately I can’t help you out on that front because I’ve never wrote one myself.
How important is the fading from start-to-finish? Another option is that you could fade it out by modulating the entire RichTextLabel.

Yuminous | 2021-07-10 09:05

There’s a demo project which shows some of these custom effects in action here:
GitHub - Eoin-ONeill-Yokai/Godot-RichTextEffect-SampleProject: This is a test project for the new godot RichTextEffect class. It also comes with some example implementations of custom text effects. View README for details.

You might be able to tune some of the custom scripts and copy their implementation.

Yuminous | 2021-07-10 09:14

Thanks, I’ve been looking through for some ideas! The fade that’s built-in might work, but I want it per letter successively, rather than as a full block (there was an example on github that did it as a full block fade and it didn’t look quite right).

elvisish | 2021-07-10 09:27

Moved image to OP

Yuminous | 2021-07-10 09:41

Here you go. An example using only fade. It uses a second RichTextLabel of block characters β–ˆ with the same colour as the background.

Yuminous | 2021-07-10 11:41

This is useful, but the code above is not the full code. it is inside a function I guess? Doesn’t seem to be working for me so I’m guessing there’s something else there I’m missing?

robotscanplay | 2021-09-12 15:02

Yes, it’s reliant on a continuous looping function β€” _process or _physics_process.
So, in this case you should try:

var counter = -20

func _physics_process(delta):
if text_animation == true:
counter += 1
if counter < 161:
$RichTextLabel.set_bbcode("[fade start=" + str(counter) + " length=10]" + $RichTextLabel.text + "[/fade]")
$RichTextLabel2.set_bbcode("[fade start=" + str(counter-180) + " length=10]" + "β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" + "[/fade]")

But… I should say the functioning of this code is as hacky as it looks. It may not look right unless you have a font with the required characters.

I do remember with this question I was actually halfway to coding a special RichTextEffect that would be automatic and reversible, but never got around to finishing it.

Do you want to achieve this kind of reversible effect in your project too?

Yuminous | 2021-09-13 10:50

Old problem but I solved this with a RichTextEffect I called RichTextEffectFadeIn.
duration lets the fade effect go faster or slower.
fade_range defines the amount of characters you want to fade in at the same time with a gradient.
fade_factor is the gradient.

extends RichTextEffect
class_name RichTextFadeIn

var bbcode = "fade_in"
var text_index = 0
var range_tmp = 0
var new_text = true

func _init():
	resource_name = "RichTextFadeIn"

func _process_custom_fx(char_fx):
	var duration = char_fx.env.get("duration", 0.05)
	var fade_range = char_fx.env.get("fade_range", 5)
	var fade_factor = char_fx.env.get("fade_factor", 0.5)
	var elapsed_time = char_fx.elapsed_time
	if new_text and elapsed_time > duration:
		new_text = false
	elif not new_text and elapsed_time < duration:
		text_index = 0
		new_text = true
	if ((elapsed_time+duration) / (text_index + duration)) < duration:
		if char_fx.range.x in range(text_index, (text_index+fade_range)):
			var idx = char_fx.range.x - text_index + 1
			char_fx.color.a = elapsed_time / (elapsed_time * (1.0+(idx*fade_factor)))
		elif char_fx.range.x < text_index:
			char_fx.color.a = 1
			char_fx.color.a = 0
		text_index += 1
	return true

It’s not perfect, but it looks interesting at least! :slight_smile: