質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

3回答

2750閲覧

[Unity]親クラスのGameObjectを子クラスから参照する方法が知りたい。

llemon

総合スコア17

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

0クリップ

投稿2018/12/01 07:22

Unityを使って開発をしています。

質問がいくつかあります。マル数字で示したところが質問のすべてです。

GameManager クラスを MoveManager クラスが継承しています。
GameManager クラスは以下のようにGameObjectをメンバ変数として持っています。

C#

1public class GameManager : MonoBehaviour { 2 public static GameObject player; 3 public GameObject mainCamera; 4}

子クラスではmainCameraの値を変化させます。

C#

1public class MoveManager : GameManager { 2 float stageMoveSpeed = 0.01f; 3 Transform trMainCamera; 4 Vector3 posTrMainCamera; 5 6 private void Start() { 7 trMainCamera = mainCamera.GetComponent<Transform>(); 8 posTrMainCamera = trMainCamera.position; 9 } 10 11 void Update() { 12 posTrMainCamera.x = posTrMainCamera.x + stageMoveSpeed; 13 trMainCamera.position = posTrMainCamera; 14 } 15}

この上記2つのスクリプトを一つのGameManagerというオブジェクトにAdd Componentしてみました。
この時、Inspector上はこのような表示となっております。
アタッチなし

1つ目の質問です。
①なぜMain CameraはGameManagerとMoveManagerの両方に出現するのでしょうか。継承している場合、子クラスのInspectorにも表示されるのでしょうか

2つ目の質問です。
②オブジェクトをアタッチできるようにInspector上に表示していますが、GameManager のplayer がInspector上に表示されないのはなぜでしょうか。Inspector上にアタッチできるような状態でオブジェクト名を表示させる条件は何なのでしょうか?(publicでstaticではないGameObjectの型ならなんでも表示されるのでしょうか)

この状態で、GameManagerのMainCamera にメインカメラをアタッチしてみましたが、MainCameraを取得できず実行時エラーとなってしまいました。
GameManagerにアタッチ

しかし、以下のようにMoveManagerにアタッチしてみたところ、MainCameraを取得できたため、エラーが起こりませんでした。
MoveManagerにアタッチ

③上記のように、MoveManagerにアタッチした時だけメインカメラを取得できた理由は何なのでしょうか?親クラスにオブジェクトをアタッチしているから、子クラスが参照できると思うのですが、なぜ親クラスでアタッチすると利用できず、子クラスでアタッチすると参照できるのでしょうか。そもそも子クラスにはGameObjectの宣言がないので、子クラス側でアタッチできるというのもよくわかりません。

④このように実装しているのも、よく利用するオブジェクトを一か所にまとめた設計にしたいというのが狙いなのですが、ほかに良い方法はありますでしょうか。

上記の①~④が質問です。
よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

(以下、継承元を「親クラス」、継承先を「子クラス」と称します)


そもそも継承というのは「あたかも親クラスのコードが子クラスにも存在するかのように振る舞う」というものです。
つまり(実際には書いてないけど)MoveManagerにもpublic GameObject mainCamera;が書かれているという扱いになります。
なので子クラスのインスペクターにもmainCameraが出現してます。



①と同様に、(実際には書いてないけど)MoveManagerにもpublic static GameObject player;が書かれているという扱いになっています。
が、static変数はインスペクター上に表示されません(継承とは関係無く常にそう)。
こいつはstatic変数が特殊な振る舞いをするからです。詳しくは「unity static」辺りでググってください。

ヒエラルキー上に表示されるのは、「private/static/constではない(要は普通のpublicな)変数」です。
型としてはGameObjectを始めとする各種のコンポーネント(Transform, Collider, Sprite等)、自作クラス、int/string/Vector3/配列/Listなど大抵なんでも表示されます。(よく使う中で表示されないのはDictionaryぐらい)



継承のルールその2として、「親クラスと子クラスは別の存在」です。
スクリーンショットの状態をイメージで言うと、
・1個のGameObjectがGameManagerという箱と、MoveManagerという箱、2つの箱を持っている
・GameManager箱の中にmainCameraカゴがある
・MoveManager箱の中にmainCameraカゴがある
という状態なので、「mainCameraカゴ」は同じ名前ですが全くの別物・別空間にある存在です。
(①で示したように、MoveManagerには実際には書いてないけどmainCamera変数を宣言したことになっている為)

