Unity 初心者向けキャラクター属性表示チュートリアル

このチュートリアルでは、Unity を使ってキャラクターの名前が表示されたボタンを押すと、そのキャラクターのイラストと属性(力、スピード、魔法など)が表示されるシンプルなシステムを作成します。TextMeshPro を使って属性を表示し、UI の操作やスクリプトを学びながら、キャラクター情報の表示機能を実装します。


目次

目標

キャラクター名のボタンをクリックすることで、そのキャラクターのイラストと属性を表示するシステムを構築します。


Step 1: Unity プロジェクトの準備

画像の準備

ダウンロードされるファイルは、webpフォーマットになります

新しいプロジェクトを作成

  • Unity Hubを開き、「New Project」をクリックして、テンプレートとして「3D」を選びます。
  • プロジェクト名を「CharacterDisplayTutorial」にします。

TextMeshPro パッケージのインストール(必要に応じて)

  • Unity エディター上部の「Window」→「Package Manager」を開き、「TextMeshPro」を検索してインストールします。

Step 2: UIの作成

Canvas の作成と設定

  • Canvas を作成し、選択した状態で Canvas Scaler コンポーネントの設定を確認します。
  • 「UI Scale Mode」を「Scale With Screen Size」に設定し、Reference Resolution の値を X: 800, Y: 600 に設定します。これにより、画面サイズが変わっても UI が適切にスケーリングされます。
  • 「Screen Match Mode」を「Expand」に設定します。これにより、異なる画面のアスペクト比に応じて UI が自動的に調整されます。
  • 「Reference Pixels Per Unit」はデフォルトの 100 に設定します。

800x600 は、かつて標準的な解像度としてよく使われていましたが、現在のディスプレイの標準解像度はこれよりも高く、フルHD(1920×1080)やそれ以上が一般的です。そのため、現代のデバイスや画面サイズに合わせるのであれば、800x600 では少し小さいかもしれません。

推奨事項:

  1. 現代の解像度に合わせる場合:
    例えば、フルHD解像度を想定する場合は、1920x1080 を基準に設定すると良いです。これにより、現代のディスプレイで一般的な解像度に適応しやすくなります。
    • Reference Resolution: X: 1920, Y: 1080
    • この設定により、アスペクト比が16:9の画面に適応しやすくなります。
  2. マルチプラットフォームを考慮する場合:
    もし様々な画面サイズ(スマートフォン、タブレット、PCなど)に対応することを考えているなら、解像度をどこに合わせるかはプロジェクトのターゲットデバイスによって決めると良いです。800x600 は最低限の対応解像度として残しつつ、スケール設定で柔軟に対応する方法もあります。

結論として、800x600 は小型のディスプレイや、旧型のPC向けには問題ありませんが、現在主流のディスプレイでは解像度が低く感じられる可能性があります。ターゲットとするプラットフォームによって調整するのが良いでしょう。

キャラクター名を表示するボタンを作成

  • Canvas を右クリックし、「UI」→「Button」でボタンを追加します。
  • ボタンの名前を「Character1Button」に変更し、インスペクターの Text フィールドにキャラクター名(例: 「Dragon」)を設定します。
  • 複数のキャラクター用にボタンを複製し、それぞれのボタンの名前とテキストを変更します(例: 「Knight」「Elf」など)。

キャラクター情報を表示するパネルを作成

  • Canvas を右クリックして「UI」→「Panel」を選び、パネルを作成します。
  • 名前を「CharacterInfoPanel」に変更し、インスペクターで最初は非表示に設定します。

イラストを表示するImageを追加

  • CharacterInfoPanel を右クリックし、「UI」→「Image」で Image オブジェクトを作成し、キャラクターのイラストを表示する領域を設定します。

属性を表示するTextMeshProを追加

  • CharacterInfoPanel を右クリックし、「UI」→「Text – TextMeshPro」で TextMeshPro のテキストフィールドを追加します。
  • 名前を「CharacterAttributes」に変更し、テキストのフォントやサイズを調整します。

Step 3: スクリプトの作成

C# スクリプトの作成

  • Assets フォルダ内で「右クリック」→「Create」→「C# Script」で新しいスクリプトを作成し、名前を「CharacterDisplay.cs」にします。

スクリプトの内容

コード全体に詳細なコメントを追加しました。特に初心者向けに、各行やセクションが何をしているのかを説明しています。

