今回はUnityのJavascript、C#の継承を使って既存のキャラクター操作スクリプトを継承し、親クラスの機能はそのままに子クラスで新しく機能を取りつけたいと思います。
UnityのJavascrptの継承に関しては
を参照してください。
Javascriptを使ってプログラミングしている方はあまりクラスを意識せず作成している方が多いと思います。
ですがデフォルトでMonoBehaviourクラスを継承して1つのスクリプトが作られています。
UnityのJavaScriptで継承を行う方法
どんなスクリプトでも大元のMonoBehaviourクラスを継承して最低限の機能を保有しているわけですね。
さきほど記載したリンク先の記事にも書いてありますが、UnityのJavascriptで継承を行うには
1 2 3 4 | public class 子クラス extends 親クラス { } |
とします。
Start関数やUpdate関数等もクラス内に記載するといつも通りのスクリプトが組めます。
クラスを使っていない時はMonoBehaviourクラスを自動で継承していますが、あえて記載するとしたら親クラスのところをMonobehaviourにします。
1 2 3 4 5 6 7 8 9 10 | public class 子クラス extends Monobehaviour { function Start() { } function Update() { } } |
オブジェクト指向言語や継承について勉強したことがないと解りづらいかもしれませんが、親クラスを継承した子クラスは親クラスの機能をすべて持っている事になります。
つまり子クラスで親クラスを継承さえしていれば何も書かずともまったく同じ機能が子クラスで使えます。
さらに子クラスで新たに機能を追加していけるのでキャラクターの機能を拡張していく時に便利です。
C#の場合は
1 2 3 4 | public class 子クラス : 親クラス { } |
となります。
親クラスであるキャラクター操作スクリプトParentMoveの作成
文章だけだと解りづらいのでまずはキャラクター操作スクリプトParentMoveを作成し、キャラクターに取りつけます。
Animator等の設定はすでにされているとします。
Animatorに関しては
を参照してください。
JavaScriptのParentMoveスクリプトは以下のように作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | private var animator : Animator; private var cCon : CharacterController; private var x : float; private var y : float; private var velocity : Vector3; function Start () { animator = GetComponent(Animator); cCon = GetComponent.<CharacterController>(); velocity = Vector3.zero; } function Update () { // キャラクターコライダが接地、またはレイが地面に到達している場合 if(cCon.isGrounded) { // 地面に接地してる時は初期化 if(cCon.isGrounded) { velocity = Vector3.zero; // レイを飛ばして接地確認の場合は重力だけは働かせておく、前後左右は初期化 } else { velocity = new Vector3(0f, velocity.y, 0f); } x = Input.GetAxis("Horizontal"); y = Input.GetAxis("Vertical"); var input = new Vector3(x, 0f, y); // 方向キーが多少押されている if(input.magnitude > 0f) { animator.SetFloat("Speed", input.magnitude); transform.LookAt(transform.position + input); velocity += input.normalized * 2f; // キーの押しが小さすぎる場合は移動しない } else { animator.SetFloat("Speed", 0f); } } velocity.y += Physics.gravity.y * Time.deltaTime; cCon.Move(velocity * Time.deltaTime); } // Unity実行時からの経過時間 function Show() { Debug.Log("Parent:" + Time.time); } // オブジェクトの名前を返す function GetObjectName() { Debug.Log("ObjectNameIs " + gameObject.name); } |
移動キーが押された時にキャラクターをその方向に向かせ移動させる機能になります。
Unityの実行時からの経過時間を表示するShow関数を定義しています。
C#のParentMoveは
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | using UnityEngine; using System.Collections; public class ParentMove : MonoBehaviour { private Animator animator; private CharacterController cCon; private Vector3 velocity; [SerializeField] private float walkSpeed = 1.5f; void Start () { animator = GetComponent<Animator>(); cCon = GetComponent<CharacterController>(); velocity = Vector3.zero; } public virtual void Update () { // キャラクターコライダが接地、またはレイが地面に到達している場合 if(cCon.isGrounded) { velocity = Vector3.zero; var input = new Vector3(Input.GetAxis("Horizontal"), 0f, Input.GetAxis("Vertical")); // 方向キーが多少押されている if(input.magnitude > 0f) { animator.SetFloat("Speed", input.magnitude); transform.LookAt(transform.position + input); velocity += input.normalized * walkSpeed; // キーの押しが小さすぎる場合は移動しない } else { animator.SetFloat("Speed", 0f); } } velocity.y += Physics.gravity.y * Time.deltaTime; cCon.Move(velocity * Time.deltaTime); } // Unity実行時からの経過時間 public virtual void Show() { Debug.Log("Parent:" + Time.time); } public virtual void GetObjectName() { Debug.Log("ObjectNameIs " + gameObject.name); } } |
となります。
親クラスParentMoveを継承して子クラスChildMoveを作成
ParentMoveスクリプトを継承するクラスChildMoveクラスを作成します。
JavaScriptは以下のように作ります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | public class ChildMove extends ParentMove { // Update関数内で親クラスのUpdate関数の後に別の処理を追加 function Update() { super.Update(); if(Input.GetKeyDown("p")) { super.Show(); // Cキーを押した時は子クラスのShow関数を表示 } else if(Input.GetKeyDown("c")) { Show(); } else if(Input.GetKeyDown("g")) { GetObjectName(); } } // 呼び出されるとUnity実行時からの時間を表示する function Show() { Debug.Log("Child:" + Time.time); } } |
子クラスであるChildMoveは親クラスを継承する子クラスとして作成します。
(子クラス名はスクリプト名と同じ名前にする必要があります)
子クラスにも親クラスと同じShow関数を作成します。
Update関数内では親クラスのUpdate関数を
super.Update()
として呼び出し、その後処理を追加しています。
Pキーが押されたら親要素のShow関数を実行し、Cキーが押されたら子クラスのShow関数を実行しています。
親クラスを継承してみて面白いのは、親クラスであるParentMoveはクラス形式で作成していないスクリプトにもかかわらず子クラスで継承元として使用出来ている事です。
クラス形式で作成してこなかったスクリプトも継承出来るのでありがたいですね!
C#のChildMoveは
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | using UnityEngine; using System.Collections; public class ChildMove : ParentMove { // Updateに新しい処理を追加する public override void Update () { base.Update (); if (Input.GetKeyDown ("p")) { base.Show (); } else if (Input.GetKeyDown ("c")) { Show (); } else if(Input.GetKeyDown("g")) { GetObjectName(); } } public override void Show () { Debug.Log ("Child:" + Time.time); } } |
となります。
JavaScriptでは親クラスのメソッドはsuperで呼び出していましたが、C#だとbaseで呼び出します。
これで継承が完了です。
親クラスであるParentMoveでキャラクターを移動する機能を記述していますが、子クラスであるChildMoveでは移動処理は一切記述していません。
GetObjectNameメソッドはParentMoveスクリプトにしかありませんが、ChildMoveから呼び出しても実行出来ます。
キャラクターにChildMoveを取りつけてください。
継承したキャラクター操作スクリプトChildMoveで動くかどうか確認
これでちゃんとキャラクターが動くのかどうかUnityを実行して試してみましょう。
↑のようにキャラクターが動きました。
PキーやCキーを押して親クラス、子クラスのShow関数が呼ばれるか確認してください。
Unityの継承を利用してみて思う事
いやぁ継承は便利ですね!
継承を使う利点としては親クラスのプロパティや機能を持っている事です。
なのでただ歩かせるだけのキャラクター用に移動スクリプトを記述して、攻撃が出来るキャラクター用のスクリプトを移動スクリプトから継承し攻撃機能を拡張して作る。
といったように親の要素を継承し、かつ拡張していける所です。
子クラスでは親クラスと同じ関数名で処理を書いて親クラスの関数を上書き(厳密には親クラスの関数を呼べるので上書きではない)した処理が書けるのも便利ですね。
といいつつ、わたくし自身は継承を使っていないんですが・・・・(^_^;)
大規模なゲームとか作成するとなると後々便利になってくるんだと思います・・・・(-.-)