Hello! First time using this forum, so I’m probably going to sound stupid. I’m also new to Godot and programming as a whole, so that adds onto it.
For the music selector in my project, I’m trying to use a RichTextLabel to display the name of the song, and have it automatically scroll to fit the full name of the track and have it loop back to the beginning. Something akin to a news crawl.
I tried checking around for any similar topics that use RichTextLabel nodes, but couldn’t really find any, only one for a regular Label node, which required it to be a child to a Control node.
If anyone has any ideas on how a script for this might work, I’d love to hear cuz that would rock. Thank you!
Any solution that would work with a Label mode would also work for a RichTextLabel node with a few adjustments.
Anyway mrcdk’s solution would work, but I would also suggest having the name of the song twice in the label so there’s not a gap between the start and end of the text. Also, I don’t think a ScrollContainer will scroll past the end of the label if there’s no blank space there.
I’ve thought about doing this, but it’s low on my priority list. If I were going to scroll, I’d try to do it by character, basically pulling each character off the front after it disappears and appending it to the end. The suggestion @paintsimmon had of making it appear twice is a good idea, just in case your text is too short.
yeah that also works, though it might not be as smooth as scrolling the scrollcontainer.
To make the marquee loop seamless, you should warp the scroll ratio or value back to the start when the second instance of the text reaches the position the first instance would be at the start. This creates the illusion of scrolling forever, like that infinite staircase in super mario 64 that speedrunners backwards long jump past
Yeah, duplicating the label and wrapping the scroll to the beginning when the scroll value reaches the size of the Label does the trick. It seamlessly scrolls forever.
Ok, I played around with what @mrcdk, @paintsimmon and @wchc posted. It’s almost perfect - until you start using BBCode. So I tweaked it a little, and made it work with my Sound plugin.
## Scrolls the title, artist (if available), and album (if available) of a song
## played using [member Music.play]. It uses the [RichTextLabel] child node
## if found, and otherwise creates one at runtime.
class_name MusicMarqueeHScrollContainer extends ScrollContainer
## The color to use for song titles.
@export var title_color: Color = Color.MAGENTA
## The color to use for artist names.
@export var artist_color: Color = Color.CORNFLOWER_BLUE
## The color to use for album names.
@export var album_color: Color = Color.GREEN
var rich_text_label: RichTextLabel
func _ready() -> void:
horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_SHOW_NEVER
vertical_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
for node in get_children():
if node is RichTextLabel:
rich_text_label = node
if not rich_text_label:
rich_text_label = RichTextLabel.new()
add_child(rich_text_label)
rich_text_label.autowrap_mode = TextServer.AUTOWRAP_OFF
rich_text_label.scroll_active = false
rich_text_label.fit_content = true
rich_text_label.bbcode_enabled = true
Music.song_started.connect(_on_song_started)
Music.song_stopped.connect(_on_song_stopped)
func _process(_delta: float) -> void:
scroll_horizontal += 1
if scroll_horizontal >= rich_text_label.size.x - size.x:
scroll_horizontal = 0
func _on_song_started() -> void:
rich_text_label.text = Music.get_current_song().get_song_info_as_bbcode(title_color, artist_color, album_color)
rich_text_label.text = rich_text_label.text.lpad(rich_text_label.text.length() + int(size.x / 4))
rich_text_label.text = rich_text_label.text.rpad(rich_text_label.text.length() + int(size.x / 4))
scroll_horizontal = 0
func _on_song_stopped() -> void:
rich_text_label.text = ""
This will create a MusicMarqueeHScrollContainer node you can add to your project like any normal Node. (Minus the fancy icon.)
If you don’t want to use that, you just need to create your own Signals for when the song starts and stops, and another way to get the song information.
You can use something like this to get the title:
var title: String
if stream is AudioStreamOggVorbis or stream is AudioStreamWAV:
var tags: Dictionary = stream.get_tags()
if tags.has("title"):
title = tags["title"]
if title.is_empty():
title = stream.resource_path.get_file().to_snake_case().trim_suffix(".ogg").trim_suffix(".wav").capitalize()