using UnityEngine;
using UnityEngine.UI;       // UnityのUI要素を操作するために必要なライブラリ
using TMPro;               // TextMeshPro(高品質なテキストレンダリングを行うためのUIコンポーネント)を使うためのライブラリ
using System;              // [Serializable] 属性を使用するための標準ライブラリ

// CharacterDisplayクラスは、キャラクターのイラストと属性を表示する機能を提供します
public class CharacterDisplay : MonoBehaviour
{
    // UI要素への参照
    public Image characterImage;           // キャラクターのイラストを表示するImageコンポーネント
    public TextMeshProUGUI characterAttributes;  // キャラクターの属性(力、スピードなど)を表示するTextMeshProコンポーネント
    public GameObject panel;               // キャラクター情報を表示するパネル(非表示/表示の切り替えが可能)

    // キャラクターのデータ構造を定義する内部クラス
    [Serializable] // Unityのインスペクターでこのクラスを表示・編集可能にするための属性
    public class Character
    {
        public string name;               // キャラクターの名前
        public Sprite illustration;       // キャラクターのイラスト画像(Sprite)
        public string attributes;         // キャラクターの属性情報(例: 力、スピード、魔法など)
    }

    // ゲーム内で使用されるキャラクターのリスト
    public Character[] characters;         // 複数のキャラクターを格納するための配列

    // ボタンが押された際に呼び出されるメソッド
    // index はどのボタンが押されたかを示すインデックス
    public void OnCharacterButtonPressed(int index)
    {
        // index が範囲内(0 <= index < characters.Length)の場合に処理を実行
        if (0 <= index && index < characters.Length)
        {
            // キャラクター情報を表示するパネルを有効化(表示状態にする)
            panel.SetActive(true);

            // 押されたボタンに対応するキャラクターのイラストと属性を更新
            characterImage.sprite = characters[index].illustration;   // イラストを表示
            characterAttributes.text = characters[index].attributes;  // 属性情報をテキストに設定
        }
    }
}

インスペクターでのイメージ


Step 4: Unityエディターでの設定

スクリプトをアタッチ

  • Canvas を選択し、作成した CharacterDisplay スクリプトをドラッグしてアタッチします。

スクリプト内のフィールドを設定

  • インスペクターで characterImagecharacterAttributespanel フィールドにそれぞれ対応する UI 要素をドラッグして設定します。

キャラクター情報を設定

  • CharacterDisplay スクリプト内の characters リストに、各キャラクターの名前、イラスト(Sprite)、および属性(String)を設定します。

ボタンにクリックイベントを設定

  • 各キャラクターのボタンを選択し、「OnClick ()」イベントに CharacterDisplay スクリプトの OnCharacterButtonPressed イベントハンドラを設定し、応するキャラクターのインデックスを引数として渡します(例: Dragon -> 0, Knight -> 1, Elf -> 2)。

エディタのイメージ

Canvasの例

Panelの例

Buttonの例


Step 5: 動作確認

シーンを保存

  • シーンを保存し、再生ボタンを押してシーンを再生します。

動作を確認

  • キャラクター名のボタンをクリックすると、該当するキャラクターのイラストと属性がパネルに表示されることを確認します。

完成:

これで、キャラクター名のボタンを押すと、それぞれのキャラクターのイラストと属性が TextMeshPro を使って表示されるシンプルなシステムが完成しました。

技術資料:Character クラスCharacter クラスの設計と構造

Character クラスを CharacterDisplay クラスのインナークラス(内部クラス)として定義する理由と、その設計上のメリットやデメリットについて説明します。また、プロジェクトの要件に応じて、インナークラスまたは外部クラスとして定義する際の考慮点についても述べます。

Character クラスをインナークラスとして定義する理由

Character クラスを CharacterDisplay クラスのインナークラス(内部クラス)として定義している理由は、主に次のような理由が考えられます。

1. 構造的な関係を明示するため

Character クラスは CharacterDisplay クラス専用のデータ構造です。他のクラスやスクリプトからは使用されず、CharacterDisplay クラス内でのみ使用されるため、インナークラスとして定義することで「Character クラスは CharacterDisplay の一部であり、外部では使用されない」という関係が明確になります。

2. スコープの限定

インナークラスとして定義することで、CharacterDisplay クラス内にスコープを限定できます。これにより、他のスクリプトやクラスが Character クラスに誤ってアクセスすることを防ぎ、意図しない誤用を避けられます。

