チャックブログ

UnityやC#などをメインに公開していきます。C++も勉強始めました!

【Unity】全てのGameObjectについているタグの中から指定した文字列の一部でもあれば取得する方法

初めに

知恵袋にて「FindGameobjectsWithTagのような指定したTag名のオブジェクトをすべて取得するのではなく、指定した文字列が含まれているオブジェクトを取得する関数はないの?」という質問がありました。
自分もそういえば考えたことがなかったのでどうせなので作ってみようと思います。

サンプルコード

using System.Collections.Generic;
using UnityEngine;

public class Test: MonoBehaviour
{
    
    public List<GameObject> allObjectList;        //現在のシーンのActiveになっているすべてのオブジェクトを取得
    public List<GameObject> kunin;                //ちゃんと動作されているか確認用
    void Start()
    {
        // typeで指定した型の全てのオブジェクトを配列で取得しその要素数分繰り返す
        foreach (GameObject obj in FindObjectsOfType(typeof(GameObject)))
        {
            // シーン上に存在するオブジェクトならば処理.
            if (obj.activeInHierarchy)
            {
                //オブジェクトを格納
                allObjectList.Add(obj);
            }
        }
    }

    void Update()
    {
        //テスト用
        if (Input.GetKeyDown(KeyCode.A))
        {
            kunin = CheckTag("b",allObjectList);
        }
    }

    /// <summary>
    /// 渡したList<GameObject>の中にあるタグ名の中に指定した文字があればそれを返す
    /// </summary>
    /// <param name="_word">指定した文字</param>
    /// <param name="_list">ゲームオブジェクトを格納したList</param>
    /// <returns></returns>
    List<GameObject> CheckTag(string _word,List<GameObject> _list)
    {
        //リターン用のList
        List<GameObject> returnList=new List<GameObject>();
        //渡されたListの要素分処理
        foreach (GameObject obj in _list)
        {
            //Tagの中にその文字があるか判断
            if (obj.tag.Contains(_word))
            {
                //オブジェクトを格納
                returnList.Add(obj);
            }
        }
        return returnList;
    }
}

終わり

作って思ったんですが使いどころがちょっと難しいですねこれ。

【Unity】事前に決めた座標を行ったり来たりする方法

行ったり来たりする処理

身近で行ったり来たりする処理どうする?的な話題になったので自分なりに考えた処理

サンプルコード

    [SerializeField, Header("移動速度")]
    float speed = 5;

    [SerializeField, Header("感知できる距離")]
    float range = 0.5f;

    [SerializeField,Header("移動したい座標")]
    Vector3[] movePath = new Vector3[3];
    Vector3 direction;

    int pathValue = 0;                  //現在どのパスなのか
    int nextPathValue;                  //次の移動したいパス

    enum MoveType
    {
        MoveOn,
        Return
    }

    MoveType moveType;

    private void Start()
    {
        //初期位置を記憶しておく(配列の0番目)
        movePath[0] = transform.position;

        //次の座標のパス
        nextPathValue = 1;
        moveType = MoveType.MoveOn;
    }

    private void Update()
    {
        Move();
    }

    /// <summary>
    /// 動くよ
    /// </summary>
    void Move()
    {
        //移動する向きベクトルを作成
        direction = movePath[nextPathValue] - movePath[pathValue];
        //方向ベクトルを作成
        direction.Normalize();

        Debug.Log(pathValue +"  "+nextPathValue);

        //移動
        transform.position += direction * Time.deltaTime * speed;

        //目標地点に近づいたか評価
        if (CheckDistance(transform.position, movePath[nextPathValue], range))
        {
            //次のパスに移動先を変更
            NextDesignatedLocation();
        }
    }
    /// <summary>
    /// 範囲を指定してその範囲ないか調べる関数
    /// </summary>
    /// <param name="_myPos">自身の位置</param>
    /// <param name="_nextPos">次の移動位置</param>
    /// <param name="_range">半径</param>
    /// <returns></returns>
    bool CheckDistance(Vector3 _myPos, Vector3 _nextPos, float _range)
    {
        bool inRange = false;
        //targetの位置に近づいたらtrue
        if (Vector3.Distance(_myPos, _nextPos) <= _range)
        {
            inRange = true;
        }
        return inRange;
    }

    /// <summary>
    /// 次のパスに指定する
    /// </summary>
    void NextDesignatedLocation()
    {
        switch (moveType)
        {
            case MoveType.MoveOn:
                pathValue = nextPathValue;
                nextPathValue++;
                if (nextPathValue == movePath.Length-1)
                {
                    moveType = MoveType.Return;
                }
                break;
            case MoveType.Return:
                pathValue = nextPathValue;
                nextPathValue--;
                if (nextPathValue == 0)
                {
                    moveType = MoveType.MoveOn;
                }
                break;
            default:
                pathValue = nextPathValue;
                nextPathValue++;
                if (nextPathValue == movePath.Length - 1)
                {
                    moveType = MoveType.Return;
                }
                break;
        }
    }

