2nd term 2nd week - dsuz/csharp GitHub Wiki
- 継承
- 多態性
- CSharp2-2.unitypackage をダウンロードして Unity のプロジェクトにインポートする
- Project のフォルダ "2-2 inheritance and polymorphism" の下にある Platformer2D シーンを開いて実行し、動くことを確認しておくこと
このシーンの動きについて、機能的に特別なことは何もありません。アイテムの挙動について enum を活用したり、アイテムを複数持つために List を活用している程度です。では、Coin オブジェクトの CoinController コンポーネントのコードを見てみましょう。すると、書かれている内容が非常に少ないことに気づくでしょう。これだけの内容で「プレイヤーがコインに触れたら、効果音を鳴らしてオブジェクトを消し、100 点を追加する」ことができるわけがありません。これだけのコードでそんなことができるのは、これが「ItemBase2D を継承している」からです。
今回の授業ではごく一部しか扱わないので、教科書を見ておくこと。
- 継承 - クラスの機能を引き継いで新しいクラスを作ること
- Unity では、コンポーネントは必ず MonoBehaviour を継承している
- 以下の用語は最低でも理解しておくこと
- 基底クラス (base class)
- 派生クラス (subclass, inherited class, derived class)
- 抽象クラス (abstract class)
- 実装 (implementation)
以下の手順でアイテムの基底クラス (ItemBase2D) を抽象クラス (abstract class) にしてみましょう。
- 冒頭の
public class
をpublic abstract class
に変える- これにより ItemBase2D を直接インスタンス化する(つまり GameObject に追加する)ことはできなくなる
- Activate() 関数の定義から、
public virtual void
をpublic abstract void
に変える - abstract な関数に実装は追加できないので、関数の処理が書かれているブロックを削除する
つまり以下のようなコードになります。
public abstract class ItemBase2D : MonoBehaviour
{
/// <summary>アイテムを取った時に鳴る効果音</summary>
[Tooltip("アイテムを取った時に鳴らす効果音")]
[SerializeField] AudioClip _sound = default;
/// <summary>アイテムの効果をいつ発揮するか</summary>
[Tooltip("Get を選ぶと、取った時に効果が発動する。Use を選ぶと、アイテムを使った時に発動する")]
[SerializeField] ActivateTiming _whenActivated = ActivateTiming.Get;
/// <summary>
/// アイテムが発動する効果を実装する
/// </summary>
public abstract void Activate();
private void OnTriggerEnter2D(Collider2D collision)
// (以下略)
この状態で、派生クラス(例えば HeartController)の Activate() メソッドを削除してみましょう。すると CS0534 のコンパイル エラーになります。これは「派生クラスが基底クラスの抽象(abstract な)メンバーを継承していない」という意味です。派生クラスは基底クラスのすべての抽象メンバー(メンバ関数・メンバ変数・プロパティ)を実装する必要があります。つまり、抽象クラスと抽象メンバーを使うことで「実装を強制する」ことができます。抽象クラスにしなければ、この強制はできません。
ItemBase2D を継承したコンポーネントを使ったアイテムの "When Activated" に "Use" を指定すると、アイテムをとった時ではなく、アイテムを「使った」時に効果を発動することができる。アイテムを使うためにはアイテムを「所持」していなければならない。持っているアイテムは PlatformerPlayerController2D コンポーネントのメンバ変数 _itemList に格納されている。これは「ItemBase2D 型」の List である。
アイテムを「使う」と、ItemBase2D 型の変数(インスタンス)の Activate() メソッドを呼ぶ。
この時、ItemBase2D の変数に KeyController 型の値が入っている時は、KeyController.Activate() が呼ばれる。
ItemBase2D の変数に CoinController 型の値が入っている時は、CoinController.Activate() が呼ばれる。
ItemBase2D の変数に HeartController 型の値が入っている時は、HeartController.Activate() が呼ばれる。
つまり、ItemBase2D の変数に入っている値によって、同じように Activate() を呼んでいるのに異なる処理が実行される。
これを多態性(ポリモーフィズム, polymorphism)という。
今回の授業ではごく一部しか扱わないので、教科書を見ておくこと。
- 多態性 - 同じ関数でも状況によって異なる処理をすること
- 隠蔽(できるだけ使わない)
- オーバーライド(よく使う)
「取るとジャンプ力がアップするアイテム」を作れ。ただし、アイテムの機能を実装するコンポーネントは ItemBase2D を継承して作り、既に ItemBase2D にある機能を重複させないこと。なお、アイテム用の画像は Sprites フォルダーに Shoes というスプライトがあるので、それを使ってよい。
- 『独習 C# 新版』
- 8.2 継承
- 8.3 ポリモーフィズム
paiza ラーニングの C#入門編8: さらにクラスを理解しよう の演習を全て正解する
- 合計 11 問あります
- 受講する(動画を見る)必要はありませんが、演習が解けない場合は動画を見て学んでもよいでしょう
- 動画は見ていなくても受講済みにしてしまって構いません
自分で作っているゲームに対して、継承・多態性を使った機能を追加する。
単純な例としては、アイテムや敵キャラクターなど「基本の挙動は同じだが、一部の機能が違う」ものが対象になりやすいでしょう。
提出方法: プロジェクトを github にプッシュし、リポジトリの URL を Slack で送信する。DM で送らずにチャンネルに送信すること。また、以下を付記すること。
- 実行するためにはどのシーンを実行すればよいか
- どのスクリプトでそれをやっているのか
- 以下のスクリプト名を教えてくれればよいです
- 基底クラス
- 派生クラス
- 多態性を使った呼び出しをしている場所
- 以下のスクリプト名を教えてくれればよいです