0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Unity】入力キーの判定&画面上のキーを色変化させるスクリプト

Posted at

はじめに

現在タイピングゲームを作っているunity初心者です。
その際のキー入力判定と、押したキーの色を変える演出の実装方法について、汎用性が高そうだと思ったのでメモしておきます。

ゲーム画面

ゲーム画面はこんな感じです。

image.png

キーの画像はGeminiで生成し、フォントは以下を使わせていただきました。
チェックポイント.(ピリオド)
(キーの文字が少しずれているのは TMPro -> Font Asset Creator の設定の問題かもしれないです。後々調整します)
今回Text Mesh Proの使い方などUI関連の説明は省きます。

この記事ではキーボード入力で使用していますが、例えばWASDの移動で対応キーを表示させてわかりやすくするなど、いろいろ使えると思います。

実装する動作

  1. キーボードの入力を受け取る
  2. 押されたキーと連動して画面上のキーを赤色に変化させ、視覚的に分かりやすくする
  3. 受け取った文字を画面に表示する

実装手順

手順ごとに解説をします。解説が不要な方は、最後にコードの最終形まとめがあるのでそちらをご覧ください。

1. キーボードの入力を受け取る

以下のKeyScript.csを作成してください。

KeyScript.cs

using UnityEngine;

public class KeyScript : MonoBehaviour
{
    // SerializeField でインスペクターからキーコードを設定できるようにする
    [SerializeField] KeyCode targetKeyCode;

    void Update()
    {
        if (Input.GetKeyDown(targetKeyCode))    // 設定されたキーが押されたとき
        {
            Debug.Log($"{targetKeyCode}が押されました");    // 確認用のログを出力
        }
    }
}

KeyScript.csを作成したら、反応させたいキーのオブジェクトにアタッチしましょう。
アタッチしたオブジェクトのインスペクターを開いて、赤い四角で囲んだスクリプトの「Inputkey」で、反応させたいキーを選択してください。
(※画像のスクリプト名は KeyScript_test となっていますが、作成した KeyScript に読み替えて進めてください)

image.png

プロジェクトを実行して、設定したキーを入力してみましょう。

以下のログが出力されたら成功です。
image.png

反応させたいキーすべてに忘れずアタッチしましょう。

Tips💡
KeyCodeの選択肢が多すぎてダル…って思いませんでしたか?
実は、リストを開いたまま探したいキーの頭文字を押すと、そこへジャンプできます。

  • 頭文字ジャンプ:「S」キーを押せば "S" で始まる項目へ移動
  • 次の候補:もう一度「S」キーを押すと、次の "S" 始まりの項目へ移動

スクロールよりも速くなるので、ぜひ試してみてください!

2. 押されたキーを赤色に変化させる

KeyScript.cs に、入力に応じてオブジェクトの色を変える処理を追記します。
「SpriteRenderer」という、Unityでは2Dの画像にもともとついているコンポーネントを使用して色を変更します。
詳しくは以下の記事で解説されていますので気になる方は読んでみてください。

【Unity】SpriteRendererとは?2D画像を描画するためのコンポーネント

KeyScript.cs
(前回のコードからの変更点は▼▼▼ ここから追記 ▼▼▼▲▲▲ ここまで追記 ▲▲▲ で示した箇所です。)

using UnityEngine;

public class KeyScript : MonoBehaviour
{
    [SerializeField] KeyCode targetKeyCode;
    
    // ▼▼▼ ここから追記 ▼▼▼
    private SpriteRenderer keySpriteRenderer;

    void Start()
    {
        // オブジェクトについている「SpriteRenderer」というコンポーネントを探して、
        // 変数 keySpriteRenderer に入れる(後で色を変えるために必要)
        keySpriteRenderer = GetComponent<SpriteRenderer>();
        
        if (keySpriteRenderer == null)
        {
            Debug.LogError("KeyScriptにSpriteRendererコンポーネントが設定されていません。");
            // enabled = false にすると、これ以降 Updateメソッドが呼ばれなくなります(エラー回避)
            enabled = false;
        }
    }
    // ▲▲▲ ここまで追記 ▲▲▲

