Unity練習3
unity練習2の続きとなっています.練習1と直接の関連性はありません.
引き続きこちらの記事を参考にしていきます.
文字の表示
文字を表示するスクリプトを作成してみる.Projectタブ内のAssets/Scriptsを選択し,次の手順を行う.
(右クリック)→[create]→[C# script]
そして作成されたものの名前を"GameManager"に変更する.すると画面は次のようになっている.
次に,今作成した"GameManager"をダブルクリックしてスクリプト開く.(筆者はVScodeで開くように設定してある.)そしてスクリプトの内容を次のように書き換える.
using UnityEngine;
using UnityEngine.UI;
// MonoBehaviourを継承することでオブジェクトにコンポーネントとして
// アタッチすることができるようになる
public class GameManager : MonoBehaviour{
// SerializeFieldと書くとprivateなパラメーターでも
// インスペクター上で値を変更できる
[SerializeField]
private Text mainText;
[SerializeField]
private Text nameText;
private string _text = "Hello,World!";
// MonoBehaviourを継承している場合限定で
// 最初の更新関数(Updateメソッド)が呼ばれる時に最初に呼ばれる
private void Start(){
// Main Textに指定したTextコンポーネントの
// テキストのパラメーターに代入する
mainText.text = _text;
}
}
ここでは,C#の文法的なことは割愛する.Javaなどの言語に触れたことがあれば何となくわかるかもしれない.
コードの解説はコメント分に記述されている.
書き換えた後はunityエディタに戻り,Inapectorタブ上で"GameManager"が変更されていることを確認する.次の図ではひとつ前の図を比べて変更が適用されていることが分かる.
その次に,Hierarchyタブ上の"GameManager"をクリックし,Inspectorタブ上に"GameManager"の情報を表示させる.そして,先ほど変更したProjectタブ内の"GameManager"をInspector上のAdd Componentの下にドラッグ&ドロップする.すると画面は次のようになる.
次に,GameManager(Script)のMain TextとName Textを変更する.このMainTextやNameTextというのはスクリプト上で
private Text mainText
のように定義されており,例えばnameTextのところを
private Text aaaText;
のように変更するとInspecotrタブ上では次のようになる.
閑話休題,今試しに変更した部分をnameTextに戻して先の話をする.MainTextとNameTextのNone(Text)となっている部分をそれぞれ,Maintext(Text),NameText(Text)に変更する.右にある白丸のところをクリックするとNoneかMainTextかNameTextを選択できる.すると次のようになる.
ここで,実行ボタンを押すと次のような画面になる.
赤い三角は上下にずっと動いている(「Unity練習2」の記事を参照).
"Hello, World!"という表示は次のコードからきている.
private string _text = "Hello,World!";
private void Start(){
mainText.text = _text;
}
最初の文でstring型の_textという変数を宣言して,
"Hello, World!"という内容で初期化している.その変数をmainText.Textに代入しているのでこのような表示となっている.
名前の表示
コードを見れば分かるが,現状ではMainTextの変更しか行っていない.そこで次は名前(細い四角)の部分を変更していく.
Projectタブ内の"GameManager"スクリプトで,GameManagerクラスの中を,次のもの加えつつ適当に変更する.
// パラメーターを追加
private const char SEPARATE_MAIN_START = '「';
private const char SEPARATE_MAIN_END = '」';
// パラメーターを変更
private string _text = "ともり「Hello,World!」";
// メソッドを変更
private void Start()
{
ReadLine(_text);
}
/**
* 1行を読み出す
*/
private void ReadLine(string text)
{
// '「'の位置で文字列を分ける
string[] ts = text.Split(SEPARATE_MAIN_START);
// 分けたときの最初の値、つまり"ともり"が代入される
string name = ts[0];
// 分けたときの次の値、つまり"Hello,World!」"が代入されるので
// 最後の閉じ括弧を削除して代入(="Hello,World!")
string main = ts[1].Remove(ts[1].LastIndexOf(SEPARATE_MAIN_END));
nameText.text = name;
mainText.text = main;
}
コードに慣れておらず,加え方が分からない人のために,加えた後の"GameManager.cs"の本文を次に載せる.
using UnityEngine;
using UnityEngine.UI;
// MonoBehaviourを継承することでオブジェクトにコンポーネントとして
// アタッチすることができるようになる
public class GameManager : MonoBehaviour{
// SerializeFieldと書くとprivateなパラメーターでも
// インスペクター上で値を変更できる
[SerializeField]
private Text mainText;
[SerializeField]
private Text nameText;
// パラメーターを追加
private const char SEPARATE_MAIN_START = '「';
private const char SEPARATE_MAIN_END = '」';
// パラメーターを変更
private string _text = "ともり「Hello,World!」";
// メソッドを変更
private void Start(){
ReadLine(_text);
}
/*
* 1行を読み出す
*/
private void ReadLine(string text){
// '「'の位置で文字列を分ける
string[] ts = text.Split(SEPARATE_MAIN_START);
// 分けたときの最初の値、つまり"ともり"が代入される
string name = ts[0];
// 分けたときの次の値、つまり"Hello,World!」"が代入されるので
// 最後の閉じ括弧を削除して代入(="Hello,World!")
string main = ts[1].Remove(ts[1].LastIndexOf(SEPARATE_MAIN_END));
nameText.text = name;
mainText.text = main;
}
}
GameManagerクラスの変更点を簡単に記す.
1.
加えるコードの中に
private string _text = "みにに「Hello,World!」";
が存在し,これは修正前にも
private string _text = "Hello,World!";
として宣言と初期化されている.同一の変数を二回宣言することは出来ないので,修正前からある方を削除する.
2.
加えるコードの中に
private void Start(){
ReadLine(_text);
}
が存在し,これは変更前にも次の同名関数が存在する.
private void Start(){
mainText.text = _text;
}
関数も変数同様,同名のものを二回宣言することは出来ないので,修正前からある方を削除する.
3.
あとはGameManagerクラス内に,追加するコードをそのまま張り付ければよい.
これで実行すると次のようになる.
文字を一文字ずつ表示
現状では,文字が一斉に表示されるので,一文字ずつ表示されるように変更してみる.
まず,最初は一文字だけ表示させる.次のコードをGamaManagerクラスにうまく入れることを考える.
// スクリプトの最初に記述
using System.Collections.Generic;
// パラメーターを追加
private Queue<char> _charQueue;
// メソッドを追加
/**
* 文を1文字ごとに区切り、キューに格納したものを返す
*/
private Queue<char> SeparateString(string str)
{
// 文字列をchar型の配列にする = 1文字ごとに区切る
char[] chars = str.ToCharArray();
Queue<char> charQueue = new Queue<char>();
// foreach文で配列charsに格納された文字を全て取り出し
// キューに加える
foreach (char c in chars) charQueue.Enqueue(c);
return charQueue;
}
/**
* 1文字を出力する
*/
private void OutputChar()
{
// キューから値を取り出し、キュー内からは削除する
mainText.text += _charQueue.Dequeue();
}
// メソッドを変更
private void ReadLine(string text)
{
string[] ts = text.Split('「');
string name = ts[0];
string main = ts[1].Remove(ts[1].LastIndexOf('」'));
nameText.text = name;
mainText.text = "";
_charQueue = SeparateString(main);
}
private void Start()
{
ReadLine(_text);
OutputChar();
}
修正した"GameManager.cs"は次のようになる.
using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
// MonoBehaviourを継承することでオブジェクトにコンポーネントとして
// アタッチすることができるようになる
public class GameManager : MonoBehaviour{
// SerializeFieldと書くとprivateなパラメーターでも
// インスペクター上で値を変更できる
[SerializeField]
private Text mainText;
[SerializeField]
private Text nameText;
// パラメーターを追加
private const char SEPARATE_MAIN_START = '「';
private const char SEPARATE_MAIN_END = '」';
private Queue<char> _charQueue;
// パラメーターを変更
private string _text = "ともり「Hello,World!」";
// メソッドを追加
/**
* 文を1文字ごとに区切り、キューに格納したものを返す
*/
private Queue<char> SeparateString(string str){
// 文字列をchar型の配列にする = 1文字ごとに区切る
char[] chars = str.ToCharArray();
Queue<char> charQueue = new Queue<char>();
// foreach文で配列charsに格納された文字を全て取り出し
// キューに加える
foreach (char c in chars) charQueue.Enqueue(c);
return charQueue;
}
/*1文字を出力する*/
private void OutputChar(){
// キューから値を取り出し、キュー内からは削除する
mainText.text += _charQueue.Dequeue();
}
// メソッドを変更
private void ReadLine(string text){
string[] ts = text.Split('「');
string name = ts[0];
string main = ts[1].Remove(ts[1].LastIndexOf('」'));
nameText.text = name;
mainText.text = "";
_charQueue = SeparateString(main);
}
private void Start(){
ReadLine(_text);
OutputChar();
}
}
そして,この状態で実行すると次のようになる.
これに待ち時間を付けて全文を表示させる.
"GameManager.cs"を以下のように変更する.
using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
using System.Collections;
// MonoBehaviourを継承することでオブジェクトにコンポーネントとして
// アタッチすることができるようになる
public class GameManager : MonoBehaviour{
// SerializeFieldと書くとprivateなパラメーターでも
// インスペクター上で値を変更できる
[SerializeField]
private Text mainText;
[SerializeField]
private Text nameText;
[SerializeField]
private float captionSpeed = 0.2f;
// パラメーターを追加
private const char SEPARATE_MAIN_START = '「';
private const char SEPARATE_MAIN_END = '」';
private Queue<char> _charQueue;
private string _text = "ともり「Hello,World!」";
/**
* 文を1文字ごとに区切り、キューに格納したものを返す
*/
private Queue<char> SeparateString(string str){
// 文字列をchar型の配列にする = 1文字ごとに区切る
char[] chars = str.ToCharArray();
Queue<char> charQueue = new Queue<char>();
// foreach文で配列charsに格納された文字を全て取り出し
// キューに加える
foreach (char c in chars) charQueue.Enqueue(c);
return charQueue;
}
private bool OutputChar(){
// キューに何も格納されていなければfalseを返す
if (_charQueue.Count <= 0) return false;
mainText.text += _charQueue.Dequeue();
return true;
}
/**
* 文字送りするコルーチン
*/
private IEnumerator ShowChars(float wait){
// OutputCharメソッドがfalseを返す(=キューが空になる)までループする
while (OutputChar())
// wait秒だけ待機
yield return new WaitForSeconds(wait);
// コルーチンを抜け出す
yield break;
}
private void Start(){
ReadLine(_text);
}
private void ReadLine(string text){
string[] ts = text.Split(SEPARATE_MAIN_START);
string name = ts[0];
string main = ts[1].Remove(ts[1].LastIndexOf(SEPARATE_MAIN_END));
nameText.text = name;
mainText.text = "";
_charQueue = SeparateString(main);
// コルーチンを呼び出す
StartCoroutine(ShowChars(captionSpeed));
}
}
これで文字を時間差で表示することができる.文字送りのスピードを変えるときUnityエディタのInspector上でCaption Speedを変更する.もしくはスクリプトの次の部分を変更する.
[SerializeField]
private float captionSpeed = 0.2f;
ここではコードの内容を見ていく.
private Queue<char> SeparateString(string str){
// 文字列をchar型の配列にする = 1文字ごとに区切る
char[] chars = str.ToCharArray();
Queue<char> charQueue = new Queue<char>();
// foreach文で配列charsに格納された文字を全て取り出し
// キューに加える
foreach (char c in chars) charQueue.Enqueue(c);
return charQueue;
}
ToCharArrayはstring型のものをchar型の配列に変換する.ここでは引数のstring型strをchar型配列のcharsに変換している.
次にchar型のQueueを作り,foreachですべての要素を先頭から順番に格納している.foreachはfor文で先頭から繰り返していくのと等価である.そして返り値として作成したQueueを返す.
private bool OutputChar(){
// キューに何も格納されていなければfalseを返す
if (_charQueue.Count <= 0) return false;
mainText.text += _charQueue.Dequeue();
return true;
}
_charQueue.Dequeue()はQueueの先頭にあるオブジェクトを返して削除するので,ここでmainTextに文字を加えていく.
// 文字送りするコルーチン
private IEnumerator ShowChars(float wait){
// OutputCharメソッドがfalseを返す(=キューが空になる)までループする
while (OutputChar())
// wait秒だけ待機
yield return new WaitForSeconds(wait);
// コルーチンを抜け出す
yield break;
}
このメソッドはコメントアウトで解説しきっているので,yield breakの説明をしているサイトを載せるだけとします.
private void ReadLine(string text){
string[] ts = text.Split(SEPARATE_MAIN_START);
string name = ts[0];
string main = ts[1].Remove(ts[1].LastIndexOf(SEPARATE_MAIN_END));
nameText.text = name;
mainText.text = "";
_charQueue = SeparateString(main);
// コルーチンを呼び出す
StartCoroutine(ShowChars(captionSpeed));
}
string[] ts = text.Split(SEPARATE_MAIN_START);で."「"を基準にして,この前をts[0]に,後をts[1]に格納し,それぞれをname, mainに格納している.このとき,ts[1]には"」"も入ってしまっているので,ts[1].Remove(ts[1].LastIndexOf(SEPARATE_MAIN_END));で除いてから格納する.
StartCoroutineは,(処理)→(一定時間待機)の繰り返しを一つの関数で行えるものである.詳細な説明は次のサイトにまかせる.
クリックで全文表示
次は,クリックされたら文字送りを待たずに全文が表示されるようにする."GamaManager.cs"を次のように変更する.
using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
using System.Collections;
// MonoBehaviourを継承することでオブジェクトにコンポーネントとして
// アタッチすることができるようになる
public class GameManager : MonoBehaviour{
// SerializeFieldと書くとprivateなパラメーターでも
// インスペクター上で値を変更できる
[SerializeField]
private Text mainText;
[SerializeField]
private Text nameText;
[SerializeField]
private float captionSpeed = 0.2f;
// パラメーターを追加
private const char SEPARATE_MAIN_START = '「';
private const char SEPARATE_MAIN_END = '」';
private Queue<char> _charQueue;
private string _text = "ともり「Hello,World!」";
/**
* 文を1文字ごとに区切り、キューに格納したものを返す
*/
private Queue<char> SeparateString(string str){
// 文字列をchar型の配列にする = 1文字ごとに区切る
char[] chars = str.ToCharArray();
Queue<char> charQueue = new Queue<char>();
// foreach文で配列charsに格納された文字を全て取り出し
// キューに加える
foreach (char c in chars) charQueue.Enqueue(c);
return charQueue;
}
private bool OutputChar(){
// キューに何も格納されていなければfalseを返す
if (_charQueue.Count <= 0) return false;
mainText.text += _charQueue.Dequeue();
return true;
}
// 文字送りするコルーチン
private IEnumerator ShowChars(float wait){
// OutputCharメソッドがfalseを返す(=キューが空になる)までループする
while (OutputChar())
// wait秒だけ待機
yield return new WaitForSeconds(wait);
// コルーチンを抜け出す
yield break;
}
private void Start(){
ReadLine(_text);
}
private void ReadLine(string text){
string[] ts = text.Split(SEPARATE_MAIN_START);
string name = ts[0];
string main = ts[1].Remove(ts[1].LastIndexOf(SEPARATE_MAIN_END));
nameText.text = name;
mainText.text = "";
_charQueue = SeparateString(main);
// コルーチンを呼び出す
StartCoroutine(ShowChars(captionSpeed));
}
//全文表示
private void OutputAllChar(){
// コルーチンをストップ
StopCoroutine(ShowChars(captionSpeed));
// キューが空になるまで表示
while (OutputChar()) ;
}
//クリックしたときの処理
private void OnClick(){
OutputAllChar();
}
// MonoBehaviourを継承しているとき,毎フレーム呼ばれる
private void Update(){
// 左(=0)クリックされたらOnClickメソッドを呼び出し
if (Input.GetMouseButtonDown(0)) OnClick();
}
}
実行して左クリックをしてみると,全文が一気に表示されるはずである.ちなみに
Input.GetMouseButtonDown(0):左クリック
Input.GetMouseButtonDown(1):右クリック
Input.GetMouseButtonDown(2):中クリック
を表す.
他にもクリックされた判定はいくつかの種類がある.それが載っているサイトを以下に示す.
次のページを表示
全文が表示されているときにクリックされると次のページが表示されるようにする.
"GameManager.cs"を次のように変更する.
using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
using System.Collections;
// MonoBehaviourを継承することでオブジェクトにコンポーネントとして
// アタッチすることができるようになる
public class GameManager : MonoBehaviour{
// SerializeFieldと書くとprivateなパラメーターでも
// インスペクター上で値を変更できる
[SerializeField]
private Text mainText;
[SerializeField]
private Text nameText;
[SerializeField]
private float captionSpeed = 0.2f;
// パラメーターを追加
private const char SEPARATE_MAIN_START = '「';
private const char SEPARATE_MAIN_END = '」';
private Queue<char> _charQueue;
private const char SEPARATE_PAGE = '&';
private Queue<string> _pageQueue;
private string _text = "ともり「トーキョーは 薄暗い閃光放って」&ともり 「消耗した MPも回復できぬまま」";
/**
* 文を1文字ごとに区切り、キューに格納したものを返す
*/
private Queue<char> SeparateString(string str){
// 文字列をchar型の配列にする = 1文字ごとに区切る
char[] chars = str.ToCharArray();
Queue<char> charQueue = new Queue<char>();
// foreach文で配列charsに格納された文字を全て取り出し
// キューに加える
foreach (char c in chars) charQueue.Enqueue(c);
return charQueue;
}
private bool OutputChar(){
// キューに何も格納されていなければfalseを返す
if (_charQueue.Count <= 0) return false;
mainText.text += _charQueue.Dequeue();
return true;
}
// 文字送りするコルーチン
private IEnumerator ShowChars(float wait){
// OutputCharメソッドがfalseを返す(=キューが空になる)までループする
while (OutputChar())
// wait秒だけ待機
yield return new WaitForSeconds(wait);
// コルーチンを抜け出す
yield break;
}
private void ReadLine(string text){
string[] ts = text.Split(SEPARATE_MAIN_START);
string name = ts[0];
string main = ts[1].Remove(ts[1].LastIndexOf(SEPARATE_MAIN_END));
nameText.text = name;
mainText.text = "";
_charQueue = SeparateString(main);
// コルーチンを呼び出す
StartCoroutine(ShowChars(captionSpeed));
}
//全文表示
private void OutputAllChar(){
// コルーチンをストップ
StopCoroutine(ShowChars(captionSpeed));
// キューが空になるまで表示
while (OutputChar()) ;
}
// MonoBehaviourを継承しているとき,毎フレーム呼ばれる
private void Update(){
// 左(=0)クリックされたらOnClickメソッドを呼び出し
if (Input.GetMouseButtonDown(0)) OnClick();
}
//文字列を指定した区切り文字毎に区切り,キューに格納したものを返す
private Queue<string> SeparateString(string str, char sep){
string[] strs = str.Split(sep);
Queue<string> queue = new Queue<string>();
foreach (string l in strs) queue.Enqueue(l);
return queue;
}
//初期化
private void Init(){
_pageQueue = SeparateString(_text, SEPARATE_PAGE);
ShowNextPage();
}
//次のページの表示
private bool ShowNextPage(){
if (_pageQueue.Count <= 0) return false;
ReadLine(_pageQueue.Dequeue());
return true;
}
private void Start(){
Init();
}
//クリックしたときの処理
private void OnClick(){
if (_charQueue.Count > 0) OutputAllChar();
else{
if (!ShowNextPage()){
// UnityエディタのPlayモードを終了する
UnityEditor.EditorApplication.isPlaying = false;
}
}
}
}
ページ区切りのために"&"を用いている.
以下に動作画面と説明を載せる
最初の文が子のように表示しきった後,左クリックをすると,次の図のように分が表示される.
この状態でもう一度左クリックをすると実行画面が終了する.
ページ送りアイコンの非表示
現状では,右下の赤い三角が常に上下に動いている.しかし,これはページ送りアイコンとして用いたいので,全文が表示されておらず,次のページに進めない時には表示されてほしくない.ゆえに,"GamaManager.cs"を次のように変更して,文字の表示ちゅには現れないようにする.
using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
using System.Collections;
// MonoBehaviourを継承することでオブジェクトにコンポーネントとして
// アタッチすることができるようになる
public class GameManager : MonoBehaviour{
// SerializeFieldと書くとprivateなパラメーターでも
// インスペクター上で値を変更できる
[SerializeField]
private Text mainText;
[SerializeField]
private Text nameText;
[SerializeField]
private float captionSpeed = 0.2f;
[SerializeField]
private GameObject nextPageIcon;
// パラメーターを追加
private const char SEPARATE_MAIN_START = '「';
private const char SEPARATE_MAIN_END = '」';
private Queue<char> _charQueue;
private const char SEPARATE_PAGE = '&';
private Queue<string> _pageQueue;
private string _text = "ともり「トーキョーは 薄暗い閃光放って」&ともり 「消耗した MPも回復できぬまま」";
/**
* 文を1文字ごとに区切り、キューに格納したものを返す
*/
private Queue<char> SeparateString(string str){
// 文字列をchar型の配列にする = 1文字ごとに区切る
char[] chars = str.ToCharArray();
Queue<char> charQueue = new Queue<char>();
// foreach文で配列charsに格納された文字を全て取り出し
// キューに加える
foreach (char c in chars) charQueue.Enqueue(c);
return charQueue;
}
private bool OutputChar(){
if (_charQueue.Count <= 0){
nextPageIcon.SetActive(true);
return false;
}
mainText.text += _charQueue.Dequeue();
return true;
}
// 文字送りするコルーチン
private IEnumerator ShowChars(float wait){
// OutputCharメソッドがfalseを返す(=キューが空になる)までループする
while (OutputChar())
// wait秒だけ待機
yield return new WaitForSeconds(wait);
// コルーチンを抜け出す
yield break;
}
private void ReadLine(string text){
string[] ts = text.Split(SEPARATE_MAIN_START);
string name = ts[0];
string main = ts[1].Remove(ts[1].LastIndexOf(SEPARATE_MAIN_END));
nameText.text = name;
mainText.text = "";
_charQueue = SeparateString(main);
// コルーチンを呼び出す
StartCoroutine(ShowChars(captionSpeed));
}
//全文表示
private void OutputAllChar(){
StopCoroutine(ShowChars(captionSpeed));
while (OutputChar()) ;
nextPageIcon.SetActive(true);
}
// MonoBehaviourを継承しているとき,毎フレーム呼ばれる
private void Update(){
// 左(=0)クリックされたらOnClickメソッドを呼び出し
if (Input.GetMouseButtonDown(0)) OnClick();
}
//文字列を指定した区切り文字毎に区切り,キューに格納したものを返す
private Queue<string> SeparateString(string str, char sep){
string[] strs = str.Split(sep);
Queue<string> queue = new Queue<string>();
foreach (string l in strs) queue.Enqueue(l);
return queue;
}
//初期化
private void Init(){
_pageQueue = SeparateString(_text, SEPARATE_PAGE);
ShowNextPage();
}
//次のページの表示
private bool ShowNextPage(){
if (_pageQueue.Count <= 0) return false;
// オブジェクトの表示/非表示を設定する
nextPageIcon.SetActive(false);
ReadLine(_pageQueue.Dequeue());
return true;
}
private void Start(){
Init();
}
//クリックしたときの処理
private void OnClick(){
if (_charQueue.Count > 0) OutputAllChar();
else{
if (!ShowNextPage()){
// UnityエディタのPlayモードを終了する
UnityEditor.EditorApplication.isPlaying = false;
}
}
}
}
新しいパラメータ
private GameObject nextPageIcon;
を宣言しているので,Inspector上でもパラメータが増えているはずである.そこで,今追加したnextPagelconのオブジェクトとして"NextPagelcon"を選択する.すると次のようになる.
ここで実行をしてみると,文字の表示中は右下の赤い三角が消えているはずである.
出力し終わると表示される.
Unity練習3ではここまでにしたいと思います.
ここから先はUnity練習4に続きます.
この記事が気に入ったらサポートをしてみませんか?