godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
91.53k stars 21.26k forks source link

`get_line_count()` is wrong when characters are hidden with "Characters After Shaping" behavior #99654

Open KoBeWi opened 1 week ago

KoBeWi commented 1 week ago

Tested versions

4.3 4.4 dev5

System information

Windows 10.0.19045 - Multi-window, 2 monitors - Vulkan (Forward+) - dedicated NVIDIA GeForce GTX 1060 (NVIDIA; 32.0.15.6603) - Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz (8 threads)

Issue description

I'm using RichTextLabel for my dialogue system. I rely on get_line_count() returning only lines not hidden by visible_characters.

However unfolding visible_characters does not work that well with autowrap. The word will start appearing at the end of line and then jump to the next line as it gets wrapped. It looks very jarring and many people reported this problem when playtesting my game.

The problem is that the only way to fix it is changing visible_characters_behavior from the default Characters Before Shaping to Characters After Shaping. This makes get_line_count() always return all lines, even if hidden by visible_characters.

Though while testing this, I discovered another weird thing about get_line_count() - the visible_characters interaction only works if lines end with \r. If lines end with \n, the behavior is consistent between visible_characters_behavior, i.e. it always returns all lines 🙃

Steps to reproduce

extends RichTextLabel

func _ready() -> void:
    for i in 10:
        append_text("line of text\r")

func _process(delta: float) -> void:
    visible_characters += 1
    prints(get_line_count())

Run this scripts. You will see 1, 2, 3... 10 being printed. If you change visible_characters_behavior, it will always print 10.

Minimal reproduction project (MRP)

N/A

bruvzg commented 1 week ago

However unfolding visible_characters does not work that well with autowrap. The word will start appearing at the end of line and then jump to the next line as it gets wrapped. It looks very jarring and many people reported this problem when playtesting my game.

The problem is that the only way to fix it is changing visible_characters_behavior from the default Characters Before Shaping to Characters After Shaping. This makes get_line_count() always return all lines, even if hidden by visible_characters.

These looks like expected behavior, in Characters Before Shaping mode, "hidden" lines do not exist at all, text is trimmed before processing (changing visible_characters should be equivalent of typing text in). So RTL has no idea how many line wraps there will be (\r counts as forced line wrap), but still count all paragraphs (\n is used as paragraph separator).

Not sure if it can be fully fixed, but:

bruvzg commented 1 week ago

We may also consider changing default mode to VC_CHARS_AFTER_SHAPING or VC_GLYPHS_AUTO, since it's probably more expected behavior for a lot of cases.