// zlib/libpng License
//
// Copyright (c) 2018 Sinoa
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
using System;
using System.Collections;
using UnityEngine;
namespace IceMilkTea.Core
{
///
/// UnityのMonoBehaviourでしか得られないイベントを引き込むためのコンポーネントクラスです
///
internal class MonoBehaviourEventBridge : MonoBehaviour
{
// 以下メンバ変数定義
private WaitForEndOfFrame waitForEndOfFrame;
private Action onApplicationFocusFunction;
private Action onApplicationPauseFunction;
private Action onEndOfFrame;
///
/// 対象のゲームオブジェクトに MonoBehaviourEventBridge コンポーネントを新規アタッチを行い初期化を行います
///
/// アタッチする対象のゲームオブジェクト
/// 新規でアタッチした MonoBehaviourEventBridge のインスタンスを返します
/// targetGameObject が null です
public static MonoBehaviourEventBridge Attach(GameObject targetGameObject)
{
// nullなゲームオブジェクトを渡されたら
if (targetGameObject == null)
{
// そんなことは許さない
throw new ArgumentNullException(nameof(targetGameObject));
}
// 自身をアタッチして初期化をする
var component = targetGameObject.AddComponent();
component.waitForEndOfFrame = new WaitForEndOfFrame();
component.onApplicationFocusFunction = new Action(_ => { });
component.onApplicationPauseFunction = new Action(_ => { });
component.onEndOfFrame = new Action(() => { });
// コルーチンを開始する
component.StartCoroutine(component.DoEndOfFrameLoop());
// インスペクタから姿を消して返す
component.hideFlags = HideFlags.HideInInspector;
return component;
}
///
/// OnApplicationFocusを実行する関数を設定します
///
/// OnApplicationFocusを実行する関数
/// focusFunction が null です
public void SetApplicationFocusFunction(Action focusFunction)
{
// null が渡されたら
if (focusFunction == null)
{
// 許さない
throw new ArgumentNullException(nameof(focusFunction));
}
// 新しい関数を受け取る
onApplicationFocusFunction = focusFunction;
}
///
/// OnApplicationPauseを実行する関数を設定します
///
/// OnApplicationPauseを実行する関数
/// pauseFunction が null です
public void SetApplicationPauseFunction(Action pauseFunction)
{
// null が渡されたら
if (pauseFunction == null)
{
// 許さない
throw new ArgumentNullException(nameof(pauseFunction));
}
// 新しい関数を受け取る
onApplicationPauseFunction = pauseFunction;
}
///
/// WaitForEndOfFrameの継続関数を設定します
///
/// WaitForEndOfFrameの継続を行う関数
/// endOfFrameFunction が null です
public void SetEndOfFrameFunction(Action endOfFrameFunction)
{
// null が渡されたら
if (endOfFrameFunction == null)
{
// 許さない
throw new ArgumentNullException(nameof(endOfFrameFunction));
}
// 新しい関数を受け取る
onEndOfFrame = endOfFrameFunction;
}
///
/// コンポーネントが破棄される時の処理を実行します
///
private void OnDestroy()
{
// 関数の参照を殺す
onApplicationFocusFunction = null;
onApplicationPauseFunction = null;
onEndOfFrame = null;
}
///
/// ゲームアプリケーションがウィンドウなどプレイヤーのフォーカスの状態が変化したときの処理を行います
///
/// フォーカスを得られたときはtrueを、失ったときはfalse
private void OnApplicationFocus(bool focus)
{
// 本来実行したい関数を叩く
onApplicationFocusFunction(focus);
}
///
/// ゲームアプリケーションの再生状態が変化したときの処理を行います
///
/// 一時停止になったときはtrueを、再生状態になったときはfalse
private void OnApplicationPause(bool pause)
{
// 本来実行したい関数を叩く
onApplicationPauseFunction(pause);
}
///
/// UnityのWaitForEndOfFrameの処理を永遠に実行し続けます
///
/// WaitForEndOfFrame のインスタンスを常に返し続けます
private IEnumerator DoEndOfFrameLoop()
{
// 無限ループ
while (true)
{
// フレームの終端まで待機(描画の終端でゲームループの終端ではない)して関数を叩く
yield return waitForEndOfFrame;
onEndOfFrame();
}
}
}
}