    void Update()
    {
        // SpriteRenderer が存在するかチェックした結果を hasSpriteRenderer に格納
        // 結果は true または false になる
        bool hasSpriteRenderer = keySpriteRenderer != null;

        if (Input.GetKeyDown(targetKeyCode))
        {
            Debug.Log($"{targetKeyCode}が押されました");

            // ▼▼▼ ここから追記 ▼▼▼
            if (hasSpriteRenderer)    // SpriteRendererコンポーネントがあるなら
            {
                // キーが押された瞬間、色を赤に変更
                keySpriteRenderer.color = new Color(1.0f, 0.0f, 0.0f, 1.0f); // 赤
            }
            // ▲▲▲ ここまで追記 ▲▲▲
        }
        // ▼▼▼ ここから追記 ▼▼▼
        else if (Input.GetKeyUp(targetKeyCode))    // 設定されたキーが離されたとき
        {
            if (hasSpriteRenderer)    // SpriteRendererコンポーネントがあるなら
            {
                // 色を元の色に戻す(Color.whiteで画像本来の色に戻ります)
                keySpriteRenderer.color = Color.white;
            }
        }
        // ▲▲▲ ここまで追記 ▲▲▲
    }
}

コードが書けたら、アタッチされているオブジェクトのインスペクターを確認して、「SpriteRenderer」コンポーネントがあるか確認してください。
ない場合はインスペクター下部の「Add Component」から追加できます。
image.png

問題がなければ実行してみましょう。
先ほどのログ出力に加え、キーを押している間、オブジェクトが赤色に変わっていれば成功です。

image.png
▲ 設定した「A」を押すと赤色になっています

3. 受け取った文字を表示する

受け取った文字を画面上に表示させていく機能を作ります。
以下のStringManager.csを作成してください。

StringManager.csの役割

  • 文字の管理: KeyScriptから受け取った文字を連結して保持する
  • 表示の更新: 現在の文字列を画面(UI)に反映させる

多数あるKeyScriptのどこからでもアクセスできるように、シングルトンパターンを採用しています。

StringManager.cs

using UnityEngine;
using TMPro;    // TextMesh Proを使うために必要

public class StringManager : MonoBehaviour
{
    // シングルトンパターン(どこからでもこのクラスを呼べるようにする)
    public static StringManager Instance { get; private set; }

    // インスペクターから文字を表示させるオブジェクトを設定できるようにする
    [SerializeField] private TMP_Text displayTMP;
    public string inputString = "";    // 現在入力している文字列

    // 自分自身(Instance)が重複しないようにチェックする
    private void Awake()
    {
        if (Instance == null) Instance = this;
        else Destroy(gameObject);
    }

    void Start()
    {
        if (displayTMP == null)
        {
            Debug.LogError("StringManagerにTextMesh Proコンポーネントが設定されていません。");
        }

        // 表示の初期化
        UpdateDisplay();
    }

    // 現在入力済みの文字列に新しい文字を追加するメソッド(KeyScript.cs で呼び出す)
    public void AppendString(string newCharacter)
    {
        inputString += newCharacter;
        Debug.Log("入力中の文字 : " + inputString);

        // 表示を更新する
        UpdateDisplay();
    }

    // 画面に文字列を表示するメソッド
    private void UpdateDisplay()
    {
        if (displayTMP != null)    // displayTMPにオブジェクトが設定されているなら
        {
            // TMPのテキスト要素を更新
            displayTMP.text = inputString;
        }
    }
}

上記のStringManagerを利用するために、KeyScript.csのコードも少し改変します。

KeyScript.cs(抜粋)

using UnityEngine;

public class KeyScript : MonoBehaviour
{
    [SerializeField] KeyCode targetKeyCode;
    
    // ▼▼▼ 追加 ▼▼▼
    // インスペクターで「このキーを押したら何の文字を追加するか」を設定する変数
    [SerializeField] string characterToAdd = "";
    
    private SpriteRenderer keySpriteRenderer;

    void Start()
    {
        // ▼▼▼ 追加 ▼▼▼
        // StringManager の Instance が存在しない場合(エラー処理)
        if (StringManager.Instance == null)
        {
            Debug.LogError("StringManager.Instanceが見つかりません。");
            enabled = false;
        }
        // (中略)
    }

