Unityでのクラスのインスタンス化についてのあれこれメモ

概要

自分でクラスを作ったあと、別クラスから呼び出すときにインスタンス化しないといけない。
この時に、普通のC#みたいに、「newしてインスタンス化する」方法ではなく「unityのインスペクターから、オブジェクトをアタッチする」方法をとらないとうまくいかなかったことがあった。この違いがよくわからないのでちょっと確かめてみる。

実験

2つのサークルを作成。大きいサークルが親。小さいサークルが子オブジェクトになってる。
f:id:mani1414:20220102154424p:plain
f:id:mani1414:20220102152831p:plain

1: Unityのインスペクターからアタッチする場合。

こんなスクリプトを作成。親のサークルにスクリプトをアタッチ
Update関数で子のTestBool関数を呼び出すことで、子の_testFlag変数の論理をチェック。
子の_testFlag変数はFlagTrue()関数を子側のupdate関数で呼び出しまくっているので、trueになるはず。

public class Test : MonoBehaviour
{
    public TestChild testChild;
    bool TestFrag;
    // Start is called before the first frame update
    void Start()
    {
    }

    // Update is called once per frame
    void Update()
    {
         TestFrag=testChild.TestBool();
        Debug.Log("TestFragPrrent " + TestFrag);
    }
}

子のサークルには下スクリプトをアタッチ。

public class TestChild : MonoBehaviour
{
    public bool _testFlag=false;
    // Update is called once per frame
    void Update()
    {
        FlagTrue();
    }
    public bool TestBool()
    {
       return _testFlag;
    }
    private void FlagTrue()
    {
        _testFlag = true;
        Debug.Log("_testFlag " + _testFlag);
    }
}

また、Unity実行前にTestクラスのtestChild変数に、「Unityのインスペクター上から小さいサークルオブジェクトをアタッチする。」
*この動作が「unityのインスペクターから、オブジェクトをアタッチする」方法。
f:id:mani1414:20220102154123p:plain

結果

当然、子側のフラグはtrue。それをチェックしている親側のフラグもtrue。
f:id:mani1414:20220102154559p:plain

2:newしてインスタンス化する方法

親のスクリプトを少し変更。変更点は2点。
・testChildをプライベートにして、インスペクターからアタッチできないようにする。
・Start関数でTestChildをnewしてインスタンス化する。

public class Test : MonoBehaviour
{
    private TestChild testChild;
    bool TestFrag;
    // Start is called before the first frame update
    void Start()
    {
        testChild = new TestChild();
    }

    // Update is called once per frame
    void Update()
    {
        //testChild._testFlag = true;
        TestFrag=testChild.TestBool();
        Debug.Log("TestFragPrrent " + TestFrag);
    }
}

testChildはプライベートなのでインスペクターに現れずアタッチできないようになってる。
f:id:mani1414:20220102155415p:plain

結果

子側のフラグはtrueだが、親側はfalse。親側は子の_testFlag の論理を確認してそれを返すようにしていると思ったのに何で!?ってなった。
f:id:mani1414:20220102155514p:plain

その後いろいろ調べてみて・・・

まだうすーい理解だけども、UnityはMonoBehaviourから継承されているクラスは、起動時に自動でインスタンス化されるというような記事を読んだ。
ってことは、子オブジェクトにアタッチされたスクリプトのクラスは起動時にインスタンス化すでにされており、その後、親オブジェクトでnewしてインスタンス化したとしても、それは子オブジェクトにアタッチされたものとは別のインスタンスってことなんじゃないかと思った。おそらく、「unityのインスペクターから、オブジェクトをアタッチする」という動作は、起動時にすでにインスタンスされたそのものを、呼び出す側のスクリプトに紐づける動作なんじゃないか・・・。

終わり

理解しきれていないが、自分のメモとして残しておく。もしここにたどり着いた方、全く見当違いの可能性もあるので信じないでください。間違っていたら優しく教えていただけたら幸いです。

参考サイトメモ

