本日のおすすめです。
大好物です!
一文字ずつ表示することができるよ
だしまきたまごの続編です!
おまたせしました。おまたせしすぎたかもしれません。
基本はだしまきと同じです
追加のコードを書くことによって、
メッセージの表示スピードを変えることできるよ
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class StoryManager : MonoBehaviour
{
[SerializeField] private StoryData[] storyDatas;
[SerializeField] private Image background;
[SerializeField] private Image characterImage;
[SerializeField] private TextMeshProUGUI storyText;
[SerializeField] private TextMeshProUGUI characterName;
[Header("===== テキスト演出設定 =====")]
[SerializeField, Range(0.01f, 0.2f)]
private float typingSpeed = 0.05f;
[Header("===== 効果音設定 =====")]
[SerializeField] private AudioClip typingSE;
[SerializeField] private AudioClip nextSE;
[SerializeField, Range(0f, 1f)]
private float seVolume = 0.7f;
public int storyIndex { get; private set; } = 0;
public int textIndex { get; private set; } = 0;
private bool isTyping = false;
private string currentFullText = "";
private Coroutine typingCoroutine = null;
private AudioSource audioSource;
private bool storyEnded = false;
private void Start()
{
audioSource = GetComponent<AudioSource>();
if (audioSource == null)
{
audioSource = gameObject.AddComponent<AudioSource>();
audioSource.playOnAwake = false;
}
if (storyDatas == null || storyDatas.Length == 0)
{
Debug.LogError("storyDatasが空!");
return;
}
SetStoryElement(storyIndex, textIndex);
}
private void Update()
{
if (Input.GetMouseButtonDown(0) || Input.GetKeyDown(KeyCode.Space))
{
if (storyEnded)
{
Debug.Log("ストーリーは既に終了しています。");
return;
}
if (isTyping)
{
if (typingCoroutine != null) StopCoroutine(typingCoroutine);
storyText.maxVisibleCharacters = currentFullText.Length;
isTyping = false;
PlayNextSE();
}
else
{
Next();
}
}
}
public void Next()
{
if (storyEnded || storyIndex >= storyDatas.Length)
{
Debug.Log("ストーリーは既に終了しています。");
return;
}
PlayNextSE();
textIndex++;
if (textIndex >= storyDatas[storyIndex].stories.Count)
{
textIndex = 0;
storyIndex++;
if (storyIndex >= storyDatas.Length)
{
storyEnded = true;
Debug.Log("全てのストーリーが終了しました。");
return;
}
}
SetStoryElement(storyIndex, textIndex);
}
private void SetStoryElement(int _storyIndex, int _textIndex)
{
var currentStoryData = storyDatas[_storyIndex];
var storyElement = currentStoryData.stories[_textIndex];
background.sprite = storyElement.Background;
characterImage.sprite = storyElement.CharacterImage;
characterName.text = storyElement.CharacterName;
currentFullText = storyElement.StoryText;
if (typingCoroutine != null) StopCoroutine(typingCoroutine);
storyText.text = currentFullText;
storyText.maxVisibleCharacters = 0;
isTyping = true;
typingCoroutine = StartCoroutine(TypeText());
}
private IEnumerator TypeText()
{
int total = currentFullText.Length;
isTyping = true;
for (int i = 0; i <= total; i++)
{
storyText.maxVisibleCharacters = i;
if (i < total && !char.IsWhiteSpace(currentFullText[i]) && typingSE != null)
{
audioSource.PlayOneShot(typingSE, seVolume);
}
yield return new WaitForSeconds(typingSpeed);
}
isTyping = false;
typingCoroutine = null;
}
private void PlayNextSE()
{
if (nextSE != null)
audioSource.PlayOneShot(nextSE, seVolume);
}
}なが~~~~~いです
ほぼ150行。
だしまきで掲載済みのもの、だいたい同じ意味のものはカットします。
こっちコピペすればおけ
Collections.Generic;using System.Collections.Generic;同じような処理をいろんな型で使い回しできるようにしてくれる!
コードを少なく書けるようにしてくれる!
テキスト演出の設定
[Header("===== テキスト演出設定 =====")]
[SerializeField, Range(0.01f, 0.2f)]
private float typingSpeed = 0.05f;typingSpeedタイピングスピード
インスペクターから設定できるようになる
0.01~0.2の間(Range)で設定できるよ
0.05f=1秒に20文字くらいで標準なスピード
効果音の設定
[Header("===== 効果音設定 =====")]
[SerializeField] private AudioClip typingSE; // タイピング音
[SerializeField] private AudioClip nextSE; // 次の文に進むときの音
[SerializeField, Range(0f, 1f)]
private float seVolume = 0.7f;AudioClipオーディオクリップ
音のかたまりで、音を鳴らすことに必要
float seVolume全体の効果音の大きさを調節できるようになるよ
private bool isTyping = false; // 今タイピング中?
private string currentFullText = ""; // 表示予定の全文(一時保存)
private Coroutine typingCoroutine = null; // タイピング中の一時中止
private AudioSource audioSource; // 再生中に効果音を調整してくれるAudio Sourceオーディオクリップを読み込んで
再生・停止・音量調整ができるようになる
private bool isTyping = false;
private string currentFullText = "";
private Coroutine typingCoroutine = null;
private AudioSource audioSource;
private bool storyEnded = false;bool isTypingprivate bool isTyping = false;今タイピング進行中か判定してくれる
これでタイピングが終わってから
次に勧めるようになるように制御してくれる
string currentFullText = "";いま表示しようとしている全文を一時的に保存
文字を一文字表示するための元データ
typingCoroutineCoroutine typingCoroutine = null;いま表示しているところのタイピング音の一時停止
nullでいまタイピングしていない状態
AudioSource audioSource;効果音を再生するのに必要
これを使ってタイピング音と次にいくときの音をだす
bool storyEndedbool storyEnded = false;
ストーリーが全て完了したかどうか確認する
なくなったら終わるための処理をする
audioSource = GetComponent<AudioSource>();
if (audioSource == null)
{
audioSource = gameObject.AddComponent<AudioSource>();
audioSource.playOnAwake = false;AudioSourceオーディオソースが同じゲームオブジェクトにあるか探してくれる
なかったら自動的に追加してくれて、
playOnAwake = false(シーンが始まる時に音がならなくなる)ように
設定してくれる
スクリプトが音声再生用の準備を完了させてくれる
if (isTyping)
{
if (typingCoroutine != null) StopCoroutine(typingCoroutine);
storyText.maxVisibleCharacters = currentFullText.Length;
isTyping = false;
PlayNextSE();
}
else
{
Next();
}タイピング中のとき(isTyping == true)
一文字ずつ表示していたtypingCoroutine を強制的に終わらせる
storyText.maxVisibleCharacters = currentFullText.Le ngth;
良いやつのテキストを使って一度に全文を出してくれる
isTyping = false;
もうタイピングが終わったよって更新してくれる
PlayNextSE();
スキップしたよの効果音を鳴らしてくれる
こんかいのおさらい
using System.Collections; //C#で型を決めたリストを作る
using System.Collections.Generic; //同じ処理を使い回せるようにするよ
using TMPro; //いいテキストを使うよ
using UnityEngine; //標準のC#を使うよ
using UnityEngine.UI; //標準で基本のC#を使うよ
public class StoryManager : MonoBehaviour //StoryManagerの初期スクリプトを使うよ
{
[SerializeField] private StoryData[] storyDatas; //ストーリーデータのスクリプト
[SerializeField] private Image background; //背景
[SerializeField] private Image characterImage; //キャラの立ち絵
[SerializeField] private TextMeshProUGUI storyText; //ストーリーのテキスト
[SerializeField] private TextMeshProUGUI characterName; //キャラの名前
[Header("===== テキスト演出設定 =====")]
[SerializeField, Range(0.01f, 0.2f)] //0.01fから0.2fの間で設定できるよ
private float typingSpeed = 0.05f; //0.05fで設定してるよ
[Header("===== 効果音設定 =====")]
[SerializeField] private AudioClip typingSE; //タイピング音
[SerializeField] private AudioClip nextSE; //次に進むときの音
[SerializeField, Range(0f, 1f)] //0fから1fの間で設定できるよ
private float seVolume = 0.7f; //0.7fで設定してるよ
public int storyIndex { get; private set; } = 0; //storyIndexを誰でも設定変更できるよ
public int textIndex { get; private set; } = 0; //textIndexを誰でも設定変更できるよ
private bool isTyping = false; //タイピング進行中か判定してくれる
private string currentFullText = ""; //いま表示しようとしている全文を一時的に保存してくれる
private Coroutine typingCoroutine = null; //いま表示しようとしているところのタイピング音の一時停止
private AudioSource audioSource; //効果音を再生するのに必要
private bool storyEnded = false; //ストーリーが終わったか確認してくれる 終わったら終わるための処理に入る
private void Start() //すたーと!
{
audioSource = GetComponent<AudioSource>(); //同じゲームオブジェクトに音があるか確認してくれる
if (audioSource == null) //音がなかったら自動的に音をつけてくれる
{
audioSource = gameObject.AddComponent<AudioSource>(); //音を追加してほしいよ~
audioSource.playOnAwake = false; //音が鳴らないようにしてくれる
}
if (storyDatas == null || storyDatas.Length == 0)
{ //ストーリーデータがないときに挙動がおかしくならないようにしてくれる
Debug.LogError("storyDatasが空!");
return;
} //ストーリーデータがないときにインスペクターで設定してねって教えてくれる
SetStoryElement(storyIndex, textIndex); //どこの処理をしているか教えてくれる
}
private void Update() //更新!
{
if (Input.GetMouseButtonDown(0) || Input.GetKeyDown(KeyCode.Space))
{ //左クリックかスペースキーを押されたときを検知してくれる
if (storyEnded) //このストーリーが終わったかどうかのチェックと分岐
{
Debug.Log("ストーリーは既に終了しています。"); //その時に終わっていることを教えてくれる
return;
}
if (isTyping) //タイピング中のとき
{
if (typingCoroutine != null) StopCoroutine(typingCoroutine); //タイピングを終わらせる
storyText.maxVisibleCharacters = currentFullText.Length; //全文表示
isTyping = false; //タイピングの終わりを更新してくれる
PlayNextSE(); //スキップしたよの効果音
}
else //まだ途中だよ
{
Next(); //つぎ!
}
}
}
public void Next() //つぎを始める!
{
if (storyEnded || storyIndex >= storyDatas.Length) // 全部見たか判定してくれる
{
Debug.Log("ストーリーは既に終了しています。"); //終わったか教えてくれる
return;
}
PlayNextSE(); //つぎへの効果音を鳴らすよ
textIndex++; //つぎのテキストを表示するよ
if (textIndex >= storyDatas[storyIndex].stories.Count) //全部見たか判定してくれる
{
textIndex = 0; //いまのテキスト表示が終わったよ
storyIndex++; //いまのストーリーが終わったからつぎに進む準備をするよ
if (storyIndex >= storyDatas.Length) //全部見たか教えてくれる
{
storyEnded = true; //ストーリーが終わったことを確認したら終わる準備に入る
Debug.Log("全てのストーリーが終了しました。"); //終わったら教えてくれる
return;
}
}
SetStoryElement(storyIndex, textIndex);
} //指定した位置を画面に全部反映してくれる、やっと動ける
private void SetStoryElement(int _storyIndex, int _textIndex)
{ //セリフ変わったりキャラが変わるよ
var currentStoryData = storyDatas[_storyIndex]; //いま処理しているところを編集できるようにしてくれる
var storyElement = currentStoryData.stories[_textIndex]; //いま表示するべきものを取り出して表示するとこに入れてるよ
background.sprite = storyElement.Background;
characterImage.sprite = storyElement.CharacterImage;
characterName.text = storyElement.CharacterName; //いま表示するべきものを反映してくれる
currentFullText = storyElement.StoryText; //いま表示する全文を保存してくれてる
if (typingCoroutine != null) StopCoroutine(typingCoroutine); //タイピングを終わらせてくれる
storyText.text = currentFullText; //ストーリーテキストを全文セットしてくれる
storyText.maxVisibleCharacters = 0; //何文字まで表示するかを非表示
isTyping = true; //いまタイピング中だよ
typingCoroutine = StartCoroutine(TypeText()); //一文字ずつ表示して音をだすループに入る
}
private IEnumerator TypeText() //タイピングテキストをできるように待機中
{
int total = currentFullText.Length; //全文の文字数を取得するよ
isTyping = true; //いまタイピング中を確認
for (int i = 0; i <= total; i++) //全表示終わりをループ
{
storyText.maxVisibleCharacters = i; //何文字まで出すかを指定できる
if (i < total && !char.IsWhiteSpace(currentFullText[i]) && typingSE != null)
{ //文字と効果音を設定している場合だけ
audioSource.PlayOneShot(typingSE, seVolume);
} //タイピング音を鳴らしてくれる 文字や効果音がないときは鳴らさない
yield return new WaitForSeconds(typingSpeed); //つぎの文字まで待機するよ
}
isTyping = false; //タイピング終わり
typingCoroutine = null; //再開をさせないで終了判定してくれる
}
private void PlayNextSE() //つぎへの効果音
{
if (nextSE != null) //つぎのテキストにいくとき一度だけ
audioSource.PlayOneShot(nextSE, seVolume); //つぎへ進む効果音の音量調整
}
}なが~~~いけど、書いてることはちょーシンプルです
さばのみぞれ煮ってすごい美味しくてだいすき
週に1回は食べたい
いただきます🌟



