ユニティでデッドサイクルとカード死をどうやって検出しますか?
携帯電話/シミュレータでゲームが死んだらログ出力もなく、スタック情報もないし、バグもないので、イライラしますか?この記事では、私たちのプロジェクトでユニティカードの死を検出する方法を紹介します。おそらくあなたに似合うと思います。
原理を実現する
ほとんどの場合、ユニティはシングルスレッドと考えられます。これに基づいてユニティのシステム関数FixedUpdateでゲームの実行期間の総フレーム数を統計します。ユニティがカード死していないなら、Total Frameはずっと累積しています。もしある時間内にTotal Frameは変化しないなら、ユニティはもうカードが死んだと考えられます。
Unityのメインスレッドがすでにカードが死んでいる以上、もう一つのスレッドを使ってタイミングを合わせてunityのメインスレッドのTotalFrameが変化しないかどうかを確認する必要があります。
サンプルコード
私たちのゲームでは一般的にカードが死ぬ場合はタイマーの中にあります。私たちのタイマーはユニティのUpdateでタイマーのリストを駆動することによって、カードが死ぬと他のスレッドにタイマーで実行中の関数をプリントアウトして、カードの死の関数を特定できます。タイマーは、ユニティTimerのTimer.csを参照することができる。
同時にUnityのUpdateで複数のイベントを配布します。例えば、PreUpdate、Updateは問題が発生して、カードがそこに位置しやすくなります。
問題を例をあげて説明する
次に私たちが出会ったカード死の問題を例に挙げます。
死の循環
次のこの死はユニティではカードが死ぬが、NETではできない。NETではiがbyteの最大値255を超えるとiは0から始まる。
イベントシステムをブロックしました。
いくつかのシステムでUGUIのイベントシステムをブロックし、ユーザーの入力を受け入れることができなくなりました。この問題はユニティカードの死に分類されるべきではありません。
タイマーの追加を繰り返す
その理由は、下の階に同名のタイマーが制限されていないため、いくつかのロジックで誤って使用され、毎秒1つのタイマーが追加されています。タイマーの中のロジックが大きく、長い間終了しない場合、繰り返しタイマーを追加すると、ゲームの運行が遅くなります。
重複登録イベント
いくつかのインターフェースのリフレッシュ関数とコントローラ関数では、頻繁にイベントを繰り返し登録し、イベントを投げ出す際に同じ関数がN回呼び出されます。この問題はUnityのProfilerで関数の呼び出し回数がはっきりと見えます。
拡張
再帰的呼び出し
再帰的に呼び出し、Stck overflowに報告します。unityカードを死なせません。
なぜ無限再帰的に呼び出されたのですか?
これは、各方法の
この記事ではユニティで死のサイクルとカードの死を検出する記事について紹介していますが、ユニティの死のサイクルやカードの死の内容については以前の記事を検索したり、次の関連記事を見たりしてください。これからもよろしくお願いします。
原理を実現する
ほとんどの場合、ユニティはシングルスレッドと考えられます。これに基づいてユニティのシステム関数FixedUpdateでゲームの実行期間の総フレーム数を統計します。ユニティがカード死していないなら、Total Frameはずっと累積しています。もしある時間内にTotal Frameは変化しないなら、ユニティはもうカードが死んだと考えられます。
Unityのメインスレッドがすでにカードが死んでいる以上、もう一つのスレッドを使ってタイミングを合わせてunityのメインスレッドのTotalFrameが変化しないかどうかを確認する必要があります。
サンプルコード
using System;
using System.Threading;
using UnityEngine;
namespace KEngine
{
/// <summary>
/// unity
/// </summary>
public static class UnityThreadDetect
{
public static Thread _MainThread = System.Threading.Thread.CurrentThread;// unity
private static int check_interval = 3000;//
public static void Start()
{
new Thread(CheckMainThread).Start();
}
static void CheckMainThread()
{
long frame = 0;
while(!AppEngine.IsApplicationQuit)
{
frame = AppEngine.TotalFrame;
Thread.Sleep(check_interval);
if (frame == AppEngine.TotalFrame)
{
Log.LogToFile("unity thread dead,ThreadState:{0}",_MainThread.ThreadState);
if (AppEngine.IsApplicationFocus)
{
//todo report error
}
}
}
}
}
}
カードを捕獲して死ぬ方法名私たちのゲームでは一般的にカードが死ぬ場合はタイマーの中にあります。私たちのタイマーはユニティのUpdateでタイマーのリストを駆動することによって、カードが死ぬと他のスレッドにタイマーで実行中の関数をプリントアウトして、カードの死の関数を特定できます。タイマーは、ユニティTimerのTimer.csを参照することができる。
同時にUnityのUpdateで複数のイベントを配布します。例えば、PreUpdate、Updateは問題が発生して、カードがそこに位置しやすくなります。
問題を例をあげて説明する
次に私たちが出会ったカード死の問題を例に挙げます。
死の循環
次のこの死はユニティではカードが死ぬが、NETではできない。NETではiがbyteの最大値255を超えるとiは0から始まる。
public static void TesBadCode()
{
byte i = 0;
while (true)
{
i++;
}
}
現在私達が遭遇したほとんどの状況は論理コードにwhere(true) do xxx
と書かれています。その後、中にはbreakがありません。循環が永遠に下がらないことになります。イベントシステムをブロックしました。
いくつかのシステムでUGUIのイベントシステムをブロックし、ユーザーの入力を受け入れることができなくなりました。この問題はユニティカードの死に分類されるべきではありません。
タイマーの追加を繰り返す
その理由は、下の階に同名のタイマーが制限されていないため、いくつかのロジックで誤って使用され、毎秒1つのタイマーが追加されています。タイマーの中のロジックが大きく、長い間終了しない場合、繰り返しタイマーを追加すると、ゲームの運行が遅くなります。
重複登録イベント
いくつかのインターフェースのリフレッシュ関数とコントローラ関数では、頻繁にイベントを繰り返し登録し、イベントを投げ出す際に同じ関数がN回呼び出されます。この問題はUnityのProfilerで関数の呼び出し回数がはっきりと見えます。
拡張
再帰的呼び出し
再帰的に呼び出し、Stck overflowに報告します。unityカードを死なせません。
なぜ無限再帰的に呼び出されたのですか?
これは、各方法の
は限られています。超えたら、Stocoverflowに報告して、アプリケーションカードを死なせないからです。
public static void TesBadCode()
{
while (true)
{
TesBadCode();
}
}
締め括りをつけるこの記事ではユニティで死のサイクルとカードの死を検出する記事について紹介していますが、ユニティの死のサイクルやカードの死の内容については以前の記事を検索したり、次の関連記事を見たりしてください。これからもよろしくお願いします。