3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

UnityAdvent Calendar 2022

Day 18

【Unity】Timelineにテロップ用テキストデータを一括で流し込む

Last updated at Posted at 2022-12-17

課題

  • UnityのTimelineを用いたテキスト表示(字幕、テロップ、歌詞、etc..)で、大量のClipを手で打ち込む作業を効率化したい
  • 表示するテキストが変わった際に一気に読み込み直せるようにしたい

アウトプット

area_area_short.gif

アプローチ

  • カラオケ風の歌詞表示において、歌詞を一気にTimelineに流し込む機能を作る
  • StartとEndを指定して(SectionTrackで指定)、その間に等分に文字表示Clipを配置していくことで、歌詞表示のたたき台を作り、その後微調整でタイミングを修正出来るようにする

スクリーンショット 2022-12-17 22.56.31.png

歌詞テキストデータ

Area Area feat. ZORNを引用
スクリーンショット 2022-12-17 22.46.44.png

歌詞モデルクラス

using System.Collections.Generic;
using System.IO;
using UnityEngine.Assertions;

public class Lyric
{
    public class Bundle
    {
        public SectionType SectionType { get; set; }
        public List<string> LyricTexts { get; set; } = new List<string>();
    }

    public List<Bundle> LyricBundles { get; set; } = new List<Bundle>();

    public static Lyric Convert(string lyricText)
    {
        var lyric = new Lyric();
        var readingBundle = default(Bundle);
        var reader = new StringReader(lyricText);
        while (reader.Peek() > 0)
        {
            var line = reader.ReadLine();
            switch (line)
            {
                case "[Intro]":
                    readingBundle = new Bundle() { SectionType = SectionType.Intro };
                    lyric.LyricBundles.Add(readingBundle);
                    break;
                case "[Hook]":
                    readingBundle = new Bundle() { SectionType = SectionType.Hook };
                    lyric.LyricBundles.Add(readingBundle);
                    break;
                case "[Verse]":
                    readingBundle = new Bundle() { SectionType = SectionType.Verse };
                    lyric.LyricBundles.Add(readingBundle);
                    break;
                case "[Outro]":
                    readingBundle = new Bundle() { SectionType = SectionType.Outro };
                    lyric.LyricBundles.Add(readingBundle);
                    break;
                case "":
                    break;
                default:
                    Assert.IsNotNull(readingBundle);
                    readingBundle.LyricTexts.Add(line);
                    break;
            }
        }

        return lyric;
    }
}

TimelineClipへの変換処理

using System.Linq;
using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(UILyricTrack))]
public class UILyricTrackEditor : Editor
{
    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();

        if (GUILayout.Button("Import"))
        {
            var track = target as UILyricTrack;
            var sectionTrack = track.timelineAsset
                .GetOutputTracks()
                .FirstOrDefault(x => x.name == "Section");
            if (sectionTrack == null) return;
            var sectionTimelineClips = sectionTrack.GetClips();
            if (!sectionTimelineClips.Any()) return;
 
            var lyric = Lyric.Convert(track.LyricTextAsset.text);
            for (var bundleIndex = 0; bundleIndex < lyric.LyricBundles.Count; bundleIndex++)
            {
                var sectionTimelineClip = sectionTimelineClips.ElementAt(bundleIndex);
                if (sectionTimelineClip == null) continue;
                
                var sectionClip = (SectionClip)sectionTimelineClip.asset;
                var bundle = lyric.LyricBundles[bundleIndex];
                if (sectionClip.template.Type != bundle.SectionType) return;

                for (var lyricIndex = 0; lyricIndex < bundle.LyricTexts.Count; lyricIndex++)
                {
                    var clipAsset = track.CreateDefaultClip();
                    var duration = sectionTimelineClip.duration / bundle.LyricTexts.Count;
                    clipAsset.start = sectionTimelineClip.start + lyricIndex * duration;
                    clipAsset.duration = duration;
                    ((UILyricClip)clipAsset.asset).template.lyric = bundle.LyricTexts[lyricIndex];
                }
            }
        }
    }
}

まとめ

  • Clipを仮置き出来るだけでもだいぶ楽
  • HIPHOPのような、BPMが一定の音楽であれば仮置段階でも十分に歌詞表示として機能しそう
3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?