    void Update()
    {
        bool hasSpriteRenderer = keySpriteRenderer != null;

        if (Input.GetKeyDown(targetKeyCode))
        {
            // (中略)
            
            // ▼▼▼ 追加 ▼▼▼
            // StringManager.Instance が存在するかつ characterToAddが設定されているなら
            if (StringManager.Instance != null && !string.IsNullOrEmpty(characterToAdd))
            {
                // StringManager内のAppendStringメソッドを呼び出す
                // 引数にcharacterToAddを渡すことで指定の文字を追加することができる
                StringManager.Instance.AppendString(characterToAdd);
            }
        }
        // (中略)
    }
}

ここからはUnityエディタ上での作業が少し多いので、手順1手順2に分けて解説します。

手順1:マネージャーの配置

  1. ヒエラルキーで空のオブジェクトを作成し、名前を GameManager などに変更します。
  2. 作成したオブジェクトに StringManager.cs をアタッチします。
  3. 文字表示用の TextMesh Pro (UI) もヒエラルキーに追加しておきます。
  4. StringManager のインスペクターにある Display TMP の枠に、3で作成したTextMesh Proをドラッグ&ドロップして紐付けます。

image.png

手順2:キーごとの文字設定

  1. KeyScript がついているキーのオブジェクトを選択します。
  2. インスペクターに Character To Add(追加する文字)という項目が増えているので、そこにそのキーに対応する文字(例:「A」など)を入力します。

image.png

実行確認
プロジェクトを再生し、キーを押して画面上の文字が増えていけば成功です!

コードの最終形

KeyScript.cs

using UnityEngine;

public class KeyScript : MonoBehaviour
{
    [SerializeField] KeyCode targetKeyCode;
    [SerializeField] string characterToAdd = "";
    private SpriteRenderer keySpriteRenderer;

    void Start()
    {
        if (StringManager.Instance == null)
        {
            Debug.LogError("StringManager.Instanceが見つかりません。");
            enabled = false;
        }

        keySpriteRenderer = GetComponent<SpriteRenderer>();

        if (keySpriteRenderer == null)
        {
            Debug.LogError("KeyScriptにSpriteRendererコンポーネントが設定されていません。");
            enabled = false;
        }
    }

    void Update()
    {
        bool hasSpriteRenderer = keySpriteRenderer != null;

        if (Input.GetKeyDown(targetKeyCode))
        {
            if (hasSpriteRenderer)
            {
                keySpriteRenderer.color = new Color(1.0f, 0.0f, 0.0f, 1.0f);
            }
            if (StringManager.Instance != null && !string.IsNullOrEmpty(characterToAdd))
            {
                StringManager.Instance.AppendString(characterToAdd);
            }
        }
        else if (Input.GetKeyUp(targetKeyCode))
        {
            if (hasSpriteRenderer)
            {
                keySpriteRenderer.color = Color.white;
            }
        }
    }
}

StringManager.cs

using UnityEngine;
using TMPro;

public class StringManager : MonoBehaviour
{
    public static StringManager Instance { get; private set; }

    [SerializeField] private TMP_Text displayTMP;
    public string inputString = "";

    private void Awake()
    {
        if (Instance == null) Instance = this;
        else Destroy(gameObject);
    }

    void Start()
    {
        if (displayTMP == null)
        {
            Debug.LogError("StringManagerにTextMesh Proコンポーネントが設定されていません。");
        }

        UpdateDisplay();
    }

    public void AppendString(string newCharacter)
    {
        inputString += newCharacter;
        Debug.Log("入力中の文字 : " + inputString);

        UpdateDisplay();
    }

    private void UpdateDisplay()
    {
        if (displayTMP != null)
        {
            displayTMP.text = inputString;
        }
    }
}

今後実装したいこと

  • 問題文との入力判定
    ロジック自体はすでに実装済みなので、近いうちに整理して別の記事としてまとめようと思います。

  • キー配置の自動化
    今回はキーの数だけ手動でオブジェクトを配置し、それぞれに targetKeyCodecharacterToAdd を設定したため、かなり手間がかかりました。
    今後は、これらの配置や設定をスクリプトで自動生成する方法も検討しています。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?