Skip to main content

Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines

That text animation is beautiful! Need to look into how to do that.

I kept pressing the wrench button but it would only sometimes let me throw things, not sure why? I also got trapped by the box on the second level.

Love the art! And some great puzzle ideas in here


(+1)

Thanks!   You'll want to start by looking into "CharFXTransform" in the Godot documentation.   The "visible" boolean is what you want to play with.  For the fade out part, just make it wait for the fade in process to finish before starting and repeat the logic except change opacity from 100 to 0, so the same thing but in reverse visually... To make it wiggle, you can actually offset each individual character with [var].offset = Vector2(X, Y), but you want to make sure you make X and Y something like X = sin(something)* amplitude and Y = sin(something)* amplitude.   or cos.  Basically you leverage that sin/cos is a wave, and multiply it by how wiggly you want it to be.   Create this in a standalone .gd, give it a classname, be sure to include a declared variable called "bbcode" = "[sickradeffect]" then you can call your sick rad effect into code attached to dialogue box if and only if you wrap text in the inspector like this.   "[sickradeffect]SICKRADEFFECTEXAMPLE[/sickradeffect]"    That way sickradeffect only applies if and only if you wrap text in this.  You're essentially adding something custom along side the ability to write out text like this "[b]THIS WOULD BE BOLD[/b]".


This is the way to do it to save yourself from typing it out over and over again in whatever project.   Even cooler, you can create a permanent, personal library of text effects that to include in any project from the get go.   If you haven't written anything like that yet, once you do, congrats, you've crafted your first personalized boilerplate code.  Ideally each text effect that you design should be in a seperate .gd file, and should have a unique bbcode to prevent conflicts.   In your dialogue box code include something like "text_label.custom_effects = [sickradeffect.new(), sickradeffect2.new(),...etc]",.         "custom_effects" is a pre-existing array designed for you to fill it with....custom effects in the manner described here.  And then make sure to @onready your label.   I hope that helps!   

(+1)

Actually, I went ahead and had a conversation with some AI so it could output a super generic guide to probably better explain what I'm talking about, in full, and in order, and with descriptive variables wrapped in square brackets.  I was just steam of consciousness typing my last reply.   😅    This should *actually* help you do this.  I read it over and I think it's right.


1. class_name — making a script globally available

When you put class_name [YourEffectName] at the top of a GDScript file, Godot registers it project-wide. Every other script can use [YourEffectName] by name with no import needed.

class_name [YourEffectName] extends RichTextEffect # Now any script in the project can write: # [YourEffectName].new()

Without class_name you'd have to use load("res://[path/to/your/file].gd").new() every time. class_name skips all of that.

2. RichTextEffect — what it is and how Godot uses it

Godot's RichTextLabel node has a built-in system for per-character visual effects. You plug in any number of effects and Godot calls them automatically every frame for every character.

To create one, extend RichTextEffect and implement one function:

extends RichTextEffect  var bbcode = "[your_tag]"   # the tag this effect listens for  func _process_custom_fx(char_fx: CharFXTransform) -> bool:     # Godot calls this every frame for every character inside [[your_tag]]...[[/your_tag]]     # char_fx gives you: index, color, offset, and more     # whatever you do here IS what appears on screen     return true

3. The bbcode variable — which characters get the effect

The bbcode variable tells Godot which tag to listen for. If you set it to "[your_tag]", only characters wrapped in [[your_tag]]...[[/your_tag]] get processed.

# In your effect script: var bbcode = "[your_tag]"  # In your label text: label.text = "Normal text [[your_tag]]this gets the effect[[/your_tag]] normal again"

Setting bbcode = "" applies the effect to all characters with no tag needed. Built-in tags like [b], [color], [i] are unaffected — they run independently and stack fine.

4. custom_effects — registering effects on a label

custom_effects is a built-in array on every RichTextLabel. It ships empty. You fill it with instances of your effects and Godot runs all of them every frame.

# In [YourDialogueScript] or wherever you control the label: @onready var [your_label_variable]: RichTextLabel = $[YourPanelNode]/[YourLabelNode]  func _ready() -> void:     [your_label_variable].custom_effects = [         [YourFirstEffect].new(),         [YourSecondEffect].new(),         [YourThirdEffect].new()     ]

All registered effects are active. Which ones actually do anything depends on whether the text contains their BBCode tag.

5. @onready — safely referencing child nodes

Node references can only be resolved once the scene tree is ready. @onready delays the assignment until that moment automatically.

# This is shorthand for assigning in _ready(): @onready var [your_label_variable]: RichTextLabel = $[YourPanelNode]/[YourLabelNode]  # It's exactly equivalent to writing: var [your_label_variable]: RichTextLabel func _ready() -> void:     [your_label_variable] = $[YourPanelNode]/[YourLabelNode]

The variable name ([your_label_variable]) is your choice. The node path ($[YourPanelNode]/[YourLabelNode]) must match the actual scene tree structure.

6. Combining multiple effects

Because each effect has its own BBCode tag, you can stack them freely on the same text:

[your_label_variable].text = "[[first_tag]][[second_tag]]both effects here[[/second_tag]] only first here[[/first_tag]]"

Godot runs each registered effect on each character. A character inside both tags gets both effects applied.

One file per effect is the right structure. Don't try to bundle multiple effects into one file — you can only declare one bbcode variable per class, and GDScript only allows one class_name per file.

7. The full plug-and-play setup

1

Create effect files — one per effect, each with class_name [YourEffectName], var bbcode = "[your_tag]", and _process_custom_fx().

2

Register them in [YourDialogueScript] — add all effects to [your_label_variable].custom_effects in _ready().

3

Use tags in text — wrap any text in [[your_tag]]..[[/your_tag]] and the effect runs automatically.

4

Adding a new effect — create the file, add one line to custom_effects. Nothing else needs to change.

8. What "boilerplate" means here

Boilerplate is reusable code that solves a general problem with no project-specific logic in it. A well-written [YourEffectName] qualifies — it knows nothing about your game, just how to transform characters visually. Drop it into any Godot project and it works.

A dialogue box script is boilerplate at its core (entry cycling, timing, dismiss fade) but often has project-specific parts on top (portrait modes, character-specific flags). Strip those out and the skeleton becomes reusable too.