3. 可読性の向上

Character クラスは CharacterDisplay クラスと密接に関連しており、内部クラスにすることでコード全体の可読性が向上します。Character クラスが他の部分から独立しているわけではなく、CharacterDisplay に密接に関わるものであるため、同じクラス内にまとめることでコードが整理され、理解しやすくなります。

4. データと表示の一体化

Character クラスはキャラクターのデータを持ち、CharacterDisplay クラスはそのデータを表示する役割を持っています。インナークラスにすることで、データとその表示ロジックが近接して管理され、設計の一貫性が保たれます。

5. インスペクターでのシリアライズ

Character クラスに [Serializable] 属性を付けることで、Unity のインスペクターで CharacterDisplayクラスの一部として Character の配列を管理できます。インナークラスとして定義しておけば、キャラクター情報が CharacterDisplay クラスの一部として直感的にまとめられ、インスペクターからも管理しやすくなります。


インナークラス構造の適切性

1. インナークラスの利点

  • カプセル化Character クラスが CharacterDisplay クラス内でのみ使用される場合、インナークラスとしてカプセル化することで、不必要な外部アクセスを防げます。
  • 論理的なまとまりCharacter クラスが CharacterDisplay に依存しているなら、インナークラスにすることで論理的なまとまりが良くなり、コードの可読性が向上します。

2. インナークラスの欠点

  • 柔軟性の制限Character クラスが他のスクリプトやシステムでも必要になる場合、インナークラスとして定義すると、アクセスや再利用が難しくなります。
  • 拡張性の低下: 他のシステムで Character クラスのデータや機能を利用したい場合、インナークラスでは拡張性が低下します。例えば、キャラクターのデータを別の管理システムで使用する場合、インナークラスだと不便です。

推奨される構造

インナークラスが適切な場合

  • 他のシステムに依存しない場合Character クラスが CharacterDisplay クラス内でのみ使用される処理に閉じている場合、インナークラスとして定義するのが適切です。キャラクターのデータが UI 表示のためだけに使用される場合などが該当します。
  • 設計がシンプルな場合: ゲームの規模が小さく、キャラクター情報が表示や簡単な処理にのみ使われる場合は、インナークラスの構造がシンプルで管理がしやすいです。

インナークラスが不適切な場合

  • キャラクターがゲーム全体で重要な役割を果たす場合: 戦闘システム、AI、データ保存など、他のシステムがキャラクター情報にアクセスする必要がある場合は、Character クラスを外部クラスにした方が柔軟です。インナークラスではアクセスが煩雑になり、再利用が難しくなります。

Character クラスを外部クラスに定義する方法

プロジェクト全体でキャラクター情報が多くの場所で使用される場合、Character クラスをインナークラスではなく、外部クラスとして定義する方が適切です。

// 外部クラスとして Character を定義
[System.Serializable]
public class Character
{
    public string name;
    public Sprite illustration;
    public string attributes;
}

// CharacterDisplay クラス
public class CharacterDisplay : MonoBehaviour
{
    public Character[] characters;
    public Image characterImage;
    public TextMeshProUGUI characterAttributes;
    public GameObject panel;

    public void OnCharacterButtonPressed(int index)
    {
        if (0 <= index && index < characters.Length)
        {
            Character selectedCharacter = characters[index];
            panel.SetActive(true);
            characterImage.sprite = selectedCharacter.illustration;
            characterAttributes.text = selectedCharacter.attributes;
        }
    }
}

メリット

  • 柔軟な再利用Character クラスを他のクラスやシステムでも利用しやすくなります。
  • 明確な責任分担Character クラスはデータを管理し、CharacterDisplay クラスは表示に専念するという役割が明確に分離されます。
  • 将来的な拡張性Character クラスを他のシステムで再利用したり、拡張する際に柔軟性が高まります。

結論

Character クラスの設計は、ゲームの規模やプロジェクトの要件に応じて適切な構造を選択する必要があります。キャラクター情報が CharacterDisplay クラス内で完結するシンプルなシナリオでは、インナークラスの利用が適しています。一方で、キャラクター情報を他のシステムでも利用する必要がある場合は、外部クラスとして定義する方が柔軟で拡張性が高くなります。

技術資料:インナークラスに外部からアクセスする方法