まとめ

急いで書いたとはいえ汎用性がなさそうなものができてしまった…

【C++】値渡し、ポインタ渡し、参照渡しについてと自分が陥った穴

注意

この記事はC++初心者がインプットしたものをアウトプットしたものなのでもしかしたら間違いがあるかもしれませんご了承ください。

値渡し

サンプルコード

void test(int num)
{
    num++;
    std::cout << num << std::endl;
}


int main()
{
    int value = 1;

    std::cout << value <<std::endl;

    test(value);

    std::cout << value << std::endl;
}

実行結果

1
2
1

値渡しとは引数で渡した物のコピーを作成してそのコピーに変更を加えています。
なので関数の呼び出し元となったvalueの値は変更されません。

ポインタ渡し

サンプルコード

void test(int *num)
{
    *num+=10;
    std::cout << *num << std::endl;
}


int main()
{
    int value = 1;

    std::cout << value <<std::endl;

    test(&value);

    std::cout << value << std::endl;
}

実行結果

1
11
11

ポインタ渡しは変数のアドレスを渡すのでアドレスに直接書き込むことができます。
関数の呼び出し元の変数にも変化を与えることが可能です。

参照渡し

サンプルコード

void test(int &num)
{
    num+=10;
    std::cout << num << std::endl;
}


int main()
{
    int value = 1;

    std::cout << value <<std::endl;

    test(value);

    std::cout << value << std::endl;
}

実行結果

1
11
11

こちらはポインタ渡しと同様にtest関数で値を変更した際関数呼び出し元の変数も変更されます。
この記法で記述すると関数内で別の変数のように扱えるのでC#を先に学んでいた身だとこっちの方がわかりやすかったです。

陥った穴

配列を値渡しした際のできごと… サンプルコード

void test(int num[])
{
    num[0] = 10;
    std::cout << num[0] << std::endl;
}


int main()
{
    int value[3] = {0,1,2};

    std::cout << value[0] <<std::endl;

    test(value);

    std::cout << value[0] << std::endl;
}

実行結果

0
10
10

あれ?値渡ししたのに0,10,0って結果にならない…
このように値渡しをしてるのになぜか関数呼び出し元の変数も変化している…なんでだろうと悩んでいました。
どうも配列を値渡しするとポインタ渡しになるようです…まじかぁ

終わり

C++難しいですが、一つ勉強になりました。

【Unity】Unity2019 2DLight実装方法

Unity2019から実装された2DLightの実装方法

動作環境

Unity2019.2.0b9

実装までの流れ

PackageManagerからLightweight RPをインストール。 f:id:tilyakuda:20190729201731p:plain インストールしたら Create>Rendering>Lightweight Render Pipeline>Pipeline AssetCreate>Rendering>Lightweight Render Pipeline>2DRendererを作成。 f:id:tilyakuda:20190729202158p:plain f:id:tilyakuda:20190729202155p:plain 作成したらPipeline Assetで作成したものを一度クリックしてInspecdtorに表示 その後General>Renderer Type>Customを選択。 f:id:tilyakuda:20190729202522p:plain その後 Edit>ProjectSetting>GraphicsScriptable Render Pipeline Settingsに先ほど設定した Pipeline Assetをアタッチ。 f:id:tilyakuda:20190729202806p:plain これで実装ができました。

使用方法

通常のlightを生成させるところに新しく項目がでてきます。 f:id:tilyakuda:20190729203006p:plain

サンプル

5つあるうちの4つのlightサンプルです。 使用されていない1つのlightは画面全体に光を当てるものなので省略 f:id:tilyakuda:20190729203045g:plain f:id:tilyakuda:20190729213319p:plain

【C++】テンプレート完全に理解したぃ

初めに

C++のテンプレートを触ってみたい、テンプレートってなに?って人向けの記事となっています。 (ぶっちゃけ自分も最近知ったものなので完璧ではないような気がします)

例えば

こんな関数があったとします

int Add(int a,int b)
{
    return a + b;
}
float Add(float a, float b)
{
    return a + b;
}

両方とも引数と戻り値の型が違うだけで中身はやっていることが同じです、これ無駄じゃないですか?

そんな時こそテンプレート!

template<typename T>
T Add(T a, T b)
{
    return a + b;
}

