By default, the typewriter runs at a constant characters/second speed specified by the typewriter effect's Characters Per Second value. If you're using the AudioWait() sequencer command to play audio with each line and need to vary the typewriter speed to match the audio length, you can use an OnConversationLine() method to change it. Something like:
void OnConversationLine(Subtitle subtitle)
{
// Regex might be more concise, but this is a simple way to get the audio clip name:
var audioWaitPos = subtitle.sequence.IndexOf("AudioWait(");
if (audioWaitPos == -1) return; // No audio.
var audioWaitEndPos = subtitle.sequence.Indexof(")", audioWaitPos);
var clipNamePos = audioWaitPos + "AudioWait(".Length;
var clipNameLength = audioWaitEndPos - clipNamePos;
var audioClipName = subtitle.sequence.Substring(clipNamePos, clipNameLength);
var audioClip = DialogueManager.LoadAsset(audioClipName, typeof(AudioClip));
// Determine which subtitle panel we'll use:
DialogueActor dialogueActor;
var panel = DialogueManager.standardDialogueUI.conversationUIElements.standardSubtitleControls.GetPanel(subtitle, out dialogueActor);
// Set the subtitle panel's typewriter speed:
var numChars = subtitle.formattedText.text.Length; // (See note below.)
panel.GetTypewriter().charactersPerSecond = numChars / audioClip.length;
}
Notes:
Doesn't account for RPG Maker-style speed codes in text or rich text/TextMesh Pro tags.
Doesn't account for using Addressables with async loading; tries to load audio clip immediately.
Thank you so much for sharing this useful piece of code. As someone who is still navigating and learning, I find it somewhat challenging to implement directly. Could you possibly break it down into more detailed, step-by-step instructions? It would be incredibly helpful.
I just wanted to update - I've managed to figure it out by using AI.
I created an individual script and attached this script to the Dialogue Manager, then it worked perfectly!
The AI detected some issues and fixed them, so I want to share the new code here. Here’s what the script looks like:
using UnityEngine;
using PixelCrushers.DialogueSystem;
public class TypewriterAdjuster : MonoBehaviour
{
void OnConversationLine(Subtitle subtitle)
{
// Regex might be more concise, but this is a simple way to get the audio clip name:
var audioWaitPos = subtitle.sequence.IndexOf("AudioWait(");
if (audioWaitPos == -1) return; // No audio.
var audioWaitEndPos = subtitle.sequence.IndexOf(")", audioWaitPos);
var clipNamePos = audioWaitPos + "AudioWait(".Length;
var clipNameLength = audioWaitEndPos - clipNamePos;
var audioClipName = subtitle.sequence.Substring(clipNamePos, clipNameLength);
// Load the audio clip and cast it to AudioClip.
var audioClip = (AudioClip)DialogueManager.LoadAsset(audioClipName, typeof(AudioClip));
if (audioClip == null) return; // If no audio clip found, return.
// Determine which subtitle panel we'll use:
DialogueActor dialogueActor;
var panel = DialogueManager.standardDialogueUI.conversationUIElements.standardSubtitleControls.GetPanel(subtitle, out dialogueActor);
// Set the subtitle panel's typewriter speed:
var numChars = subtitle.formattedText.text.Length;
panel.GetTypewriter().charactersPerSecond = numChars / audioClip.length;
}
}