ゲーム中でキャラクター情報にアクセスする必要がある場合、CharacterDisplay クラスを通じて Character クラスのインスタンスにアクセスするか、Character クラスを外部から直接参照できるようにする設計が必要です。以下では、その主なアプローチを紹介します。

1. CharacterDisplay クラスのメソッドを利用する

CharacterDisplay クラスはキャラクター情報を管理しているため、外部のスクリプトから CharacterDisplayクラスを通じてキャラクター情報にアクセスできます。例えば、選択されたキャラクターの情報を他のクラスで使用するには、CharacterDisplay に情報を取得するメソッドを作成します。

public class CharacterDisplay : MonoBehaviour
{
    public Character[] characters;

    // 特定のキャラクターを返すメソッド
    public Character GetCharacter(int index)
    {
        if (0 <= index && index < characters.Length)
        {
            return characters[index];
        }
        return null;  // 範囲外の場合
    }
}

外部のスクリプトから、この GetCharacter メソッドを呼び出して、キャラクター情報にアクセスできます。

// 例: 外部のスクリプトからアクセス
CharacterDisplay characterDisplay = FindObjectOfType<CharacterDisplay>();
Character selectedCharacter = characterDisplay.GetCharacter(0);

if (selectedCharacter != null)
{
    Debug.Log("キャラクター名: " + selectedCharacter.name);
}

2. キャラクターのデータを公開するプロパティを利用する

キャラクターのデータを外部から安全にアクセスできるように、CharacterDisplay クラスにプロパティを定義することも可能です。これにより、外部スクリプトは CharacterDisplay クラスを介してキャラクター情報にアクセスできます。

public class CharacterDisplay : MonoBehaviour
{
    private Character selectedCharacter;

    public Character SelectedCharacter
    {
        get { return selectedCharacter; }
        private set { selectedCharacter = value; }
    }

    // ボタンが押されたときに呼ばれるメソッド
    public void OnCharacterButtonPressed(int index)
    {
        if (0 <= index && index < characters.Length)
        {
            selectedCharacter = characters[index];
            panel.SetActive(true);
            characterImage.sprite = selectedCharacter.illustration;
            characterAttributes.text = selectedCharacter.attributes;
        }
    }
}

外部スクリプトは、このプロパティを使って選択されたキャラクターの情報にアクセスできます。

// 例: 他のスクリプトからアクセス
CharacterDisplay characterDisplay = FindObjectOfType<CharacterDisplay>();
Character selectedCharacter = characterDisplay.SelectedCharacter;

if (selectedCharacter != null)
{
    Debug.Log("選択されたキャラクターの名前: " + selectedCharacter.name);
}

3. Character クラスを外部で使えるように定義する(再掲)

もし Character クラスを他のスクリプトでも扱いたい場合は、インナークラスとしてではなく、外部クラスとして定義することが有効です。これにより、他のスクリプトから Character クラスを直接扱えるようになります。

// 外部クラスとして定義する
[System.Serializable]
public class Character
{
    public string name;
    public Sprite illustration;
    public string attributes;
}

// CharacterDisplay クラス内で使用
public class CharacterDisplay : MonoBehaviour
{
    public Character[] characters;
    public Image characterImage;
    public TextMeshProUGUI characterAttributes;
    public GameObject panel;

    public void OnCharacterButtonPressed(int index)
    {
        if (0 <= index && index < characters.Length)
        {
            Character selectedCharacter = characters[index];
            panel.SetActive(true);
            characterImage.sprite = selectedCharacter.illustration;
            characterAttributes.text = selectedCharacter.attributes;
        }
    }
}

外部クラスとして Character を定義することで、他のスクリプトからも直接アクセスが可能になります。

// 例: 外部スクリプトでのキャラクター作成
Character myCharacter = new Character();
myCharacter.name = "勇者";
myCharacter.attributes = "攻撃力: 50, 防御力: 20";

まとめ

CharacterDisplay 経由でアクセス:

外部スクリプトからキャラクター情報にアクセスする場合、CharacterDisplay クラスにメソッドやプロパティを定義し、それを通じてアクセスする方法が一般的です。

外部クラスとして Character を定義:

キャラクター情報を他のクラスでも汎用的に扱いたい場合、Character クラスを CharacterDisplay から分離し、外部クラスとして定義することが有効です。

いずれの場合でも、キャラクター情報にアクセスする際は、スコープやアクセス修飾子を適切に設定し、安全かつ柔軟な設計を心がけましょう。

Unity

Posted by hidepon