FC2ブログ
    05 «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.» 07

    ハルシオンシステムの気ままBlog

    株式会社ハルシオンシステムのメンバーが送る、UnityやらJavaやらの技術的話題から、自社開発のアプリの宣伝とかとかのブログです。ほんと気ままにいきたいと思います。更新日は毎週 月 木でっす!

     

    【ハルシオンブログ】UnityのUpdateで10フレームに1回とかで処理したいとき。 

    こんにちは。
    大坂です。

    UnityのUpdateで10フレームに1回とかで処理したいときのお話。
    「Time.deltaTime」を足しこんで何秒に1回処理とかもしてとかもよくやるんですが、何フレームに1回とかも簡単にできます。


    void Update()
    {
    if(Time.frameCount % 10 == 0)
    {
    // 処理
    }
    }


    って書くだけですね。
    上記だと10フレームに1回処理を行います。
    10のところを変えたら好きなフレーム数で処理してくれます。

    では今週もこれにてノシ

    Category: 開発日記(Unity)

    tb 0 : cm 0   

    【ハルシオンブログ】Unity+Admobの動画リワードではまったので、修正したよメモ 

    あつーい日が始まりましたね。
    とりあえず来週までずっと30度以上じゃないですか・・・・
    熱中症、日射病に気を付けてくださいまし。
    ほんと暑いのやですよねー


    UnityでAdmobを入れたんですが、リワードを受け取る処理でエラーがでたので、直してました。
    前動いてた気がしたんですけどね・・・・
    ちなみにAdmobのSDKは2022/6/27時点での最新です。

    GoogleMobileAds-v7.1.0

    【現象】
    リワードを受け取って動画を閉じるとアプリが落ちる。

    実機のエラーは特に分からず・・・・

    エラーはこんな内容。

    Exception in MessageQueue callback: handleReceiveCallback
    java.lang.Error: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***

    処理としては何をしていたかというと、画面AのメソッドAをAdmobManagerに渡して、リワードを受け取る時にメソッドAを実行という感じ。
    メソッドAでは、画面AのGameObjectとかTextをいじっていました。

    [画面A.cs]

    void OnClickViewReward() {
    AdmobManager.instance.ProcReawrd(GetReward);
    }

    void GetReward() {
    btnViewReward.gameObject.SetActive(false);
    btnClose.transform.GetComponentInChildren().text = "閉じる";
    gold += rewardValue;
    GameData.instance.Save();
    }



    [AdmobManager.cs]

    Action actionReward;

    private void LoadReward() {
    this.reward = new RewardedAd(ID);
    this.reward.OnUserEarnedReward += HandleUserEarnedReward;
    this.reward.OnAdClosed += HandleCloseAd;
    AdRequest request = new AdRequest.Builder().Build();
    this.reward.LoadAd(request);
    }

    ///
    /// リワード動画開始
    ///

    public void ProcReawrd(Action reward) {
    actionReward = reward;
    #if UNITY_ANDROID || UNITY_IOS
    if (this.reward.IsLoaded()) {
    this.reward.Show();
    }
    #endif
    }

    public void HandleUserEarnedReward(object sender, Reward args) {
    actionReward();
    }


    こんな感じだとダメらしい。

    GetRewardのはじめの
    btnViewReward.gameObject.SetActive(false);
    で、エラーがでてしまうようです。

    ちなみにこの行を消しても次の行で・・・・・

    OnUserEarnedRewardのタイミングでは動画の方がアクティブになっていて、UI周りとか触れないのかな?

    ってことで、次のようにしたら動きました。

    [AdmobManager.cs]

    Action actionReward;

    private void LoadReward() {
    this.reward = new RewardedAd(ID);
    this.reward.OnUserEarnedReward += HandleUserEarnedReward;
    this.reward.OnAdClosed += HandleCloseAd;
    AdRequest request = new AdRequest.Builder().Build();
    this.reward.LoadAd(request);
    }

    ///
    /// リワード動画開始
    ///

    public void ProcReawrd(Action reward) {
    isReward = false;
    isClose = false;
    actionReward = reward;
    #if UNITY_ANDROID || UNITY_IOS
    if (this.reward.IsLoaded()) {
    this.reward.Show();
    }
    #endif
    }

    public void HandleUserEarnedReward(object sender, Reward args) {
    isReward = true;
    }
    public void HandleCloseAd(object sender, EventArgs args) {
    isClose = true;
    }
    private void Update(){
    if(isReward && isClose){
    actionReward();
    isReward = false;
    isClose = false;
    }
    }


    リワード取得のタイミングと、閉じたタイミングでフラグを立てて、Updateで処理。

    なぜこのタイミングならできるのかは分かりませんが、できました。

    ということで、Unity + Admobの動画リワードではまったの巻でした。

    では、あでゅ~ノシ

    Category: 開発日記(Unity)

    tb 0 : cm 0   

    【ハルシオンブログ】Library/Search/propertyDatabase.dbなどのエラーが出た時 

    こんにちは。
    大坂です。

    たぶんUnityを強制終了した後にUnityを立ち上げたらこんなエラーが出てきたので、対処法です。

    The property database "Library/Search/propertyDatabase.db" is already opened.
    UnityEditor.EditorApplication:Internal_InvokeTickEvents ()
    The property database "Library/Search/propertyAliases.db" is already opened.
    UnityEditor.EditorApplication:Internal_InvokeTickEvents ()


    対象プロジェクトフォルダの「Temp」の中にある以下のファイルを削除するとエラーが出なくなります。


    何かのお役に立てば。
    ではではノシ

    Category: 開発日記(Unity)

    tb 0 : cm 0   

    【ハルシオンブログ】JSonUtilityを使うとクラスの中身とか簡単に見れたりもするよ? 

    蒸し蒸しして嫌な日が続きますね。
    梅雨もあと半月くらいでしょうか。
    湿気に弱い坂内っす。

    さて、Unityでこんなデータを作った時。

    [Blog20220620.cs]

    using System;
    using UnityEngine;

    public class Blog20220620 : MonoBehaviour
    {
    [System.Serializable]
    public class Chouka {
    public string place;
    public DateTime date;
    public FishData[] chouka;
    }

    [System.Serializable]
    public class FishData {
    public int no;
    public string name;
    public float length;
    }

    void Start() {
    Chouka chouka = new Chouka() {
    place = "根岸湾",
    date = DateTime.Parse("2022/06/20 11:50"),
    chouka = new FishData[]
    {
    new FishData(){
    no = 1,
    name = "アジ",
    length = 30.2f,
    },
    new FishData(){
    no = 2,
    name = "マダイ",
    length = 52.3f,
    },
    new FishData() {
    no = 2,
    name = "キス",
    length = 25.6f,
    }
    }
    };
    }
    }

    JsonUtilityを使うと、簡単に出力できます。
    (しってます?)

    これ書くだけ。


    var json = JsonUtility.ToJson(chouka, prettyPrint:true);
    Debug.Log(json);


    [blog20220620.cs]

    using System;
    using UnityEngine;

    public class Blog20220620 : MonoBehaviour
    {
    [System.Serializable]
    public class Chouka {
    public string place;
    public DateTime date;
    public FishData[] chouka;
    }

    [System.Serializable]
    public class FishData {
    public int no;
    public string name;
    public float length;
    }

    void Start() {
    Chouka chouka = new Chouka() {
    place = "根岸湾",
    date = DateTime.Parse("2022/06/20 11:50"),
    chouka = new FishData[]
    {
    new FishData(){
    no = 1,
    name = "アジ",
    length = 30.2f,
    },
    new FishData(){
    no = 2,
    name = "マダイ",
    length = 52.3f,
    },
    new FishData() {
    no = 2,
    name = "キス",
    length = 25.6f,
    }
    }
    };

    var json = JsonUtility.ToJson(chouka, prettyPrint:true);
    Debug.Log(json);
    }
    }



    これだけで出力できます。



    ほらこんな感じに・・・・・・
    floatのところなんかすごい数字入ってるんですが・・・・
    なんやこれ!

    でも、こうやって出力すると、ちゃんと25.6ってなるんですよね。
    Debug.Log(chouka.chouka[2].length);

    ってことで、データの中身を確認したい時とかにJsonUtilityで表示とかすると楽でいいですよ。って話でした。

    では、あでゅ~ノシ

    Category: 開発日記(Unity)

    tb 0 : cm 0   

    【ハルシオンブログ】画像のアスペクト比を一定にしながらサイズを変更する 

    こんにちは。
    大坂です。

    いろんな画面サイズを作っているときに画像のアスペクト比が崩れることがあります。
    そんな時に画像のアスペクト比を一定にしながらサイズを変更する方法です。
    Aspect Ratio Fitter」を使うとよいですね。
    ※リンクはAPI

    まずは何もつけないで画面サイズを変更するとこんな感じで、画像のアスペクト比が変わってしまいます。

    ※クリックすると動きます。

    アスペクト比を一定にしながらサイズを変更したい画像に「Aspect Ratio Fitter」コンポーネントを付けて、
    とりあえず「Envelope Parent」を設定。


    これで画面サイズを変えてみるとこんな感じでちゃんとアスペクト比を保持してくれます。

    ※クリックすると動きます。

    という感じで簡単にアスペクト比を変えずに画像サイズが変えられます。
    何かの時に使ってみてください。

    ではではノシ

    Category: Androidアプリ紹介

    tb 0 : cm 0   

    【ハルシオンブログ】UnityC#で文字列の結合ってStringBuilder使ってますか?どれくらいStringの結合と速度が違うのか測ってみた。 

    こんにちは。
    ブログかくのを忘れていた坂内っす。

    UnityC#で文字列の結合を行う際に、StringBuilderを使うといいって話よく聞きますよね。

    どれくらいいいのかちょっと確認してみました。


    1から10000の文字を結合する処理をstringの結合と、StringBuilderでの結合の2パターンで書いてみました。

    [Blog20220613.cs]

    using System.Text;
    using UnityEngine;

    public class Blog20220613 : MonoBehaviour
    {
    void Start()
    {
    System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
    // stringの結合
    sw.Start();
    string str = "";
    for (int i = 0; i < 10000; i++) {
    str += i.ToString();
    }
    sw.Stop();
    Debug.Log("string結合:" + str);
    Debug.Log(sw.ElapsedMilliseconds);

    sw.Reset();

    // StringBuilderでの結合
    sw.Start();
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < 10000; i++) {
    sb.Append(i.ToString());
    }
    sw.Stop();
    Debug.Log("StringBuilder結合:" + sb.ToString());
    Debug.Log(sw.ElapsedMilliseconds);
    }

    }



    上側がstring結合、下側がStringBuilderでの結合になります。
    これを実行した結果はこちら。


    やば・・・・・!?

    約47倍!?

    StringBuilder早すぎじゃないですかね?

    100回や500回とかの結合ならそこまで差はなさそうですが、1000回を超すと差がはっきりと出てきますね!

    文字列の結合なので、こんな感じでアルファベット並べたのを繰り返した場合、さらに差がはっきりと出ますね。


    using System.Text;
    using UnityEngine;

    public class Blog20220613 : MonoBehaviour
    {
    void Start()
    {
    System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
    // stringの結合
    sw.Start();
    string str = "";
    for (int i = 0; i < 10000; i++) {
    str += "abcdefghijklmnopqrstuvwxyz";
    }
    sw.Stop();
    Debug.Log("string結合:" + str);
    Debug.Log(sw.ElapsedMilliseconds);

    sw.Reset();

    // stringbuilderでの結合
    sw.Start();
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < 10000; i++) {
    sb.Append("abcdefghijklmnopqrstuvwxyz");
    }
    sw.Stop();
    Debug.Log("StringBuilder結合:" + sb.ToString());
    Debug.Log(sw.ElapsedMilliseconds);
    }

    }




    これ凄いですね。

    今後文字列の結合にはStringBuilderを使おうと心に決めました。

    では、あでゅ~ノシ

    Category: 開発日記(Unity)

    tb 0 : cm 0   

    【ハルシオンブログ】同じ文字列を連続してつなげたいとき 

    こんにちは。
    大坂です。

    文字列で★などを連続で指定個数つなげたいときのお話。
    forとかで指定個数分回してもいいのですが、普通に「new string」だけでできますね。

    コード

    // for で指定個数つなげる
    string test_1 = "";
    for(int i = 0; i < 3; i++)
    {
    test_1 += "★";
    }
    Debug.Log($"test_1:{test_1}");

    // new string を使用する
    string test_2 = new string('★', 5);
    Debug.Log($"test_2:{test_2}");


    結果


    簡単な話ですが知っていると少し楽に書けますね。
    ではまたノシ

    Category: 開発日記(Unity)

    tb 0 : cm 0   

    【ハルシオンブログ】デリゲートに格納されたメソッドをスレッドセーフに呼ぶ方法? 

    こんにちは。坂内っす。

    UnityでC#書いてる時にデリゲート使ってますか?
    デリゲートクラスがNullになってしまいエラーが出たりってことありませんか?

    そんな時はスレッドセーフな書き方があるらしいです。

    スレッドセーフとはなんぞや?
    「スレッドセーフ(Thread-safe)は、マルチスレッドプログラミングにおける概念である。あるコードがスレッドセーフであるという場合、そのコードを複数のスレッドが同時並行的に実行しても問題が発生しないことを意味する。特に、ある共有データへの複数のスレッドによるアクセスがあるとき、一度に1つのスレッドのみがその共有データにアクセスするようにして安全性を確保しなければならない。」

    Wikiより


    だそうです。

    こんなコードを書いた時、TestBのほうがスレッドセーフらしいですよ。

    [Blog20220606.cs]

    using UnityEngine;

    public class Blog20220606 : MonoBehaviour
    {

    public delegate void Callback();

    void Start()
    {
    TestA(ShowHello);
    TestB(ShowHello);
    TestA(null);
    TestB(null);
    }

    void ShowHello() {
    Debug.Log("Hello!!");
    }

    static void TestA(Callback callback) {
    Debug.Log("TestA");
    if (callback != null) {
    callback();
    }
    }
    static void TestB(Callback callback) {
    Debug.Log("TestB");
    callback?.Invoke();
    }
    }



    もちろんTestAの方でもnullの判定はしているので動きます。エラーはでません。

    Delegateは非同期処理とかでよく使われたりするということで、TestAのcallback()の時点でcallbackがnullになった場合(ifの後で)NullPointerExceptionが出てしまう可能性があるらしいです。
    そこでTestBのように 「callback?.Invoke()」という形にするとスレッドセーフになるようです。

    メモ程度ですが、デリゲートのスレッドセーフな実行方法についてでした。

    では、あでゅ~ノシ

    Category: 開発日記(Unity)

    tb 0 : cm 0   

    【ハルシオンブログ】ゲームオブジェクトかつアクティブでコンポーネントが有効かの確認 

    こんにちは。
    大坂です。

    ゲームオブジェクトがアクティブかつコンポーネントが有効かの確認をしたいとき。
    まぁ簡単で「isActiveAndEnabled」を使うだけです。

    こんな3個のパターンで確認
    ①ゲームオブジェクトが非アクティブ


    ②Imageコンポーネントが無効


    ③ゲームオブジェクトがアクティブかつImageコンポーネントが有効


    確認コード

    public Image img_1;
    public Image img_2;
    public Image img_3;

    void Start()
    {
    Debug.Log($"img_1:{img_1.isActiveAndEnabled}");
    Debug.Log($"img_2:{img_2.isActiveAndEnabled}");
    Debug.Log($"img_3:{img_3.isActiveAndEnabled}");
    }


    結果


    「③ゲームオブジェクトがアクティブかつImageコンポーネントが有効」の場合だけ「True」が返ってきますね。
    あんまり使いどころがないかもしれませんが、両方を一気に確認したいときに使えます。

    ではまたノシ

    Category: 開発日記(Unity)

    tb 0 : cm 0