[Unity]2D牧場ゲームを作ってみる　その３[メッセージ表示]

# 前置き
子供からの夢で「牧場物語やルーンファクトリーみたいな牧場ゲームを作ってみたい！」と思っていました。
QiitaでUnityを使った2Dゲームはないかと調べたところ、素晴らしい記事を発見しました。

- [UnityでRPGを作るpart3 接触してるときにボタンを押したらメッセージを表示する](https://qiita.com/_tybt/items/c5e90c8825361d788829)

こちらの神記事を参考に2D牧場ゲームを作成していこうと思います。

# 今回作成するもの

- 1.文字を表示するメッセージウィンドウの作成
- 2.接触時にボタンを押したら反応するためのスクリプト作成
- 3.Inspectorにスクリプトを追加して設定
- 4.イベントトリガのためのBox Colldierを追加

# 1.文字を表示するメッセージウィンドウの作成

- 他のキャラに話しかけたとき、会話を始められるよう、メッセージを表示できるように設定していきます。

## 1-1.メッセージウィンドウの準備

- `右クリック > UI > Canvas`でメッセージを表示する領域を設定しましょう。名前は`message_window`としましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/763295/3cb9a345-9c73-bb62-302f-75030f948724.png)

- ImageとTextも同じように設定しましょう。
- Imageはウィンドウの枠を描画に関する設定、Textはウィンドウに表示するテキストの設定です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/763295/24d91640-f216-a06d-fc4d-6883e81d20e0.png)

- 以下の画像のように名前を設定しましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/763295/498381a4-8ab2-47e5-d0f5-5f8ed4f5efd7.png)

## 1-2.ウィンドウの領域を設定


- Canvas(message_window)の`Canvas Scaler(Script)`の`UI Scale Mode`を`Screen With Screen Size`に設定します。
- これで表示時にウィンドウの大きさに合わせてお要素などの大きさが調整されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/763295/cecea7d9-8c18-075e-e534-1a7c8582a841.png)

## 1-3.ウィンドウの色や画像を設定

- 次はImage(window)の`Image(Script)`を編集して、色や画像を設定していきます。
  - `Source Image`：デフォルトのAssetであるBackgroundを選択
  - `Color`：好きな色を選択
  - `ImageType`：SlicedのままでOK 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/763295/f452d4a2-5407-59c7-5977-c1b2798d5c24.png)


## 1-4.テキストのオブジェクトを設定
- 最後にメッセージを表示するためのテキストオブジェクトを設定する。
- `Text`と`Font Size`を好きに設定。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/763295/6b521e2c-dcf2-4748-694c-6e45233f9c5d.png)



# 2.接触時にボタンを押したら反応するためのスクリプト作成

## 2-1.親クラス

- まずは親クラスを設定。
- 親クラスはフィールド全般でオブジェクトに適応できる共通クラス。
- 以下のコードはキャラが接触しているときにボタンを押したら特定のメソッドを呼び出すことができます。

```cs
using System.Collections;
using UnityEngine;
using UnityEngine.UI;

/**
 * フィールドオブジェクトの基本処理
 */
public abstract class FieldObjectBase : MonoBehaviour
{

    // Unityのインスペクタ(UI上)で、前項でつくったオブジェクトをバインドする。
　　// （次項 : インスペクタでscriptを追加して、設定をする で説明）
    public Canvas window;
    public Text target;

    // 接触判定
    private bool isContacted = false;
    private IEnumerator coroutine;


    // colliderをもつオブジェクトの領域に入ったとき(下記で説明1)
    private void OnTriggerEnter2D(Collider2D collider) {
        isContacted = collider.gameObject.tag.Equals("Player");
    }

    // colliderをもつオブジェクトの領域外にでたとき(下記で説明1)
    private void OnTriggerExit2D(Collider2D collider) {
        isContacted = !collider.gameObject.tag.Equals("Player");
    }

    private void FixedUpdate() {
        if (isContacted && coroutine == null && Input.GetButton("Submit") && Input.anyKeyDown) {
            coroutine = CreateCoroutine();
            // コルーチンの起動(下記説明2)
            StartCoroutine(coroutine);
        }
    }

    /**
     * リアクション用コルーチン(下記で説明2)
     */
    private IEnumerator CreateCoroutine() {
        // window起動
        window.gameObject.SetActive(true);

        // 抽象メソッド呼び出し 詳細は子クラスで実装
        yield return OnAction();

        // window終了
        this.target.text = "";
        this.window.gameObject.SetActive(false);

        StopCoroutine(coroutine);
        coroutine = null;
    }

    protected abstract IEnumerator OnAction();

    /**
     * メッセージを表示する
     */
    protected void showMessage(string message) {
        this.target.text = message;
    }
}
```


## 2-2.子クラス

- 子クラスに設定をしていきます。
- 子クラスが親で特定のメソッドが呼ばれたとき、メッセージ表示の処理を行います。
- セリフはInspector上で設定できるようにします。

```cs
public class MessageCharactor : FieldObjectBase {

    // セリフ : Unityのインスペクタ(UI上)で会話文を定義する 
　　// （次項 : インスペクタでscriptを追加して、設定をする で説明）
    [SerializeField]
    private List<string> messages;

    // 親クラスから呼ばれるコールバックメソッド (接触 & ボタン押したときに実行)
    protected override IEnumerator OnAction() {

        for (int i = 0; i < messages.Count; ++i) {
            // 1フレーム分 処理を待機(下記説明1)
            yield return null;

            // 会話をwindowのtextフィールドに表示
            showMessage(messages[i]);

            // キー入力を待機 (下記説明1)
            yield return new WaitUntil(() => Input.anyKeyDown);
        }

        yield break;
    }
}

```


# 3.Inspectorにスクリプトを追加して設定

- 話しかけるキャラクター、以下のキャラを設定します。
- 名前は「セルザウィード」と言うルーンファクトリーのキャラクターになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/763295/26105b38-5ac6-f61b-5b69-26f13fc36f6f.png)


- 話しかけるキャラクターに`Message Charactor`のスクリプトを追加します。
- `Messages`の`+`ボタンを押して`Element`を追加します。
- `Element`に表示したいメッセージを書き込みましょう。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/763295/ec141079-6d0e-e313-b7c1-1c3a5a8f5059.png)

# 4.イベントトリガのためのBox Colldierを追加

- `Box Collider 2D`を2つに設定し、片方は`Is Trigger`をON、片方はOFFにします。
  - `Is Trigger`をONにすると、キャラへの衝突判定がなくなります。
  - `Is Trigger`をOFFにすると、キャラに触れてエンターを押してもメッセージが表示されません。
  - `Box Colldier 2D`を2つ用意することで、解決することができます。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/763295/dde0bcd4-bf9c-d92b-300f-af9e350ce9b6.png)


# 完成

![Videotogif (5).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/763295/f71e3810-6ac4-e446-7f70-13daf4f05c8a.gif)


# 次回作成するもの（仮）

- アイテムの持ち上げの設定
- （できれば）キャラクターに話しかけたときに、主人公の動きが止まるように設定する

# 参考にしたサイト

- [UnityでRPGを作るpart3 接触してるときにボタンを押したらメッセージを表示する](https://qiita.com/_tybt/items/c5e90c8825361d788829)