diff --git a/assets/text/text.csv b/assets/text/text.csv index 36ab57e..cf5e8e0 100644 --- a/assets/text/text.csv +++ b/assets/text/text.csv @@ -17,6 +17,8 @@ SETTINGS_GAME,Game SETTINGS_GAME_HEADING,"Game Configuration" SETTINGS_GAME_ACCESSIBILITY_HEADING,Accessibility SETTINGS_GAME_CAMERA_HEADING,Camera +SETTINGS_GAME_TEXT_HEADING,"In-game Text" +SETTINGS_TEXT_SPEED,"Text Display Speed" SETTINGS_SCREEN_SHAKE,"Enable Screen Shake" SETTINGS_HIT_LAG,"Enable Hit Lag Effect" SETTINGS_GAME_GAMEPLAY_HEADING,Gameplay diff --git a/project.godot b/project.godot index e047c03..84bacef 100644 --- a/project.godot +++ b/project.godot @@ -64,6 +64,7 @@ config/accessibility/enable_hit_lag=true audio/buses/override_bus_layout="user://audio_bus_layout.tres" config/gameplay/projection/detect_collision=true config/gameplay/projection/use_local_gravity=true +config/text/default_text_speed=20.0 [global_group] diff --git a/src/game/game_settings.gd b/src/game/game_settings.gd index 2116e94..2314954 100644 --- a/src/game/game_settings.gd +++ b/src/game/game_settings.gd @@ -10,12 +10,15 @@ var y_sensitivity: float var x_acceleration: float var y_acceleration: float var invert_pitch: bool + var enable_screen_shake: bool var enable_hit_lag: bool var projection_collisions: bool var projection_gravity: bool +var default_text_speed: float + func _init() -> void: ProjectSettings.settings_changed.connect(_read_settings) @@ -46,6 +49,8 @@ func _read_settings() -> void: "game/config/gameplay/projection/use_local_gravity" ) + default_text_speed = ProjectSettings.get_setting("game/config/text/default_text_speed") + func _load_audio_bus_override() -> void: # Load override audio bus file diff --git a/src/ui/decorations/text_effects/typewriter/typewriter_effect.gd b/src/ui/decorations/text_effects/typewriter/typewriter_effect.gd new file mode 100644 index 0000000..4c876db --- /dev/null +++ b/src/ui/decorations/text_effects/typewriter/typewriter_effect.gd @@ -0,0 +1,40 @@ +@tool +class_name TypewriterEffect +extends RichTextEffect +## BBCode effect which procedurally shows the text character by character, from start to end. +## Tag params: +## - speed - Speed at which text is displayed, in characters per second. +## - delay - Delay before displaying first character, in seconds. + +signal typing +signal on_frame_process_start + +# To use this effect: +# - Enable BBCode on a RichTextLabel. +# - Instead of instantiating this effect directly, use a `TypewriterLabel` node. +# - Use [type speed=10.0 delay=0.0]hello[/type] in text. +var bbcode: String = "type" + +var _force_visible := false + + +func _init(force_visible_signal: Signal) -> void: + if force_visible_signal: + force_visible_signal.connect(_set_force_visible) + + +func _process_custom_fx(char_fx: CharFXTransform) -> bool: + if not _force_visible: + var speed: float = char_fx.env.get("speed", Game.settings.default_text_speed) + var delay: float = char_fx.env.get("delay", 0.0) + + char_fx.visible = (char_fx.elapsed_time - delay) * speed >= char_fx.relative_index + + if not char_fx.visible: + typing.emit() + + return true + + +func _set_force_visible() -> void: + _force_visible = true diff --git a/src/ui/decorations/text_effects/typewriter/typewriter_label.gd b/src/ui/decorations/text_effects/typewriter/typewriter_label.gd new file mode 100644 index 0000000..3490b50 --- /dev/null +++ b/src/ui/decorations/text_effects/typewriter/typewriter_label.gd @@ -0,0 +1,53 @@ +class_name TypewriterLabel extends RichTextLabel +## RichTextLabel with a managed typewriter effect. +## Allows for signal-based monitoring of a typewriter effect's status. +## In most cases you'll want to use this rather than instantiating TypewriterEffect yourself. +## Use `display_text` to set the text for this label. + +## Emitted on the first frame that all characters in the typewriter effect are visible. +signal typing_finished + +## Emit this to force the typewriter effect to finish on the next update. +## Useful for advancing skippable dialogue boxes. +signal force_visible + +var _finished: bool = true +var _typing: bool = false + + +func _init() -> void: + bbcode_enabled = true + var effect := TypewriterEffect.new(force_visible) + effect.typing.connect(_on_typing) + install_effect(effect) + + +## Is the typewriter effect finished? +func is_finished() -> bool: + return _finished + + +## Reset the manager's progress monitor. +## This is called automatically when setting the label text with `set_text` +func reset() -> void: + _finished = false + + +## Clear the text box and set a new line of text. +## The `finished` signal will be emitted when the text is done displaying. +func display_text(text: String) -> void: + reset() + clear() + append_text(text) + + +func _process(_delta: float) -> void: + if not _finished: + if not _typing: + _finished = true + typing_finished.emit() + _typing = false + + +func _on_typing() -> void: + _typing = true diff --git a/src/ui/menus/settings_menu/settings_menu.tscn b/src/ui/menus/settings_menu/settings_menu.tscn index 4f8a0ae..75e7e2a 100644 --- a/src/ui/menus/settings_menu/settings_menu.tscn +++ b/src/ui/menus/settings_menu/settings_menu.tscn @@ -106,6 +106,28 @@ key = &"game/config/gameplay/projection/use_local_gravity" [node name="SettingLabel" parent="TabContainer/SETTINGS_GAME/VBoxContainer/ScrollContainer/MarginContainer/SettingsList/ProjectionGravity" index="1"] text = "SETTINGS_PROJECTION_GRAVITY" +[node name="TextHeading" type="HBoxContainer" parent="TabContainer/SETTINGS_GAME/VBoxContainer/ScrollContainer/MarginContainer/SettingsList"] +layout_mode = 2 + +[node name="Label" type="Label" parent="TabContainer/SETTINGS_GAME/VBoxContainer/ScrollContainer/MarginContainer/SettingsList/TextHeading"] +layout_mode = 2 +theme_type_variation = &"HeaderMedium" +text = "SETTINGS_GAME_TEXT_HEADING" + +[node name="HSeparator" type="HSeparator" parent="TabContainer/SETTINGS_GAME/VBoxContainer/ScrollContainer/MarginContainer/SettingsList/TextHeading"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="TextSpeed" parent="TabContainer/SETTINGS_GAME/VBoxContainer/ScrollContainer/MarginContainer/SettingsList" groups=["Settings"] instance=ExtResource("3_jox8e")] +layout_mode = 2 +key = &"game/config/text/default_text_speed" + +[node name="SettingLabel" parent="TabContainer/SETTINGS_GAME/VBoxContainer/ScrollContainer/MarginContainer/SettingsList/TextSpeed" index="1"] +text = "SETTINGS_TEXT_SPEED" + +[node name="SpinBox" parent="TabContainer/SETTINGS_GAME/VBoxContainer/ScrollContainer/MarginContainer/SettingsList/TextSpeed/PanelContainer/MarginContainer/NumericSlider" index="1"] +suffix = "char/s" + [node name="CameraHeading" type="HBoxContainer" parent="TabContainer/SETTINGS_GAME/VBoxContainer/ScrollContainer/MarginContainer/SettingsList"] layout_mode = 2 @@ -492,6 +514,8 @@ text = "UI_ACCEPT" [editable path="TabContainer/SETTINGS_GAME/VBoxContainer/ScrollContainer/MarginContainer/SettingsList/HitLag"] [editable path="TabContainer/SETTINGS_GAME/VBoxContainer/ScrollContainer/MarginContainer/SettingsList/ProjectionCollision"] [editable path="TabContainer/SETTINGS_GAME/VBoxContainer/ScrollContainer/MarginContainer/SettingsList/ProjectionGravity"] +[editable path="TabContainer/SETTINGS_GAME/VBoxContainer/ScrollContainer/MarginContainer/SettingsList/TextSpeed"] +[editable path="TabContainer/SETTINGS_GAME/VBoxContainer/ScrollContainer/MarginContainer/SettingsList/TextSpeed/PanelContainer/MarginContainer/NumericSlider"] [editable path="TabContainer/SETTINGS_GAME/VBoxContainer/ScrollContainer/MarginContainer/SettingsList/FreeCameraSpeed"] [editable path="TabContainer/SETTINGS_GAME/VBoxContainer/ScrollContainer/MarginContainer/SettingsList/FreeCameraSpeed/PanelContainer/MarginContainer/NumericSlider"] [editable path="TabContainer/SETTINGS_GAME/VBoxContainer/ScrollContainer/MarginContainer/SettingsList/SensitivityX"]