int main()
{
    std::string str;

    str = std::to_string(Add(114, 514));
    printf("合計:%s\n", str.c_str());

    str = std::to_string(Add(114.0f, 514.0f));
    printf("合計:%s\n", str.c_str());
}

実行結果 f:id:tilyakuda:20190626112138p:plain こんな感じで一つの関数テンプレートでint型とfloat型の合計した数値を出すことができました。(例がなんかアレだけど気にしない) int float char string様々な型に対応しております。

intの時だけは別の処理にしたいんだけど?

可能です!

template<typename T>
T Add(T a, T b)
{
    return a + b;
}
template<>
int Add(int a, int b)
{
    return a * b;
}

int main()
{
    std::string str;

    str = std::to_string(Add(114, 514));
    printf("合計:%s\n", str.c_str());

    str = std::to_string(Add(114.0f, 514.0f));
    printf("合計:%s\n", str.c_str());
}

実行結果 f:id:tilyakuda:20190626114220p:plain こんな感じにint型が使われた時だけ乗算処理させてみました。

テンプレートはほかにも

  • 関数テンプレート
  • クラステンプレート
  • メンバテンプレート
  • エイリアステンプレート があります。

まとめ

テンプレート完全に理解した…ぃ

アクセス修飾子のおさらい

初めに

最近他人(プロ)のコードを見る機会があったのですが普段自分が使わないアクセス修飾子が見えて「あれ?これなんだっけ?」となったので改めおさらいを込めて記事にします。 (Unityで実験しています)

サンプルコード1

public class test : MonoBehaviour
{
    //どこからでもアクセスできる
    public int test1=1;

    //自身のクラスと継承したクラスならアクセスできる
    protected int test2=2;

    //外部のプロジェクトからアクセスできなくする
    internal int test3=3;

    //上の二をまとめたもの(正直これが一番よくわかってない)
    protected internal int test4=4;

    //このクラス内でしか使えない
    private int test5=5;
}

こんな感じに継承クラスを作成してみました。

継承してみた

f:id:tilyakuda:20190625114841p:plain
継承した結果
継承した結果、test1~test4までが呼び出せることが確認できます。

クラス参照してみた

f:id:tilyakuda:20190625115134p:plain
クラス参照
クラス参照したみた結果、test1,test3,test4の3つを参照することができました。protected は継承しないと見れないことがよくわかります。

まとめ

アクセス修飾子完全に理解したぃ

【C#】delegate(デリゲート)とevent(イベント)

初めに

delegate?event?なにそれ…」「名前は聞いたことあるけど使ったことない」という人向けの記事です。 (Unityでテストしています)

delegateってなに?

delegate(デリゲート)はメソッドを参照するための型です、C言語C++言語やったことある方なら関数ポインターみたいなものという認識でいいと思います。

eventってなに?

event(イベント)はdelegateのプロパティのようなものという認識で大丈夫です。

delegateを使ってみよう

delegateを作ってみましょう。

  //       ↓戻り値    ↓型名    ↓引数
    private delegate void    Del   ();
    Del del;

これでdelegate(デリゲート)の作成ができます。

次にこのdelegateにメソッドを追加してみたいと思います。 戻り値と引数が一致するメソッドしか登録できませんので注意してください。

      // メソッドを追加する場合+=      
    del += メソッド;
      // メソッドを削除する場合-=    
    del -= メソッド;
  private delegate void Del();
    Del del;
    void Start()
    {
        del += test;
        del += test2;
        del();
    }

    void test()
    {
        Debug.Log("呼び出されたよ");
    }
    void test2()
    {
        Debug.Log("こっちも呼び出されたよ");
    }

これでConsoleに"呼び出されたよ""こっちも呼び出されたよ"が表示されるはずです。

eventを使ってみよう

まずはeventを作ってみましょう。

//   ↓ここpublicにしてね
    public delegate void Del();
    public event Del delEvent=null;

public event Del delEvent=null;
Del : 登録したいデリゲート名
delEvent : 型名
これでeventを作成できました。

  public delegate void Del();
    public event Del delEvent=null;

    void Start()
    {
        delEvent += test;
        delEvent += test2;
        delEvent();
    }

    void test()
    {
        Debug.Log("呼び出されたよ");
    }
    void test2()
    {
        Debug.Log("こっちも呼び出されたよ");
    }

呼び出し方も登録の仕方もほぼ同じです。 ただeventを作成したクラス内でしかeventの呼び出しができません。 追加したり削除したりすることしか外部クラスはできなくなっています。 delegateだけですと外部からdelegateを実行できてしまうのでそれを阻止するためのeventです。