Q&A
前提
Unityで真っ黒な画面にテキストが1文字ずつ順番に表示される、オーソドックスなノベル風ゲームを作りたいと思っています。
実現したいこと
- 文章の中で強調したい文字などが出てきたら、SEやBGMを鳴らす。
- 同じく文章の中で強調したい文字などが出てきたら、文字幅が不自然にならないように文字を大きく出現させる。
例:「真ん中に栗の木が一本立っている。これは命より大事な栗だ。」
『一本』という文字が表示されたタイミングでSEを流し、『命より大事な栗』という文字だけ大きくする。
発生している問題
テキストを一度char型に分解 →
#から始めるchar情報を見つけ、for文でListに格納する →
見つけたトリガーとなる文字列を、文字数分テキストから消すfor文 →
DoTweenで文字を一文字ずつ表示するfor文。
というアプローチを行いましたが、処理している内容が分かりづらく、自分の実力ではうまく書けませんでした。
他のアプローチ方法がないか考えましたが、いいアイデアが思い浮かばず悩んでいます。
該当のソースコード
C#
1public struct TextEventStruct 2 { 3 public int StartSharpCount; 4 public int DeleteCharNum; 5 public int ResultNum; 6 public string SoundType; 7 public string SoundAddress; 8 } 9 10//トリガー文字判定処理 11private async UniTask<List<TextEventStruct>> SoundStringDecision(string text, CancellationToken token) 12 { 13 bool isFindSound = false; 14 bool isSoundAddress = false; 15 16 var charArray = text.ToCharArray(); 17 int iCount = 0; 18 int charCount = 0; 19 int quoteCount = 0; 20 21 StringBuilder typeSb = new StringBuilder(); 22 StringBuilder addressSb = new StringBuilder(); 23 List<TextEventStruct> soundDataSet = new List<TextEventStruct>(); 24 25 26 for (int i = 0; i < text.Length; i++) 27 { 28 //文字判定処理開始 29 if (charArray[i] == '#') 30 { 31 Debug.Log($"#発見, {i}"); 32 isFindSound = true; 33 iCount = i; 34 charCount++; 35 } 36 //1個目の " の判定 37 else if (charArray[i] == '"' && quoteCount == 0) 38 { 39 Debug.Log($"アドレス開始, {i}"); 40 isFindSound = false; 41 isSoundAddress = true; 42 charCount++; 43 quoteCount++; 44 } 45 //2個目の " の判定 46 else if (charArray[i] == '"' && quoteCount == 1) 47 { 48 Debug.Log($"アドレス終了, {i}"); 49 isFindSound = false; 50 isSoundAddress = false; 51 52 var type = typeSb.ToString(); 53 var address = addressSb.ToString(); 54 charCount++; 55 56 // Listに(id,type,address)を入れる 57 soundDataSet.Add(new TextEventStruct 58 { 59 StartSharpCount = iCount, 60 DeleteCharNum = charCount, 61 ResultNum = 0, 62 SoundType = type, 63 SoundAddress = address 64 }); 65 // soundStructList.Add(soundDataSet); 66 67 typeSb.Clear(); 68 addressSb.Clear(); 69 charCount = 0; 70 quoteCount = 0; 71 72 } 73 74 //命令文字取得処理 75 else if (isFindSound && !isSoundAddress) 76 { 77 typeSb.Append(text[i]); 78 charCount++; 79 } 80 81 //アドレス文字取得処理 82 else if (isSoundAddress && quoteCount == 1) 83 { 84 addressSb.Append(text[i]); 85 charCount++; 86 } 87 } 88 89//DoTweenテキスト表示処理 90private async UniTask TextScaleUpAnim(TextMeshProUGUI contentsText, List<TextEventStruct> soundStructList, CancellationToken token) 91 { 92 93 bool isComplete = false; 94 int count = 0; 95 DOTweenTMPAnimator tmproAnimator = new DOTweenTMPAnimator(contentsText); 96 97 var sequence = DOTween.Sequence(); 98 for (int i = 0; i < tmproAnimator.textInfo.characterCount; i++) 99 { 100 tmproAnimator.SetCharScale(i, Vector3.zero); 101 sequence 102 .Join(tmproAnimator.DOScaleChar(i, Vector3.one, _appearTime).SetDelay(0.1f)) 103 .Join(tmproAnimator.DOFadeChar(i, 1, _appearTime).SetDelay(0.1f)); 104 } 105 sequence 106 .AppendInterval(3) 107 .AppendCallback(() => _eventParamCount++) 108 .OnComplete(() => isComplete = true); 109 await UniTask.WaitWhile(() => !isComplete); 110 111 }
試したこと
-
Excelで入力したテキストをScriptableObjectにインポート。
-
そのstringデータをDoTweenProの機能で一文字ずつ表示させる。
-
テキストの中にあらかじめ#などのキーとなる文字を入れておき、その後に続く文字としてSEやBGMなどの種類名、次にダブルクォートで囲った中に変数(アドレス)に入れる。例:#SE"_explosion1"
-
それを構造体のListに入れ、画面に表示されるとき、Listから取り出して任意のSEを流す。
というアプローチを行うが、うまく書けなかった。
補足情報(FW/ツールのバージョンなど)
エディタ: VSCode
Unityのバージョン: 2020.3.23f1