スクリプトだけで会話機能の実装

街を探索して住人と会話する場面をUnityで実装してみました。会話機能自体は、「宴」など簡単に実装できるソフトがあるらしいですが、今回はスクリプトだけで実装してみます。
全体の流れとしては

1.住人の設置
2.住人の喋る内容を設定するスクリプト
3.テキストを表示するスクリプト
4.プレイヤーが一定範囲内に入ったら会話できるサインを表すオブジェクトの表示設定

の順番で説明していきたいと思います。
ちなみに完成イメージはこんな感じです。今回はこの画像の中の、<font color="Red">Aボタンと水色のテキストウィンドウの機能について説明します。</font>

〜完成イメージ〜
![スクリーンショット 2018-05-30 20.52.25.png](https://qiita-image-store.s3.amazonaws.com/0/249989/eff96519-4cc9-6c47-d441-c1e884a2ac0f.png)

##1.住人の設置
まずは街の住人とプレイヤーを設置します。
プレイヤーの移動や配置などは割愛しますが、今回は<font color="Red">住人とプレイヤーの両方にCollider</font>をつけましょう。そして、<font color="Red">住人側のColliderにはisTriggerにチェック</font>を入れます。参考までに、プレイヤーと住人のColliderの適用範囲の画像を載せます。適用範囲とは、要するに会話可能範囲です。加えて、<font color="Red">プレイヤーにはRigidBodyと"player"と言う名前でタグ</font>をつけておきましょう。

〜プレイヤー〜
![スクリーンショット 2018-06-05 15.52.55.png](https://qiita-image-store.s3.amazonaws.com/0/249989/e8afd12b-ffe8-530f-2a5d-1ea8bfe4c21c.png)

〜プレイヤーの一部インスペクタービュー〜
![Player 当たり判定(ins).png](https://qiita-image-store.s3.amazonaws.com/0/249989/6f8b323b-9ef8-ea0d-2b61-c6fe06c59177.png)


〜住人〜
![スクリーンショット 2018-06-05 15.52.14.png](https://qiita-image-store.s3.amazonaws.com/0/249989/0fd26fee-952d-3ae0-413c-a4471e425d1c.png)

今回は[プレイヤー](https://assetstore.unity.com/packages/3d/characters/robots/space-robot-kyle-4696)と[住人](https://assetstore.unity.com/packages/3d/characters/creatures/level-1-monster-pack-77703)はリンク先の素材を使いました。ここは自由に変更してください。


##2.住人の喋る内容を設定するスクリプト
下のCharacterScriptを作成して、住人につけます。
前述したように**プレイヤーにはあらかじめ、playerという名前でタグをつけて起きましょう。**

```c#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class CharacterScript : MonoBehaviour {

     //住人の話す内容
	public string[] scenarios;
     //プレイヤーが一定範囲内に入ったら会話できるサインを表すオブジェクト
	public GameObject heart;
     //プレイヤーが範囲内にいるかどうかの判定
	bool Aflagflag = false;

	public IventScript iventScript;


	
	void Start () {
		heart.SetActive (false);
	}
	

	void Update () {
	}

	void OnTriggerEnter(Collider other){
//もしplayerタグをつけたゲームオブジェクトが住人のCollider判定範囲に入ったら
		if (other.gameObject.tag == "player") {
			Aflagflag = true;
//IventScriptのStartIventメソッドに会話が可能な状態であることを示すフラグと、住人の話す内容を送る。
			iventScript.StartIvent (Aflagflag, scenarios);

//住人の頭上にオブジェクトを表示(座標は自由に変えてください)
			heart.transform.position = gameObject.transform.position + new Vector3 (-0.5f, 1f, 0);
			heart.SetActive (true);
		}
	}


	void OnTriggerExit(Collider other){
		if(other.gameObject.tag=="player"){
//プレイヤーが範囲外に出たら会話しない。 
			Aflagflag = false;
			heart.SetActive (false);
			}
	}

}

```

スクリプトの説明をします。
プレイヤーが住人のCollider範囲=会話可能な範囲内に入ったら、Aflagflagをtrueにし、iventScriptに、セリフの内容とAflagflagの結果を送ります。そして、プレイヤーに会話が可能だと知らせるために用意したheartというオブジェクトを住人の頭上に表示します(iventScriptについてはこの後に説明します)
プレイヤーが会話可能な範囲外に出たら、Aflagflagをfalseにし、heartを消します。
先ほど用意した**住人にこのスクリプトをアタッチ**して見ましょう。そうすると、住人のインスペクタービューにCharacterScriptが表示されます。ここの**Scenariosの部分でシナリオの長さ(Size)と喋る内容を設定**できます。
HeartIconとIventControllerについてはこの後説明しますので、完成したら忘れずにここにアタッチしておきましょう。

〜住人のインスペクタービュー〜
![Character Script(ins).png](https://qiita-image-store.s3.amazonaws.com/0/249989/6cc01f1a-7227-9108-be5b-2453e530f436.png)



次にIventScriptについて説明します。

```c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class IventScript : MonoBehaviour {

	public TextController textController;
//CharacterScriptから送られてきたAflagflagの格納用
	bool flag2=false;
//CharacterScriptから送られてきたscenariosの格納用
	string[] scenarios2;

	
	public void StartIvent (bool flag,string[] scenarios) {
		flag2 = flag;
		scenarios2 = scenarios;
	}
	

	void Update () {
		
	}

	public void AButton(){
		if (flag2) {
			textController.StartText (scenarios2);	
			flag2 = false;
		}
	}
}


```

今回は、プレイヤーが住人に近づいて、ボタンを押したら会話をするように実装します。
そのため、Canvasにあらかじめそれ用のボタン（ここではAボタン）を用意し、AButtonメソッドをClickの部分にアタッチしてください。
そうすると、**プレイヤーが会話可能な範囲内にいて、かつ、ボタンを押したら会話イベントが発生する**仕組みになります。
また、空のゲームオブジェクトを用意して、名前をIventControllerとします。そして、そこにIventScriptをアタッチしましょう。

〜ボタンを用意<font color="Red">（今回はAボタンだけ！）</font>〜
![スクリーンショット 2018-06-05 15.55.32.png](https://qiita-image-store.s3.amazonaws.com/0/249989/e6c47414-0227-3972-cdc7-9180bc712a19.png)

〜会話をするためのボタン(Aボタン)のインスペクタービュー〜
![Aボタン　onClick(ins).png](https://qiita-image-store.s3.amazonaws.com/0/249989/225f8ea8-62bb-5985-29ff-becaec5b7b2c.png)

〜IventController(空のゲームオブジェクト)のインスペクタービュー〜
![IventController(ins).png](https://qiita-image-store.s3.amazonaws.com/0/249989/ec78a6a2-f5af-53ef-548a-ba5a194fa364.png)



##3.テキストを表示するスクリプト
次に、住人の話す内容を表示するためのTextControllerスクリプトを用意します。このスクリプトは[こちら](http://tsubakit1.hateblo.jp/entry/2014/12/06/233000http://tsubakit1.hateblo.jp/entry/2014/12/06/233000)のサイト様のを参考にしました。

```c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class TextController : MonoBehaviour {

	//シナリオを格納
	private string[] scenarios2;
	//uiTextへの参照を保つ
	private Text uiText;

	//現在の行番号
	int currentLine;

     //セリフを表示するテクスト(文字の大きさや色はここにアタッチしたTextをいじって決定する)
	public Text message;
	int flag=0;
    //テキストウィンドウ
	public GameObject panel;

	// Use this for initialization
	public void StartText (string[] scenarios) {
		flag=1;
		scenarios2=scenarios;
		currentLine = 0;
		uiText = message;
    //パネルを表示
		panel.SetActive (true);
   //テクストを表示
		uiText.gameObject.SetActive (true);
		TextUpdate ();

	}

	public void Click(){
		if (flag == 1) {
			//現在の行番号がラストまで行ってない状態でボタンを押すとテキストを更新する
			if (currentLine < scenarios2.Length) {			
				TextUpdate ();
			} else {
   //最後まで行ったら、テキストとテキストウィンドウを消す
					uiText.gameObject.SetActive (false);
					panel.SetActive (false);
					flag = 0;
			}
		}

	}

	
	void TextUpdate(){
		//現在の行番号をuiTextに流し込み、現在の行番号を一つ追加する
		uiText.text = scenarios2 [currentLine];
		currentLine++;
	}


}

```

ヒエラルキービューに空のゲームオブジェクトを用意して、名前をTextControllerとし、このスクリプトをアタッチしましょう。

〜TextController(空のゲームオブジェクト)のインスペクタービュー〜
![TextController(ins).png](https://qiita-image-store.s3.amazonaws.com/0/249989/c510ff1e-0e07-a288-fd70-cdd418684ea3.png)

そして、Canvas内にテキストウィンドウとなるPanelとセリフを表示する用のTextを作成します。**TextはPanelの子オブジェクト**にしましょう。以下の画像を参考にして見てください。

〜Canvas内にPanelとTextを用意〜
![canvas&panel(ヒエラルキー).png](https://qiita-image-store.s3.amazonaws.com/0/249989/7a008b91-cff3-ee8b-c174-75714f74a621.png)

〜Panelのインスペクタービュー〜
![panel (インスペクター).png](https://qiita-image-store.s3.amazonaws.com/0/249989/b19fecaf-6bab-9703-5331-e53e8b191247.png)

〜Textのインスペクタービュー〜
![text(インスペクター).png](https://qiita-image-store.s3.amazonaws.com/0/249989/a9b45924-17c7-133d-0673-057a175137d5.png)


上記のパネルや文字のスタイルはあくまで参考程度なのでお好きな形に変えてください。作った**PanelとTextはTextControllerのインスペクタービューにアタッチ**しましょう。
また、前述した**IventControllerとボタンのOnClickの部分にTextCOntrollerをアタッチ**しましょう。


##4.プレイヤーが一定範囲内に入ったら会話できるサインを表すオブジェクトの表示設定

ここまでで会話機能は成立しますが、今の状態だとどのタイミングで会話可能なのかが分かりません。なので次は、プレイヤーが会話可能な範囲に入ったら、住人の頭上にハートのオブジェクトを表示して、ボタンを押したら会話が可能だと知らせるようにしましょう。

ここまでくれば後は簡単です。
オブジェクトはなんでも良いです。私は、カプセルを二つくっつけたハート?のオブジェクトを用意しました。

〜ハートのオブジェクト〜
![HeartIcon (ヒエラルキー).png](https://qiita-image-store.s3.amazonaws.com/0/249989/98787ed9-a391-580b-2fc8-44c0d88b0e95.png)

〜こんな感じ〜
![スクリーンショット 2018-06-05 15.54.11.png](https://qiita-image-store.s3.amazonaws.com/0/249989/604759c2-b4a4-66f6-c27e-bbdf3f49e0b9.png)

CharacterScriptの様々な部分でpublic GameObject heartやheart.SetActive (true)といった表記を目にしたと思います。CharacterScriptにハートのオブジェクトを住民の頭上に表示するための命令は書いてあるので、後はその**CharacterScriptをつけた住人のインスペクタービューにこのHeartIconオブジェクトをアタッチ**するだけです。



説明は以上です。お疲れ様でした！