MoveManagerのソースコードにあるこの行
trMainCamera = mainCamera.GetComponent<Transform>();
このmainCameraは、「MoveManagerのmainCamera」を指してます。
なので「GameManagerのmainCamera」がアタッチされていようがいまいが、
「MoveManagerのmainCamera」がアタッチされていなければ、nullに対しGetComponentしているのでエラーになります。



継承の用途が間違っているように思います。一箇所にまとめるだけなら継承を用いる必要はありません。

継承を用いるパターンとして考えられるのは、「概ね同じ挙動だけど一部が違うクラス」が欲しい場合です。
この辺は「継承」や「ポリモーフィズム」をググると出て来るので参考にしてください。

超ざっくりした例)
親クラス:Animal/子クラス:Dog、Cat
子クラスにSay(鳴く)メソッドを実装:Dogクラスなら"Bow"、Catクラスなら"Meow"と返す
参照を取る:Animal animal = DogかCatクラス as Animal;
鳴かせる:animal.Say();(鳴かせたい側のスクリプトでは、対象がDogかCatかを考える必要が無い)

投稿2018/12/01 09:35

sakura_hana

総合スコア11427

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sakura_hana

2018/12/01 09:38

これを短くまとめるとlen_soukoさんの回答になります。 (ダラダラ書いてる内に被っちゃいましたが折角なので投稿)
llemon

2018/12/02 03:16

一番理解しやすいと感じたのでベストアンサーにしました。 継承の考え方を見直します。 回答していただいた皆さん、助かりました。ご回答ありがとうございました。
guest

0

Unityは触ってないのでC#な質問の①限定で回答します

①なぜMain CameraはGameManagerとMoveManagerの両方に出現するのでしょうか。継承している場合、子クラスのInspectorにも表示されるのでしょうか

継承というのはそもそも親子関係のものではありません

C#

1public class MoveManager : GameManager

上記のコードで説明すると、
MoveManagerクラスはGameManagerクラスの追加機能版のクラスになります
その為、GameManagerクラスの機能はすべて持っています(ただしprivateなどのスコープによってアクセスできなくすることは可能ですが、意味が異なるので今回は考慮しません)
ですので、名前からの推測になりますが、GameManagerクラスがゲームの情報を管理し、MoveManagerクラスは移動に関する情報だけを管理するのであるならば継承する必要はありません
もしも管理する情報の意味的に親子関係であるのならば、GameManagerクラスのメンバにMoveManagerクラスのインスタンスを持つという形になるかと思います(実際の用途が分からない上にUnityでの作法も分からない為的外れかもしれませんが・・・)

投稿2018/12/01 09:09

len_souko

総合スコア1348

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

llemon

2018/12/02 03:14

ご回答ありがとうございます。 私のやりたいことに継承を利用することが間違っていることが分かりました。別の方法を考えます。
guest

0

①継承されたクラスのpublic変数は継承先にもアタッチ可能な仕様らしいです
②staticで初期化するので初期化のタイミングがわからなくなるためです
参考
③インスタンスを持たない変数からコンポーネントを取得しようとしているからです
以下のように書き換えてください

using System.Collections; using System.Collections.Generic; using UnityEngine; public class MoveManager : GameManager { float stageMoveSpeed = 0.01f; Transform trMainCamera; Vector3 posTrMainCamera; private void Start() { trMainCamera = GetComponent<GameManager>().mainCamera.GetComponent<Transform>(); posTrMainCamera = trMainCamera.position; } void Update() { posTrMainCamera.x = posTrMainCamera.x + stageMoveSpeed; trMainCamera.position = posTrMainCamera; } }

手法など 具体例

質問文に対して
親クラスのGameObjectを子クラスから参照する方法が知りたい

unityはコンポーネント指向なので一般的なオブジェクト指向の考え方とは違うので、コンポーネントを参照する場合は親クラスから参照しても意味ないきがします

投稿2018/12/01 08:49

編集2018/12/01 09:39
flan

総合スコア146

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

llemon

2018/12/02 03:12

ご回答ありがとうございます!私の疑問が解決しました。 コンポーネントの参照方法については別の方法を考えたいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問