内積を用いた四角判定
【Unity(C#)】Rayではなく内積(Vector3.Dot)で視線判定を行う - Qiita


ピクセルアートをボケさせない方法
baba-s.hatenablog.com

リジッドボディをつかった移動方法の種類と違い
https://www.f-sp.com/entry/2016/08/16/211214

クラス同士の依存関係の解消
https://qiita.com/saeki4n/items/22a276dcac9ef537ee25

インターフェイスを使った実例
qiita.com

fixedupdateとupdateの使い分けの話
biotech-lab.org

タイルのコライダーにプレイヤーのコライダーが引っかかるときの対処法
pikopiko.artm.jp

unityにおけるクラスのインスタンス化について。
https://teratail.com/questions/105405?link=qa_related_sp


getcompornentをプロパティで行うと、タイミングに依存されない話
https://baba-s.hatenablog.com/entry/2014/09/03/200639

コライダーの中心

キャラチップにコライダーを付けたらずれていた。

f:id:mani1414:20211202225045p:plain


コライダーの中心がどう決まるのか調べてみると・・・
pivotの位置で決まるらしいということが分かった。

pivotの位置は・・・
sprite eduterを押して
f:id:mani1414:20211202230223p:plain

下の画面のpivotに書かれている
f:id:mani1414:20211202230342p:plain

top centerになっていたのをcenterに直すと
コライダーが中心に移動したのでOK
f:id:mani1414:20211202230524p:plain

タイルマップの使い方メモ  タイルマップが小さいとき

タイルマップの使い方をよく忘れるのでメモ。



・基本的な使い方
unity-guide.moon-bear.com
やっぱりこのサイトはわかりやすい。初心者に優しい。


・タイルが小さいとき。グリットに合わせる。
こんな感じの時。
f:id:mani1414:20211114232247p:plain
上のサイトにもあるけど、タイルマップ作成元のspriteをクリックして
pixel per unitの数字の数字を変える。
f:id:mani1414:20211114232653p:plain

どう変えばよいかというと
タイルマップの1マスのpixelの値にすればよい。

タイルマップ1マスのpixelの値を確認するには、Sprite Editorをクリック。
f:id:mani1414:20211114234313p:plain
そのあと、WとHの値を見ればOKそう。
f:id:mani1414:20211114234854p:plain

メモリについての勉強2

以下3点について納得するために、診断ツールを使ってメモリの状態を確かめてみる。

・値型の変数に値を入れてもヒープ全然増えないよ。
・クラスをnewするとヒープで使用しているメモリが増えるよ。
・外部ファイルを読み込むとヒープメモリ増えるよ & 解放すると減るよ。

・確認するソースコード
簡単なクラスをnewしたり、外部ファイルを読み込んだりする。

 class Program
    {
        static void Main(string[] args)
        {
            //値型
            int a = 1;
            //参照型
            var test = new Test();
            //ファイルがあったら読み込む
            var filepath = @"C:\Users\jirou\Desktop\データ.txt";
           if (File.Exists(filepath))
            {
                using(var reader=new StreamReader(filepath, Encoding.UTF8))
                {
                    while (!reader.EndOfStream)
                    {
                        
                        var line = reader.ReadLine();
                        Console.WriteLine(line);

                    }
                }
            }

        }
    }

・診断ツールの表示
visual stadioのデバック⇒ウィンドウ⇒診断ツールの表示。
下のような画面が出てくる
f:id:mani1414:20211028233335p:plain


こっから確認結果
・値型
上、int a=1の前。下、int a=1後。
 メモリの結果は変わらず。ってかむしろ下がってる・・・
f:id:mani1414:20211029225842p:plain
・値型の変数に値を入れてもヒープ全然増えないよ。ってことですね。

・参照型
若干増えてる・・・
f:id:mani1414:20211029230114p:plain
+0.01kBをクリックすると・・・

f:id:mani1414:20211029230354p:plain
_20211028.testによってメモリが増えてることが分かった。
・クラスをnewするとヒープで使用しているメモリが増えるよ。ってことですね。


・外部ファイル読み込み
using~の部分。usingに入るとテキストファイルを読み込む。usingから出ると解放されるはず。
なのでメモリはusingに入ると増え、usingから抜けると解放されると思うが、どうなるか・・・

上、usingに入る前。下 usingに入った後。
f:id:mani1414:20211029230850p:plain
予想通りメモリが増えてる。増分をクリックすると・・・

stream readerとかfileStream等が増えている。
正直ここらへんの理解は十分ではないんだけど、ファイル読み込みに関係あるクラスだから
増えてるのか・・・
f:id:mani1414:20211029231000p:plain

そのあとwhile文を抜けて43kBまで増加
f:id:mani1414:20211029232147p:plain


その後、usingを抜けると・・・
f:id:mani1414:20211029231827p:plain

減った!減少分をクリックすると・・・

さっき増えたstream readerとかfileStream等が減少している。
f:id:mani1414:20211029232248p:plain

なるほど。外部ファイルを読み込むとヒープメモリ増えるよ & 解放すると減るよ。ってことですね。


まとめ
メモリが増えたり減ったりするさまを確認できました。
結果は当然事前に調べたとおりだったけど、自分で確認できたほうが理解につながる気がするし
診断ツールの使い方もなんとなくわかったのでまぁよかったかな。

メモリについての検証 1

何にも考えないでプログラムを組んでいくと
メモリを無駄に使って重くなったり、ゲームが動作しなくなったりするらしい。

メモリとかよくわからないので、プログラムを走らせているときに
実際にメモリが増えたり減ったりするさまを診断ツールなるものをつかって確認してみたいなと思います。
この手の内容は調べればでてきそうですが、自分で手を動かして確認したほうが理解が進むかなーと思ったのでやります。



まずはメモリのお勉強

大体こんな感じに理解した。
・メモリ領域にはスタック領域とヒープ領域なるものがあるらしい。

・ヒープ領域をたくさん使って解放されないままだと重くなる。メモリを無駄にしているということになる。

・値型だとスタック領域を使う。参照型だとヒープ領域を使う。クラスをインスタンスしたりするのは参照型なのでヒープを使う。

C#にはガベージコレクションなる機能があり、ヒープ領域にあるが、使わなくなったメモリを自動で解放してくれる。
 ただし、画像等ファイルを外部から読み込む場合は、ガベージコレクションで解放されないので自分で解放しないといけない。

わかりやすかった記事。
www.engineer-walk.com


自分の理解だと、以下3点のようになると思っているので
ほんとにそうなるか、診断ツールなるもので見てみようと思います。

・クラスをnewするとヒープで使用しているメモリが増えるよ。
・変数に値を入れてもヒープ全然増えないよ。
・外部ファイルを読み込むとヒープメモリ増えるよ & 解放すると減るよ。

眠いので確認はまた明日以降。

`

このブログについて

日々UnityやC#について勉強したことをメモするブログにします。

そのうち飽きるだろうけどできる限り続けよう。

 

このブログは技術記事とかではなくて、プログラミング初心者である私のメモや右往左往を日記として書いておくものになります。なので間違った内容が書かれていることも多いと思いますのでご了承ください。