概要
00、10、13 を実行している場合は、10 を実行することを検討してください。
11、12はダウンロードされず、その時この2つは00、10と間違えられて
UniRxを使用してしまいました
フレームワークには 2
00 Unity ゲーム フレームワーク構築 2019 年第 1 四半期 C# のコア知識と簡単な Manager Of Manager フレームワーク構築 120 レッスン 01 Unity
ゲームフレームワーク構築 2019 年第 2 四半期モジュール/システム設計、命名、テスト (リソース管理/ホット アップデート) 133 レッスン
QFramework加上简介有4个
总共是6个
10 QFramework 使用指南 91课数(2个示例,备忘录和魔塔)【免费】【里面的示例是文章主题内容】
(这是sik学院视频下的资料,QF有点老了,也有一些报错。不建议用,建议到https://github.com/liangxiegame/QFramework下载最新的,里面例子,教程文档什么都有。)
11 框架搭建 决定版:架构演化(第一季) 31课数
12 框架搭建 决定版:应用篇(第二季) 51课数
13 框架搭建 决定版:理论强化篇(第三季) 53课数
名前
主に実際のサンダルの使い方に依存します
プライベート
mXxx
m_Xxx
直接小文字の xxx
パブリック
大文字 Xxx
----------------------------------------------------
00 第 1 四半期 C# のコア知識と簡単な Manager Of Manager フレームワーク構築
MsgDispatcher を使用して MonoBehavior にメッセージを送信する
/****************************************************
文件:Demo_202305032353.cs
作者:lenovo
邮箱:
日期:2023/5/3 23:53:10
功能:
*****************************************************/
using System;
using UnityEngine;
public class Demo01_202305032353 : MonoBehaviour
{
void Start()
{
MsgDispatcher.Register("KillEnemy",OnEnemyKilled);
MsgDispatcher.Send("KillEnemy","赵云");
//
MsgDispatcher.UnRegister("KillEnemy", OnEnemyKilled);
MsgDispatcher.Send("KillEnemy", "赵云");
//
this.Delay(5f, () => {
Debug.Log("5秒真男人"); });
}
private void OnEnemyKilled(object obj)
{
Debug.LogFormat("{0}KillEnemy", obj );
}
}
メッセージ MonoBehaviourMsg (MonoBehaviour に組み込まれた MsgDispatcher)
/****************************************************
文件:Demo_202305032353.cs
作者:lenovo
邮箱:
日期:2023/5/3 23:53:10
功能:
*****************************************************/
using System;
using UnityEngine;
public class Demo02_202305032353 : MonoBehaviourMsg
{
void Start()
{
this.Delay(5f, () => {
Debug.Log("5秒真男人"); });
//
RegisterMsg("AmbushEnemy", OnEnemyAmbushed);
SendMsg("AmbushEnemy", "孙膑");
//
RegisterMsg("DefendEnemy", data => Debug.LogFormat("{0}DefendEnemy", data));
SendMsg("DefendEnemy", "郝昭");
}
private void OnEnemyKilled(object obj)
{
Debug.LogFormat("{0}KillEnemy", obj );
}
private void OnEnemyAmbushed(object obj)
{
Debug.LogFormat("{0}AmbushEnemy", obj);
}
protected override void OnBeforeDestroy()
{
}
}
----------------------------------------------------
01 第 2 四半期モジュール/システム設計、命名、テスト (リソース管理/ホット アップデート)
バグ TestFramework エラー
これら 2 つの
フォルダー Tests を追加し、パッケージ TestFramework を追加しましたが、それでもエラーが報告されました。最初に単純に削除しました。
ResMgr.LoadSync
using UnityEngine;
namespace QFramework
{
public class UIXXXPanel : MonoBehaviour
{
#if UNITY_EDITOR
[UnityEditor.MenuItem("QFramework/Example/9.UIXXXPanel", false, 9)]
static void MenuItem()
{
UnityEditor.EditorApplication.isPlaying = true;
new GameObject("UIXXXPanel").AddComponent<UIXXXPanel>();
}
#endif
[SerializeField] AudioClip coinClip;
[SerializeField] AudioClip homeClip;
[SerializeField] AudioClip bgClip;
ResLoader mResLoader = new ResLoader();
private void Start()
{
coinClip = LoadAudioClip("coin");
homeClip = LoadAudioClip("home");
bgClip = LoadAudioClip("coin");
//
OtherFunction();
}
private void OtherFunction()
{
bgClip = LoadAudioClip("coin");
}
private void OnDestroy()
{
mResLoader.ReleaseAll();
}
AudioClip LoadAudioClip(string path)
{
return mResLoader.LoadSync<AudioClip>("resources://"+path);
}
}
}
ResMgr.LoadAsync + コールバック
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace QFramework
{
public class ResMgrExample : MonoBehaviour
{
#if UNITY_EDITOR
[UnityEditor.MenuItem("QFramework/Example/10.ResMgrExample", false, 10)]
static void MenuItem()
{
UnityEditor.EditorApplication.isPlaying = true;
new GameObject("ResMgrExample").AddComponent<ResMgrExample>();
}
#endif
ResLoader mResLoader = new ResLoader();
[SerializeField] AudioClip audioClip1;
[SerializeField] AudioClip audioClip2;
[SerializeField] GameObject go;
private IEnumerator Start()
{
yield return new WaitForSeconds(2.0f);
mResLoader.LoadAsync<AudioClip>(
assetName: "resources://coin",
onLoaded: coinClip =>
{
Debug.Log(coinClip.name);
Debug.Log(Time.time);
}
);//这块是回调,所以不一定比后面快
Debug.Log(Time.time);
yield return new WaitForSeconds(2.0f);
audioClip1= mResLoader.LoadSync<AudioClip>("resources://home");
yield return new WaitForSeconds(2.0f);
go=mResLoader.LoadSync<GameObject>("resources://HomePanel");
audioClip2= mResLoader.LoadSync<AudioClip>("resources://Audio/coin");
yield return new WaitForSeconds(5.0f);
mResLoader.ReleaseAll();
}
}
}
スターディレクトリ.CreateDirectory
/// <summary>文件夹有就好,没有就创建</summary>
public static void Folder_New(string path)
{
if (Directory.Exists(path) == false) //输出path
{
Directory.CreateDirectory(path);
}
}
スター BuildPipeline.BuildAssetBundles
/****************************************************
文件:AB.cs
作者:lenovo
邮箱:
日期:2023/5/6 9:41:45
功能:
*****************************************************/
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using Random = UnityEngine.Random;
public static class AB
{
public static void Build(
string outputPath,
BuildAssetBundleOptions option = BuildAssetBundleOptions.ChunkBasedCompression
)
{
BuildPipeline.BuildAssetBundles
(
outputPath,
option ,
EditorUserBuildSettings.activeBuildTarget
);
AssetDatabase.Refresh();
}
}
パッケージ化時にバグ「MenuItemAttribute」が見つかりませんでした
タイプまたは名前空間名 'MenuItemAttribute' が見つかりませんでした。
報告されたエラーは AB パッケージであり、エラーはパッケージのスクリプトにジャンプするように報告されました。
バグテスト用の dll リファレンス
この Alt+Enter で VS エラーは解決できますが、Unity エラーはまだ残っています。
using NUnit.Framework;
using UnityEngine;
namespace QFramework
{
public class NewBehaviourScript : MonoBehaviour
{
#if UNITY_EDITOR
[UnityEditor.MenuItem("QFramework/Playground")]
private static void Test()
{
}
[Test]
public void Playmode()
{
Debug.Log(HotUpdateMgr.Instance.GetLocalResVersion());
}
#endif
}
}
Unity に参照がありません
オリジナルにはこの2つがあります
バグ「EditorUserBuildSettings」が存在しません
タイプまたは名前空間名「EditorUserBuildSettings」が名前空間「UnityEditor」
アセンブリに存在しないため、エディターがチェックされます。
ここでは、Common という新しいアセンブリを作成し、いくつかのスクリプトをコピーしようとしましたが、その時点では Common アセンブリはエディターをチェックしていませんでした。
TestFrameworkを見る
TestFramework をインストールし、すべてのケースをインポートします (現時点では 1.3.4 のみにケースがあります)
ケース 2 でテストを開始できます
ケース 02 演習 1_ 解決策
主脚本
namespace MyExercise_1s
{
public static class MyMath
{
public static int Add(int a, int b)
{
return a + b;
}
public static int Subtract(int a, int b)
{
return a - b; // Fixed
}
}
}
メインスクリプトのテスト
using MyExercise_1s;
using NUnit.Framework;
namespace Tests_1s
{
public class MyMathTests
{
[Test]
public void AddsTwoPositiveIntegers()
{
Assert.AreEqual(3, MyMath.Add(1, 2));
}
[Test]
public void AddAPositiveAndNegativeInteger()
{
Assert.AreEqual(1, MyMath.Add(3, -2));
}
[Test]
public void SubtractAPositiveInteger()
{
Assert.AreEqual(3, MyMath.Subtract(5, 2));
}
[Test]
public void SubtractANegativeInteger()
{
Assert.AreEqual(7, MyMath.Subtract(5, -2));
}
}
}
Sandals のバグ (その中のフォルダー) をテストします。
アセンブリ設定
ここでは、ケース 02 のアセンブリをコピーして名前を変更し
、エディター ファイル シェルフの下の [エディター] にチェックを入れるだけです。
アセンブリ設定が異なります
他のファイル棚の下にあるものをチェックします。
アセンブリ設定は同じです
上記の設定ではまだエラーが報告されていません (V0_0_4 が参照する UnityEditor.TestRunner に問題があるのではないかと盲目的に推測しています)
Sandal のパッケージを直接インポートするとエラーが報告されます。これがこのリファレンスの問題です。
V0_0_4
using UnityEngine;
using UnityEditor;
using UnityEngine.TestTools;
using NUnit.Framework;
using System.Collections;
namespace QFramework
{
public class V0_0_4
{
class SingletonTestClass : Singleton<SingletonTestClass>
{
private SingletonTestClass() {
}
}
[Test]
public void SingletonTest()
{
var instanceA = SingletonTestClass.Instance;
var instanceB = SingletonTestClass.Instance;
Assert.AreEqual(instanceA.GetHashCode(), instanceB.GetHashCode());
}
}
}
V0_0_4編集者
#if UNITY_EDITOR
using NUnit.Framework;
namespace QFramework
{
public class V0_0_4
{
class MonoSingletonTestClass : MonoSingleton<MonoSingletonTestClass>
{
}
[Test]
public void MonoSingeltonTest()
{
var instanceA = MonoSingletonTestClass.Instance;
var instanceB = MonoSingletonTestClass.Instance;
Assert.AreEqual(instanceA.GetHashCode(), instanceB.GetHashCode());
Assert.AreEqual(instanceA.name, "MonoSingletonTestClass");
}
}
}
#endif
概要 テストフォルダーが実行される
バグは「EmbeddedLinux」をサポートしていません。
"EmbeddedLinux",报错不支持,
ウォッチサンダルの遊び場(フォルダーが入っています)
アセンブリを修正して、そのリファレンスに従ってjsonを置くのも課題ですが、
どこに置くか、内容は何か、リファレンスを自分で確認してください
{
"Version":999
}
using NUnit.Framework;
using UnityEngine;
namespace QFramework
{
public class NewBehaviourScript : MonoBehaviour
{
#if UNITY_EDITOR
[UnityEditor.MenuItem("QFramework/Playground")]
private static void Test()
{
}
[Test]
public void Playmode()
{
Debug.Log(HotUpdateMgr.Instance.GetLocalResVersion());
}
#endif
}
}
バグ「MenuItem」が見つかりませんでした
00 プログラムと設定にはエディターは含まれません
00 ルートディレクトリに置きます
バグ ObsoleteUnityEditor.BuildTarget
ウォッチサンダルのアセットバンドルの例
なお、
01 の 2 つの AB パッケージは 6、02 の
2 つのパッケージ方法は 1、4 で結果は同じで、繰り返しのパッケージは自動的に上書きされます。03 パッケージは2 が
チェックできないことが前提です。
バグがパッケージをインポートした時刻
私はパッケージが最初にインポートされた時刻を常に認識しており、その後のエクスポートでも開始時刻のままです
。
private static string GeneratePackageName()
{
// return "QFramework_" + DateTime.Now.ToString("yyyyMMddHHMM");///注意年小写的yyyy
return "Common_" + DateTime.Now.ToString("yyyyMMddHHmm");///注意年小写的yyyy
}
バグ 一部の Editor クラスが認識されない
同じスクリプトの一部を独自の別のアセンブリにコピーしました。以下の図に示すように、エラーが報告されます。これら 3 つのスクリプトを最も外側のエディターにドラッグするのが正常です。
後で、これは #UNITY_EDITOR (MenuItem のラップ) に問題があることが判明しました
。。。
その理由は、Unity がアセンブリ内のエディター内のスクリプトを認識できないため、 #UNITY_EDITOR を手動で追加する必要があると盲目的に推測しているためです
。。。
Sandal は名前空間を手動で直接書き込み、アセンブリ メソッドを使用しないため、元のバージョンを直接ドラッグする必要はありません。
----------------------------------------------------
13 フレームワーク構築決定版:理論強化(シーズン3)
----------------------------------------------------
10 はじめに QFramework ユーザーガイド
01 優れたチェーン プログラミング スタイル (コールバック、タイミング)
02 アクション => 解像度 => UI (後者は前者に基づいています)。対応して、Example (例)、Action => Res => UI とライブラリがあります。
私がやったことを修正する
01 コメントを書きます (Unity コードはコメントを単独で書くことができないため、不親切です。図 1 に示すように、コメントとコードの分離が xml によって実現されている場合でも、説明するためにマウスを移動する限り)。 02 拡張機能からの抜粋 (フレームワークは一時的に使用されます。拡張機能はコピーが簡単で、私の拡張機能に統合されます。これは、独自の拡張機能の整理でもあります (エラーを報告せずにこのプロジェクトにドラッグします)
)
2017.3.xxx を見る
2017.3 あたりのバージョンを直接使用すると、エラーは報告されず、実行に失敗し、DoTween パネルが自動的にポップアップします。
しかし、それでもこのエラーがスローされます
バグ 2020.3.23f1c1
変更により Common ライブラリが導入されます
こんな感じで、自分のライブラリを使いたくて仕方がありません。
namespace QFramework.Example
{
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;
public class DOTweenExample : MonoBehaviour
{
Button mBtnMove;
GameObject mCube;
void Start ()
{
mCube = GameObject.Find("Cube");
//mBtnMove = transform.Find("BtnMove").GetComponent<Button>();
//mBtnMove.onClick.AddListener(() => { mCube.transform.DOMoveX(5, 1f); });
mBtnMove = transform.FindTop("Canvas").GetButtonDeep
(
"BtnMove"
,() => {
mCube.transform.DOMoveX(5, 1f); }
);
}
}
}
バグアセンブリ設定
自動生成された CSharp および Editor プロジェクトを直接インポートして使用しても問題ありません。図1。
ただし、組み込みライブラリをインポートし、それを含むアセンブリを設定する必要があります (QFramework の他のアセンブリの設定を見てください。RootName が感謝しているように見えるかどうかは関係ありません)。図2。
主な理由は、制限する必要がある同じ名前のクラスが存在することです。詳細は次の記事をご覧ください
バグ ResMgr、UIMgr など、2 つのアセンブリ間の名前の競合
使用するResMgrはQFrameworkのシングルトンクラスなので型ではなく(これが原因かどうかは不明)、xxx=xxxを使う形式は使えない(これは客観的な存在なので追加しても無駄)ので、QFramework.ResMgrに限定するしかありません。
バグプロジェクトモジュール識別エラー
サークル内(見つかりません)
Assets/QFramework/Framework/3.EditorToolKit/Editor/UnityEditorRushTools/CustomHierarchy.cs
が再インポートされますが、これは正常で問題ありません。
エラーが報告された 5 か所の半分をコメントアウトします。
これら 5 つは Unity2018 で非推奨になりました。しかし、同様の代替品が見つかりませんでした
Assets/QFramework/Framework/3.EditorToolKit/Editor/UnityEditorRushTools/CustomHierarchy.cs
私は TODO をマークしました。図1
。。。
図 2 に示すように、Unity2017 はまだ見つかりますが、
Unity2020 は見つかりません (少なくとも Obsolute が与えられます)
マニュアルには期限切れの
NetworkIdentityが表示されます
無駄なVSキャッシュの削除
無駄にILCppに変更
したがって、デフォルトの Mono に戻します
Bug Unity はエラーを報告しませんでしたが、VS はエラーを報告しました。でも走れる
1 つを切り取るだけで、図 2 に示すように参照関係が存在します。
概要を見る
01 アセンブリ設定、内部の他のアセンブリを参照して設定する
02 名前の競合、制限を追加する、ResMgr、UIMgr と競合する
03 5 廃止されたステートメント、一時的にコメントアウトする
バグ 常に存在するバグ
5 つの古い文章を再インポートしてコメントします。
その他のエラーは見つかりません。どのバージョンであっても報告されるエラーは 1 つだけです
バグ MonoComplier.Tick
アセンブリの追加や削除を変更すると、処理バーが何度もスタックしてしまいました。
コンパイルエラーです。タスク マネージャーは強制的に終了することしかできない可能性が高く、次回 EnterSafeMode で選択パネルに入るときは、
プロジェクトの構造を見る
01 ディレイ
3 つのタイミング書き込みメソッド、2 つの開始コルーチン、および 1 つのメインスレッド。
最下層は StartCoroutine
namespace QFramework.Example
{
using UnityEngine;
public class DelayNodeExample : MonoBehaviour
{
private DelayAction mDelay3s = DelayAction.Allocate
(
3.0f, () => {
Log.I("延时 3s");}
);
void Start()
{
this.Delay
(
1.0f, () => {
Log.I("延时 1s");}
);
var delay2s = DelayAction.Allocate
(
2.0f, () => {
Log.I("延时 2s");}
);
this.ExecuteNode(delay2s);
}
private void Update()
{
if (mDelay3s != null
&& !mDelay3s.Finished
&& mDelay3s.Execute(Time.deltaTime)
)
{
Log.I("Delay3s 执行完成");
}
}
}
}
02
using UnityEngine;
namespace QFramework.Example
{
public class EventNodeExample : MonoBehaviour
{
private EventAction mEventNode2 = EventAction.Allocate(
() => {
Log.I("event 3 called"); },
() => {
Log.I("event 4 called"); }
);
private void Start()
{
var eventNode = EventAction.Allocate(
() =>{
Log.I("event 1 called"); },
() =>{
Log.I("event 2 called"); }
);
this.ExecuteNode(eventNode);
}
private void Update()
{
if (mEventNode2 != null
&& !mEventNode2.Finished
&& mEventNode2.Execute(Time.deltaTime))
{
Log.I("eventNode2 执行完成");
}
}
}
}
ResKitExample.Audio
AB パッケージの報告は依然としてリソースのせいです
using UnityEngine;
using QFramework;
using ResMgr = QFramework.ResMgr;
public class AudioTest : MonoBehaviour
{
private void Start()
{
ResMgr.Init();
//
AudioManager.Instance.SendMsg(new AudioSoundMsg("TestSound"));
AudioManager.Instance.SendMsg(new AudioMusicMsg("BackGroundMusic"));
AudioManager.Instance.SendMsg(new AudioStopMusicMsg());
AudioManager.PlaySound("TestSound");
AudioManager.PlayMusic("BackgroundMusic");
}
}
バグの句読点をどこに書くか
チェーンプログラミングにおける + - * / と "." は
まだ左側に置くことが一般的だと感じているためです。
。。。。。。
しかし、VS を使用してから、たとえば「,」の前に Enter キーを押しても自動的にインデントされず、Enter キーの後の「,」は自動的にインデントされることがわかりました。
VSのデフォルトとは違うと思ったので違いは残しつつ共通点を探すしかない
public static Button GetButtonDeep
(
this Transform root, string childName
,UnityEngine.Events.UnityAction action
)
{
Button result = root.GetButtonDeep(childName);
result.onClick.AddListener( action );
return result;
}
gameObject
.Show()
.Hide()
.Name("Yeah")
.Layer(0)
.Layer("Default")
.DestroySelf();
時計のメモ
実際、なぜ私が概要メモ (上) を書くよりもこのようなメモ (下) を書きたいのかわかりません (たとえそれが単なるチュートリアルであっても) あまりにも馴染みすぎていますか
?
簡潔?
コンパイルが速い?
バグアセンブリと名前空間の関係
同じ名前、まったく同じメソッド Identity() を使用します。場所は図の 2 (アセンブリ CSharp、名前空間 QFramework.Example) です。
同じ名前のものが (Assembly Common && no namespace)、図 1 にあります。
同じ名前のものが (アセンブリ QFramework.Core.Runtime && 名前空間 QFramework) にあります (図 3)。
。。。
アセンブリアセンブリ Common、QFramework.Core.Runtime は自動参照
システムで 2 番目のアセンブリとして自動的に認識されます
。。。
要因がわかりませんが、最近使用したフォルダーのパスはわかりますか?
名前空間とアセンブリ
LibsExample.ExtensionExample.GameObjectExample
例を 3 つ挙げてください
GameObject:Object
MonoBehaviour:Behaviour:Component:Object
Transform:Component:Object
using UnityEngine;
namespace QFramework.Example
{
/// <summary>
/// CEGO EXAMPLE:GameObject 链式调用支持
/// </summary>
public class GameObjectExample : MonoBehaviour
{
private void Start()
{
gameObject
.Show()
.Hide()
.Name("Yeah")
.Layer(0)
.Layer("Default")
.DestroySelf();
// 这里到会断掉,因为GameObject销毁之后就不希望再有操作了
gameObject.DestroySelfGracefully();
GameObject instantiatedObj = null;
gameObject
.DestroySelfAfterDelay(1.5f)
.DestroySelfAfterDelayGracefully(1.5f)
.ApplySelfTo(selfObj => instantiatedObj = selfObj.Instantiate());
Debug.Log(instantiatedObj);
#region 通过MonoBehaviour去调用GameObject相关的API
this
.Show()
.Hide()
.Name("Yeah")
.Layer(0)
.Layer("Default")
.DestroyGameObj();
this
.DestroyGameObjGracefully();
this
.DestroyGameObjAfterDelay(1.5f)
.DestroyGameObjAfterDelayGracefully(1.5f)
.ApplySelfTo(selfScript => instantiatedObj = selfScript.gameObject.Instantiate());
#endregion
#region 也可以使用Transform,因为Transform继承了Component,而Core里的所有的链式扩展都默认支持了Component
transform
.Show()
.Hide()
.Name("Yeah")
.Layer(0)
.Layer("Default")
.DestroyGameObj();
// 这里到会断掉,因为GameObject销毁之后就不希望再有操作了
transform
.DestroyGameObjGracefully();
transform
.DestroyGameObjAfterDelay(1.5f)
.DestroyGameObjAfterDelayGracefully(1.5f)
.ApplySelfTo(selfTrans => instantiatedObj = selfTrans.gameObject.Instantiate());
#endregion
}
}
}
LibsExample.DOTweenExample
namespace QFramework.Example
{
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;
public class DOTweenExample : MonoBehaviour
{
Button mBtnMove;
GameObject mCube;
void Start ()
{
mCube = GameObject.Find("Cube");
//mBtnMove = transform.Find("BtnMove").GetComponent<Button>();
//mBtnMove.onClick.AddListener(() => { mCube.transform.DOMoveX(5, 1f); });
mBtnMove = transform.FindTop("Canvas").GetButtonDeep
(
"BtnMove"
,() => {
mCube.transform.DOMoveX(5, 1f); }
);
}
}
}
LibsExample.ExtensionExample
全員が台本を読んだので、次の記事を含めます
転送できるいくつかのスクリプトを含める必要がある場合 (転送による影響はほとんどありません)
01 UnityAPIExtensions.cs
02 DotNetExtensions.cs
A Framework.Core.Runtime
B Framework.Core.Editor
C 共通 (独自の)
。。。
すべての 01 を Common アセンブリに移動し、古いスクリプトを削除し、A が C
01 を参照して 02 を呼び出すようにします。したがって、一緒に移動して一緒に削除します。そうしないと、参照サイクル エラーが発生します (A は B を参照し、B は A を参照します)。
また、B をCとします。。。
要約すると、元の UnityAPIExtensions.cs、DotNetExtensions.cs を転送して削除します
。。。
レポートが表示されない
LibsExample.IOCExample
最下層はアセンブリを検索し、タイプを検索する必要があります。
using UnityEngine;
namespace QFramework.Example
{
public class InjectExample : MonoBehaviour
{
[Inject] public A AObj; //注入
// Use this for initialization
void Start()
{
var container = new QFrameworkContainer();
container.RegisterInstance(new A());//放入字典
container.Inject(this);//注入
container.Resolve<A>().HelloWorld(); //解决
}
public class A
{
public void HelloWorld()
{
"This is A obj".LogInfo();
}
}
}
}
【未完成】LibsExample.NetworkExample
01 始めたばかりです。クラスを直接逆アセンブルします (1 つのクラスと 1 つのスクリプト)
02 QFramework.、QFramework.Example を分割し、名前空間に従って公開 (CSharp) し
ます 03 スクリプトを見ると、PCClient と MobileServer が表示されます (Clent は PC を属性言語として使用し、Server は Mobile を属性言語として使用する必要があるかはわかりません)
親クラスをプルする
パッケージクライアント、ユーティリティがサーバーを実行
パッケージサーバー、Unity がクライアントを実行
バグ パッケージの実行後にリソースが見つからない
プレハブのパスはそのままで、Prefabs フォルダーを追加してその中に置きました。
これは01 AB パッケージには影響しません(図 2)
バグにより AB パッケージが見つからない
StreamingAssets でプレイしましたが、このエラーは依然として報告されます。
ただし、Unity で実行するとそうではありません。
Failed to Create Res. Not Find AssetData:AssetName:UIMsg BundleName: TypeName: Key:uimsg
。。。。。。
[QMonoSingletonPath("[Framework]/MobileServer")]
public class MobileServer : MonoSingleton<MobileServer>
{
......
private IEnumerator Start()
{
UIMgr.OpenPanel<UIMsg>();
次の図、つまりフォルダー Resources まで実行します。新しいフォルダー Resources を作成し、それをプレハブにドラッグし、パックして、ビルドします。
namespace QFramework
{
public static class ResFactory
{
public static IRes Create(ResSearchRule resSearchRule)
{
var lowerAssetName = resSearchRule.AssetName.ToLower();
short assetType = 0;
if (lowerAssetName.StartsWith("resources/") || lowerAssetName.StartsWith("resources://"))
{
assetType = ResType.Internal;
}
バグソケットを繰り返すことはできません
逆輸入は解決しました
バグ 突然デバッグにプロセスをアタッチできなくなりました
まず参照関係を理解します。
以前は reImport という解決策がありました。
UniRx.Async:
UniRx.Async.Editor:UniRx.Async
UniRx:UniRx.Async
UniRx.Example:UniRx、UniRx.Async
LibsExample.BindingsRxExample
using UnityEngine;
using UnityEngine.UI;
using BindingsRx;
using BindingsRx.Bindings;
using BindingsRx.Converters;
using BindingsRx.Exceptions;
using BindingsRx.Extensions;
using BindingsRx.Filters;
namespace QFramework.Example
{
public class BindingsRxExample : MonoBehaviour
{
[SerializeField] InputField mInputField;
[SerializeField] Text mText;
void Start()
{
Transform canvas = transform.FindTop("Canvas");
mInputField = canvas.Find("InputField").GetComponent<InputField>();
mText = canvas.Find("Text").GetComponent<Text>();
// from,to。左边的改变会影响右边
mInputField.BindTextTo
(
() => mText.text
, text => mText.text = text
);
}
}
}
LibsExample.JsonPathProtobuf
using System;
using UnityEngine;
using UnityEngine.UI;
namespace QFramework
{
public class JsonPathProtobuf : MonoBehaviour
{
ProtoBufTest tempProto = new ProtoBufTest
{
ID = 1,
Msg = "Hello"
};
JsonTest tempJson = new JsonTest {
Age = 18 };
string assetsRoot = "Assets/QFramework/Example/LibsExample/JsonPathProtobuf/";
string appRoot;// Application.dataPath不能写这里
private void Start()
{
appRoot = Application.dataPath + "/QFramework/Example/LibsExample/JsonPathProtobuf/";
ShowText();
SaveProtoBuff();
LoadProtoBuff();
SaveJson();
LoadJson();
}
#region 辅助
private void ShowText()
{
Text text = transform.FindTop("Canvas").GetComponentInChildren<Text>();
text.text = "P 保存protoBuf";
text.text += "\nO 读取protoBuf";
text.text += "\nA 保存json";
text.text += "\nS 读取json";
}
private void LoadJson()
{
this.Sequence()
.Until(() => {
return Input.GetKeyDown(KeyCode.S);
})
.Event(() => {
string path = appRoot + "/TestJosn/TestJson.json";
JsonTest tempLoadJson = SerializeHelper.LoadJson<JsonTest>(path);
Debug.Log(tempLoadJson.Age);
})
.Begin();
}
private void SaveJson()
{
this.Sequence()
.Until(() => {
return Input.GetKeyDown(KeyCode.A);
})
.Event(() => {
string path = appRoot + "TestJosn".CreateDirIfNotExists();
path += "/TestJson.json"; tempJson.SaveJson(path);
#if UNITY_EDITOR
UnityEditor.AssetDatabase.Refresh();
#endif
})
.Begin();
}
private void LoadProtoBuff()
{
this.Sequence()
.Until(() => {
return Input.GetKeyDown(KeyCode.O);
})
.Event(() => {
string path = appRoot + "TestJosn/testPro.proto";
ProtoBufTest tempLoadBuf = SerializeHelper.LoadProtoBuff<ProtoBufTest>(path);
Debug.Log(tempLoadBuf.ID);
})
.Begin();
}
private void SaveProtoBuff()
{
this.Sequence()
.Until(() => {
return Input.GetKeyDown(KeyCode.P);
})
.Event(() => {
string path = (assetsRoot + "TestJosn").CreateDirIfNotExists();
path += "/testPro.proto";
tempProto.SaveProtoBuff(path);
#if UNITY_EDITOR
UnityEditor.AssetDatabase.Refresh();
#endif
})
.Begin();
}
#endregion
}
#region 内部类
[ProtoBuf.ProtoContract]
public class ProtoBufTest
{
[ProtoBuf.ProtoMember(1)]
public int ID=0;
[ProtoBuf.ProtoMember(2)]
public string Msg="Hello";
}
[System.Serializable]
public class JsonTest
{
private string mName;
public string Name
{
get {
return mName; }
set {
mName = value; }
}
private int mAge;
public int Age
{
get {
return mAge; }
set {
mAge = value; }
}
}
#endregion
}
バグ IL2CPP
モノラルに戻す
LibsExample/SingletonExample/0.Singleton
シングルトン
MonoSingleton
ISingleton、MonoBehavior
ISingleton
LibsExample/SingletonExample/0.Singleton
シングルトンは削除されましたが、静的変数はまだ存在します
namespace QFramework.Example
{
using UnityEngine;
public class Singleton : MonoBehaviour
{
private void Start()
{
Class2Singleton.Instance.Log("Hello World!");
Class2Singleton.Instance.Dispose();//删除
// a differente instance
Class2Singleton.Instance.Log("Hello World!");
}
}
}
namespace QFramework.Example
{
using UnityEngine;
internal class Class2Singleton : Singleton<Class2Singleton>
{
private static int mIndex = 0;
private Class2Singleton() {
}
public override void OnSingletonInit()
{
mIndex++;
}
public void Log(string content)
{
Debug.Log("Class2Singleton" + mIndex + ":" + content);
}
}
}
LibsExample/SingletonExample/2.SingletonProperty
MonoSingleton のライフサイクルを見てください。
namespace QFramework.Example
{
using System.Collections;
using UnityEngine;
public class MonoSingletonExample : MonoBehaviour
{
private IEnumerator Start()
{
var instance = Class2MonoSingleton.Instance;
yield return new WaitForSeconds(3.0f);
instance.Dispose();
}
}
}
namespace QFramework.Example
{
using System.Collections;
using UnityEngine;
internal class Class2MonoSingleton : MonoSingleton<Class2MonoSingleton>
{
public override void OnSingletonInit()
{
Debug.Log(name + ":" + "OnSingletonInit");
}
private void Awake()
{
Debug.Log(name + ":" + "Awake");
}
private void Start()
{
Debug.Log(name + ":" + "Start");
}
protected override void OnDestroy()
{
base.OnDestroy();
Debug.Log(name + ":" + "OnDestroy");
}
}
}
LibsExample/UniRxExample
UITestUniRx
Xxx というプレハブ、
2 つのスクリプト(両方とも部分的)、スクリプト 1 の名前は XxxComponents (Xxx.Components に変更しました)、スクリプト 2 の名前は Xxx
01 UITestUniRx.Components を見る
using UnityEngine;
using UnityEngine.UI;
using QFramework;
namespace QFramework.Example
{
public partial class UITestUniRx
{
[SerializeField] public Toggle Toggle;
[SerializeField] public Button Button;
[SerializeField] public InputField InputField;
[SerializeField] public Text Text;
}
}
01 UITestUniRxData を見る
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using QFramework;
using UniRx;
namespace QFramework.Example
{
public class UITestUniRxData : UIPanelData
{
// TODO: Query Mgr's Data
}
public partial class UITestUniRx : UIPanel
{
protected override void InitUI(IUIData uiData = null)
{
}
protected override void ProcessMsg (int eventId,QMsg msg)
{
throw new System.NotImplementedException ();
}
protected override void RegisterUIEvent()
{
Button
.onClick
.AsObservable()//可被观察
.Subscribe(x=> this.LogInfo("按下按钮"));//点击了就打印
InputField
.OnValueChangedAsObservable() //值发生变化时
.Where(x => x != null) //当x!=null时
.SubscribeToText(Text); //变换Text的值
Toggle
.OnValueChangedAsObservable() //值发生变化时
.SubscribeToInteractable(Button); //设置是否可交互
}
protected override void OnShow()
{
base.OnShow();
}
protected override void OnHide()
{
base.OnHide();
}
protected override void OnClose()
{
}
void ShowLog(string content)
{
Debug.Log("[ UITestUniRx:]" + content);
}
}
}
01、02テスト(01、02効果テスト)を見る
using System.Collections.Generic;
using UnityEngine;
using QFramework;
using QFramework.Example;
using UniRx;
using UnityEngine.UI;
using System;
using System.Text;
using UnityEngine.Networking;
using System.Collections;
namespace LFramework
{
/// <summary>
/// 2018/3/30
/// </summary>
public class TestUniRx : MonoBehaviour
{
#region 字属
public static readonly UniRx.Diagnostics.Logger log = new UniRx.Diagnostics.Logger("L Log");
//IReactiveProperty<bool> isChange = new ReactiveProperty<bool>(false);
[Header("ReactiveSubscribe的")]
private CompositeDisposable disposables = new CompositeDisposable();
/// <summary>ReactiveSubscribe的初始符</summary>
bool ReactiveSubscribeFirst = false;
private IDisposable CurrentSub;
#endregion
#region 测试
void Start()
{
QFramework.ResMgr.Init();
ReactiveSubscribeFirst = false;
TestStart01();
TestStart02();
}
void TestStart01()
{
QFramework.UIMgr.OpenPanel<UITestUniRx>();
}
void TestStart02()
{
//说明怎么操作
Debug.Log( String.Format(
"( a , DoubleClick); //双击 \n "
+ "( s , WWW); //WWW \n "
+ "( d , Property); //属性监听(T键改变值) \n "
+ "( f , Coroutine); //和unity协程 \n "
+ "( g , ReactiveSubscribe); //收集器 \n "
+ "( h , TsfSubscribe); //transform \n "
+ "空格就退出\n "
) );
Dictionary<string, Action> m_FuncDic = new Dictionary<string, Action>();
m_FuncDic.Add("a", DoubleClick); //双击
m_FuncDic.Add("s", WWW); //WWW
m_FuncDic.Add("d", Property); //属性监听
m_FuncDic.Add("f", Coroutine); //和unity协程
m_FuncDic.Add("g", ReactiveSubscribe); //收集器
m_FuncDic.Add("h", TsfSubscribe); //transform
//UniRx.Diagnostics.ObservableLogger//这里应该只是演示一种格式
// .Listener
// .Subscribe(_ => Debug.Log(_));
// m_FuncDic中,按了什么键,执行什么方法
Observable.EveryUpdate()
.Do((x) => {
if (Input.inputString != string.Empty && Input.inputString != " ")
{
Debug.Log(Input.inputString);
if (m_FuncDic.ContainsKey(Input.inputString))
{
if (CurrentSub != null)
{
CurrentSub.Dispose();
}
m_FuncDic[Input.inputString].InvokeGracefully();
}
}
})
.Subscribe()
.AddTo(this);
Observable.EveryUpdate()
.Where(_ => Input.GetKeyDown(KeyCode.Space))
.Subscribe(_ => {
disposables.Dispose();
disposables.Clear();
})
.AddTo(this);
}
#endregion
#region 辅助
/// <summary>双击</summary>
void DoubleClick()
{
var stream = Observable
.EveryUpdate()
.Where(x => Input.GetMouseButtonDown(0));
CurrentSub = stream
.Buffer(stream.Throttle(TimeSpan.FromSeconds(0.25f)))
.Do(x => Debug.Log("在检测"))
.Where(x => x.Count >= 2)
.Subscribe(x => Debug.Log("按下次数" + x.Count));
}
void WWW()
{
ObservableWWW
//.GetWWW("http://img.taopic.com/uploads/allimg/120428/128240-12042Q4020849.jpg")//这地址没东西了
.GetWWW("https://patchwiki.biligame.com/images/blhx/thumb/a/a3/0ldcv3eg1w6c27witzhw69rskhlurum.jpg/350px-%E5%A4%A7%E5%87%A4%E6%8D%A2%E8%A3%855.jpg")
.Subscribe(down =>{
Texture2D temp2d = down.texture;
Debug.Log(temp2d.name);
Sprite tempSp = Sprite.Create(temp2d
, new Rect(0, 0, temp2d.width, temp2d.height)
, Vector2.zero);
QFramework.UIMgr.GetPanel<UITestUniRx>().GetComponent<Image>().sprite = tempSp;
}, x => Debug.Log("请求错误"))
.AddTo(disposables);
}
/// <summary>属性</summary>
void Property()
{
IReactiveProperty<bool> m_Bool = new ReactiveProperty<bool>(false);
m_Bool.Subscribe(xs => Debug.Log("值改变"));
CurrentSub = Observable.EveryUpdate()
.Where(_ => Input.GetKeyDown(KeyCode.T))
.Subscribe(_ => m_Bool.Value = !m_Bool.Value);
}
/// <summary>协程</summary>
void Coroutine()
{
Sample10_MainThreadDispatcher temp = new Sample10_MainThreadDispatcher();
CurrentSub = temp.Run();
Debug.Log(temp);
}
/// <summary>GameObj</summary>
void ReactiveSubscribe()
{
if (ReactiveSubscribeFirst == false)
{
ReactiveSubscribeFirst= true;
}
disposables = new CompositeDisposable();
ReactiveCollection<int> m_ReaList = new ReactiveCollection<int>();
//
m_ReaList.ObserveCountChanged()
.Subscribe(x => {
Debug.Log("变"+x); })
.AddTo(disposables);
m_ReaList.ObserveAdd()
.Subscribe(x => {
Debug.Log("加"+x); })
.AddTo(disposables);
m_ReaList.ObserveRemove()
.Subscribe(x => Debug.Log("减"+x))
.AddTo(disposables);
//
m_ReaList.Add(1);
m_ReaList.Remove(1);
CurrentSub = disposables;
Debug.Log("-------------------------------");
}
/// <summary>transform</summary>
void TsfSubscribe()
{
CurrentSub = transform
.ObserveEveryValueChanged(x => x.position)
.Subscribe(x => Debug.Log(x));
}
#endregion
#region 内部类
/// <summary>从Assets/QFramework/Example/LibsExample/UniRxExample/OfficialExamples/Sample10_MainThreadDispatcher.cs
/// 复制修改的类
/// <para/>都运行打印很乱,可以注释其它一个一个运行
/// </summary>
public class Sample10_MainThreadDispatcher
{
public CompositeDisposable Run()
{
Debug.Log("--------------------------");
CompositeDisposable disposable = new CompositeDisposable();
// MainThreadDispatcher is heart of Rx and Unity integration
// StartCoroutine can start coroutine besides MonoBehaviour.
MainThreadDispatcher.StartCoroutine(TestAsync());//调用一次,执行一次
// We have two way of run coroutine, FromCoroutine or StartCoroutine.
// StartCoroutine is Unity primitive way and it's awaitable by yield return.
// FromCoroutine is Rx, it's composable and cancellable by subscription's IDisposable.
// FromCoroutine's overload can have return value, see:Sample05_ConvertFromCoroutine
Observable.FromCoroutine(TestAsync)//调用一次,执行一次
.Subscribe()
.AddTo(disposable);
// Add Action to MainThreadDispatcher. Action is saved queue, run on next update.
MainThreadDispatcher.Post(_ => Debug.Log("test"), null); //调用一次,执行一次
// Timebased operations is run on MainThread(as default)
// All timebased operation(Interval, Timer, Delay, Buffer, etc...)is single thread, thread safe!
Observable.Interval(TimeSpan.FromSeconds(1))//每隔一秒x++
.Subscribe(x => Debug.Log(x))
.AddTo(disposable);
// Observable.Start use ThreadPool Scheduler as default.
// ObserveOnMainThread return to mainthread
Observable.Start(() => Unit.Default) // asynchronous work ;打印了Unit的ToString()方法
.ObserveOnMainThread()
.Subscribe(x => Debug.Log(x))
.AddTo(disposable);
//
return disposable;
}
IEnumerator TestAsync()
{
Debug.Log("a");
yield return new WaitForSeconds(1);
Debug.Log("b");
yield return new WaitForSeconds(1);
Debug.Log("c");
yield return new WaitForSeconds(1);
Debug.Log("d");
}
}
#endregion
}
}
ウォッチ01エフェクト
ウォッチ02エフェクト
ダブルクリックを検出する
ネットマップ WWW
ブール値をリッスンする
リストを聞く
別途掲載します。
実行時は追加後自動変更
削除後自動変更
/// <summary>GameObj</summary>
void ReactiveSubscribe()
{
if (ReactiveSubscribeFirst == false)
{
ReactiveSubscribeFirst= true;
}
disposables = new CompositeDisposable();
ReactiveCollection<int> m_ReaList = new ReactiveCollection<int>();
//
m_ReaList.ObserveCountChanged()
.Subscribe(x => {
Debug.Log("变"+x); })
.AddTo(disposables);
m_ReaList.ObserveAdd()
.Subscribe(x => {
Debug.Log("加"+x); })
.AddTo(disposables);
m_ReaList.ObserveRemove()
.Subscribe(x => Debug.Log("减"+x))
.AddTo(disposables);
//
m_ReaList.Add(1);
m_ReaList.Remove(1);
CurrentSub = disposables;
Debug.Log("-------------------------------");
}
リスニング変換
LibsExample/UniRxExample/OfficialExamples
Sample01_観察可能なWWW
メソッドのみを記述し、MonoBehavior で呼び出します。
ObservableWWW.Get
/// <summary></summary>
private void StartTest01()
{
// Basic: Download from google.
//ObservableWWW.Get("http://google.co.jp/") //我这边超时错误
ObservableWWW
.Get("https://baidu.com/")//返回<!DOCTYPE html><!--STATUS OK--><html><head><meta.......
.Subscribe(
onNext: res => Debug.Log(res.Substring(0, 100)), // onSuccess
onError: error => Debug.LogException(error)); // onError
}
から、選択
private void StartTest02()
{
int textId = 2;//外网测不了时
if(textId == 1)
{
// Linear Pattern with LINQ Query Expressions
// download after google, start bing download
var query = from google in ObservableWWW.Get("http://google.com/")
from bing in ObservableWWW.Get("http://bing.com/")
select new {
google, bing };
var cancel = query.Subscribe(x => {
Debug.LogFormat("{0}:{1}"
, x.google.Substring(0, 100)
, x.bing.Substring(0, 100));
});
// Call Dispose is cancel downloading.
cancel.Dispose();
}
if(textId ==2)//有时会报错Empty reply from server,多运行几下
{
var query = from baidu in ObservableWWW.Get("http://baidu.com/")
from sougou in ObservableWWW.Get("http://sougou.com/")
select new {
baidu, sougou };
var cancel = query
.Subscribe(res => {
Debug.Log(res.baidu);
Debug.Log(res.sougou);
Debug.LogFormat("{0}:{1}"
, res.baidu.Substring(0, 5)
, res.sougou.Substring(0, 5));
});
// Call Dispose is cancel downloading.
//cancel.Dispose();
}
}
いつすべて
private void StartTest03_WhenAll()
{
int curID = 2;
if (curID == 1)
{
// Observable.WhenAll is for parallel asynchronous operation
// (It's like Observable.Zip but specialized for single async operations like Task.WhenAll of .NET 4)
var parallel = Observable.WhenAll(
ObservableWWW.Get("http://google.com/"),
ObservableWWW.Get("http://bing.com/"),
ObservableWWW.Get("http://unity3d.com/"));
parallel.Subscribe(xs =>
{
Debug.Log(xs[0].Substring(0, 100)); // google
Debug.Log(xs[1].Substring(0, 100)); // bing
Debug.Log(xs[2].Substring(0, 100)); // unity
});
}
if (curID == 2)
{
//意思是res的复数
var reses = Observable.WhenAll(
ObservableWWW.Get("https://baidu.com/")
, ObservableWWW.Get("https://sougou.com/")
, ObservableWWW.Get("https://www.bilibili.com/")
);
reses.Subscribe(res =>
{
Debug.Log(res[0].Substring(0, 100));
Debug.Log(res[1].Substring(0, 100));
Debug.Log(res[2].Substring(0, 100));
});
}
}
ScheduledNotifier の進行状況
100% 直接実行
private void StartTest04_ScheduledNotifier()
{
int curID = 2;
if (curID == 1)
{
// with Progress
// notifier for progress
var progressNotifier = new ScheduledNotifier<float>();
progressNotifier.Subscribe(x => Debug.Log(x)); // write www.progress
// pass notifier to WWW.Get/Post
ObservableWWW
.Get(url: "http://google.com/", progress: progressNotifier)
.Subscribe();
}
if (curID == 2)
{
var scheduledNotifier = new ScheduledNotifier<float>();
scheduledNotifier.Subscribe(x => Debug.Log(x));
ObservableWWW
.Get(url: "http://baidu.com/", progress: scheduledNotifier)
.Subscribe();
}
}
WWWエラー例外
private void StartTest05_WWWErrorException()
{
int curID = 2;
if (curID == 1)
{
// with Error
// If WWW has .error, ObservableWWW throws WWWErrorException to onError pipeline.
// WWWErrorException has RawErrorMessage, HasResponse, StatusCode, ResponseHeaders
ObservableWWW
.Get("http://www.google.com/404")
.CatchIgnore((WWWErrorException ex) =>
{
Debug.Log(ex.RawErrorMessage);
if (ex.HasResponse)
{
Debug.Log(ex.StatusCode);
}
foreach (var item in ex.ResponseHeaders)
{
Debug.Log(item.Key + ":" + item.Value);
}
})
.Subscribe();
}
if (curID == 2)
{
ObservableWWW.Get("https://www.bilibili.com/404")
.CatchIgnore((WWWErrorException error) =>
{
Debug.Log(error.RawErrorMessage);
if (error.HasResponse)
{
Debug.Log(error.StatusCode);
}
string str = "";
foreach (var item in error.ResponseHeaders)
{
str+=item.Key + ":" + item.Value+"\n";
}
Debug.Log(str);
})
.Subscribe();
}
}
Sample02_ObservableTriggers
void Do_ObservableUpdateTrigger()
{
int curID = 2;
if (curID == 1)
{
// Get the plain object
var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
// Add ObservableXxxTrigger for handle MonoBehaviour's event as Observable
cube.AddComponent<ObservableUpdateTrigger>()
.UpdateAsObservable()
.SampleFrame(30)
.Subscribe(
res => Debug.Log("cube")
, () => Debug.Log("destroy"));
// destroy after 3 second:)
GameObject.Destroy(cube, 6f);
}
if (curID == 2)
{
var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.AddComponent<ObservableUpdateTrigger>()
.UpdateAsObservable()
.SampleFrame(30)
.Skip(1)
.Subscribe(_ => {
Debug.Log("cube");
Debug.Log("destroy");
});
GameObject.Destroy(cube, 4f);
}
}
Sample03_GameObjectAsObservable(UpdateAsObservable、OnMouseUpAsObservable)
void Start()
{
int curId = 2;
if (curId == 1)
{
// All events can subscribe by ***AsObservable if enables UniRx.Triggers
this.OnMouseDownAsObservable()
.SelectMany(_ => this.gameObject.UpdateAsObservable())
.TakeUntil(this.gameObject.OnMouseUpAsObservable())//结束标志
.Select(_ => Input.mousePosition)
.RepeatUntilDestroy(this)
.Subscribe(pos => Debug.Log(pos), () => Debug.Log("!!!" + "complete"));
}
if (curId == 2)
{
// All events can subscribe by ***AsObservable if enables UniRx.Triggers
this.OnMouseDownAsObservable()//鼠标点击
.SelectMany(_ => this.gameObject.UpdateAsObservable())//点击的是一个物体
.TakeUntil(this.gameObject.OnMouseUpAsObservable())//结束标志
.Select(_ => Input.mousePosition) //在结果中选择 pos
.RepeatUntilDestroy(this) //不断重复这个过程直到销毁
.Subscribe(
onNext: pos => Debug.Log(pos),
onCompleted: () => Debug.Log("!!!" + "complete")
);
}
}
Sample04_ConvertFromUnityCallback
+LogCallbackを出力するだけです
using System;
using UnityEngine;
namespace UniRx.Examples
{
public class Sample04_ConvertFromUnityCallback : MonoBehaviour
{
void Awake()
{
// method is separatable(分离) and composable(组合)
LogHelper
.LogCallbackAsObservable()
.Where( x => (x.LogType == LogType.Warning) )
.Subscribe(x => Debug.Log(x));
LogHelper
.LogCallbackAsObservable()
.Where(x => (x.LogType == LogType.Error) )
.Subscribe(x => Debug.Log(x));
}
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
Debug.LogWarning("LogWarning");
Debug.LogError("LogError");
}
}
#region 内部类
// This is about log but more reliable log sample => Sample11_Logger
private class LogCallback
{
public string Condition;
public string StackTrace;
public UnityEngine.LogType LogType;
}
static class LogHelper
{
// If static register callback, use Subject for event branching.
#if (UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7)
static Subject<LogCallback> subject;
public static IObservable<LogCallback> LogCallbackAsObservable()
{
if (subject == null)
{
subject = new Subject<LogCallback>();
// Publish to Subject in callback
UnityEngine.Application.RegisterLogCallback((condition, stackTrace, type) =>
{
subject.OnNext(new LogCallback {
Condition = condition, StackTrace = stackTrace, LogType = type });
});
}
return subject.AsObservable();
}
#else
// If standard evetns, you can use Observable.FromEvent.
public static IObservable<LogCallback> LogCallbackAsObservable()
{
return Observable.FromEvent<Application.LogCallback, LogCallback>(
conversion: h
=> (
condition,
stackTrace,
type)
=> h( new LogCallback {
Condition = condition,
StackTrace = stackTrace,
LogType = type
}),
addHandler: h => Application.logMessageReceived += h,
removeHandler: h => Application.logMessageReceived -= h);
}
#endif
}
#endregion
}
}
Sample05_ConvertFromCoroutine
届いたのですが形式が間違っていて公式サイトを見てもどこが間違っているのかわかりません。
開始スクリプト Sample05_ConvertFromCoroutine_Start
/****************************************************
文件:Sample05_ConvertFromCoroutine_Start.cs
作者:lenovo
邮箱:
日期:2023/6/10 9:21:46
功能:对应的测试脚本
*****************************************************/
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
namespace UniRx.Examples
{
public class Sample05_ConvertFromCoroutine_Start : MonoBehaviour
{
#region 属性
#endregion
#region 生命
/// <summary>首次载入且Go激活</summary>
void Start()
{
Sample05_ConvertFromCoroutine.GetWWW("https://www.baidu.com",gameObject);
//https://docs.unity.cn/2021.3/Documentation/ScriptReference/Networking.UnityWebRequest.Get.html
//"https://www.example.com"
//https://error.html"
}
#endregion
}
}
Sample05_ConvertFromCoroutine
using System;
using System.Collections;
using System.Threading;
using UnityEngine;
#if UNITY_2018_3_OR_NEWER
#pragma warning disable CS0618
#endif
namespace UniRx.Examples
{
public class Sample05_ConvertFromCoroutine
{
// public method
public static IObservable<string> GetWWW(string url,GameObject gameObject=null)
{
int curID = 2;
if (curID == 1)
{
// convert coroutine to IObservable
// cancellation ,取消的名词
// Token,目的为了减轻服务器压力,方式是对请求数据(用户名与密码)的加工
return Observable
.FromCoroutine<string>((observer, cancellationToken)
=> GetWWWCore(url, observer, cancellationToken)
);
}
if (curID == 2)
{
return (IObservable<string>)Observable
.FromCoroutine<string>((observer, cancellationToken)
=> GetWWWCore(url, observer, cancellationToken))
.Subscribe(
_ => Debug.Log("OnNext"),
() => Debug.Log("OnCompleted"))
.AddTo(gameObject);
}
return null;
}
// IEnumerator with callback
static IEnumerator GetWWWCore(string url
, IObserver<string> observer
, CancellationToken cancellationToken)
{
var www = new UnityEngine.WWW(url);
while (!www.isDone && !cancellationToken.IsCancellationRequested)//连接中
{
yield return null;
}
if (cancellationToken.IsCancellationRequested)//取消连接
{
yield break;
}
if (www.error != null) //连接错误
{
observer.OnError(new Exception(www.error));
}
else //连接成功
{
observer.OnNext(www.text);
Debug.Log(www.text);
observer.OnCompleted();
}
}
}
}
#if UNITY_2018_3_OR_NEWER
#pragma warning restore CS0618
#endif
Sample06_ConvertToCoroutine
印刷番号、
リクエスト URL、場合によってはエラー (unity3d.com) はエラーの可能性が高い
using System;
using System.Collections;
using UnityEngine;
namespace UniRx.Examples
{
public class Sample06_ConvertToCoroutine : MonoBehaviour
{
// convert IObservable to Coroutine
void Start()
{
StartCoroutine( NormalCoroutine() );
StartCoroutine( TestNewCustomYieldInstruction() );
}
#region 辅助
/// <summary>=Range(1, 10),然后Return(100)</summary>
IEnumerator NormalCoroutine()
{
yield return new WaitForSeconds(1);
var val = default(int);
yield return Observable
.Range(1, 10)
.StartAsCoroutine(x => {
val = x; });
Debug.Log(val); // 10(callback is last value)
yield return new WaitForSeconds(3);
yield return Observable
.Return(100)
.StartAsCoroutine(x => {
val = x; });
Debug.Log(val); // 100
}
#region TestNewCustomYieldInstruction
// Note:ToAwaitableEnumerator/StartAsCoroutine/LazyTask are obsolete way on Unity 5.3
// You can use ToYieldInstruction.
#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2)
#if UNITY_2018_3_OR_NEWER
#pragma warning disable CS0618
#endif
IEnumerator TestNewCustomYieldInstruction()
{
// wait Rx Observable.
yield return Observable
.Timer(TimeSpan.FromSeconds(1))
.ToYieldInstruction();
// you can change the scheduler(this is ignore Time.scale)
yield return Observable
.Timer( TimeSpan.FromSeconds(1), Scheduler.MainThreadIgnoreTimeScale )
.ToYieldInstruction();
// get return value from ObservableYieldInstruction
var oWWW = ObservableWWW
//.Get("http://unity3d.com/")
.Get("https://www.baidu.com/")
.ToYieldInstruction(throwOnError: false);
yield return oWWW;
if (oWWW.HasError)
{
Debug.Log("oWWW.Error\n" + oWWW.Error.ToString());
}
if (oWWW.HasResult)
{
Debug.Log("oWWW.Result\n"+ oWWW.Result);
}
// other sample(wait until transform.position.y >= 100)
// 这块我打印不出什么来验证
yield return this
.ObserveEveryValueChanged(go => go.transform)
.FirstOrDefault(trans => trans.position.y >= 100 )
.ToYieldInstruction();
}
#if UNITY_2018_3_OR_NEWER
#pragma warning restore CS0618
#endif
#endif
#endregion
#endregion
}
}
Sample07_OrchestratIEnumerator
2 回実行し、2 回目にマウスをクリックしてコルーチンを終了します。
#pragma warning disable 0168
#pragma warning disable 0219
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace UniRx.Examples
{
public class Sample07_OrchestratIEnumerator : MonoBehaviour
{
void Start()
{
// after completed AsyncA, run AsyncB as continuous routine.
// UniRx expands SelectMany(IEnumerator) as SelectMany(IEnumerator.ToObservable())
var cancel = Observable
.FromCoroutine(AsyncA)
.SelectMany(AsyncB)//==.SelectMany(AsyncB.ToObservable())
.Subscribe();
// If you want to stop Coroutine(as cancel), call subscription.Dispose()
// cancel.Dispose();
Observable.EveryUpdate()
.Where(_ => Input.GetMouseButtonDown(0))
.Subscribe(_ => cancel.Dispose(), () =>Debug.Log("已取消!!!")); //取消协程任务
int i = 0; //做个计时不然看不出效果
Observable
.EveryUpdate()
.Sample(TimeSpan.FromSeconds(1f))
.Subscribe(_ => Debug.Log(i++ + "DoTimer-----"))
.AddTo(this);
}
// two coroutines
IEnumerator AsyncA()
{
Debug.Log("a start");
yield return new WaitForSeconds(3);
Debug.Log("a end");
}
IEnumerator AsyncB()
{
Debug.Log("b start");
yield return new WaitForEndOfFrame();
Debug.Log("b end");
}
}
}
#pragma warning restore 0219
#pragma warning restore 0168
Sample08_DetectDoubleClick ダブルクリック
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace UniRx.Examples
{
public class Sample08_DetectDoubleClick : MonoBehaviour
{
void Start()
{
// Global event handling is very useful.
// UniRx can handle there events.
// Observable.EveryUpdate/EveryFixedUpdate/EveryEndOfFrame
// Observable.EveryApplicationFocus/EveryApplicationPause
// Observable.OnceApplicationQuit
// This DoubleCLick Sample is from
// The introduction to Reactive Programming you've been missing
// https://gist.github.com/staltz/868e7e9bc2a7b8c1f754
var clickStream = Observable.EveryUpdate()
.Where(_ => Input.GetMouseButtonDown(0)); //if(Input.GetMouseButtonDown(0))
//打印"双击DoubleClick Detected! Count:" num++
clickStream
.Buffer(clickStream.Throttle(TimeSpan.FromMilliseconds(250)))//掐死(面包条一段一段掐团),if(timer>=250){ xs.Count++;timer=0;}
.Where(xs => xs.Count >= 2)//predicate谓语. if (xs.Count >= 2)
.Subscribe(xs => Debug.Log("双击DoubleClick Detected! Count:" + xs.Count));
}
}
}
サンプル09_イベント処理
スタートテスト01
Qを押します
スタートテスト02
スタートテスト03
スタートテスト04
スタートテスト05
StartTest01~05のスクリプト
#pragma warning disable 0067
using System;
using System.Reflection;
using UnityEngine;
namespace UniRx.Examples
{
public class Sample09_EventHandling : MonoBehaviour
{
#region 字属
/// <summary>Foo,function object Oriented,即面向对象函数,原命名为FooBar</summary>
public event EventHandler<MyEventArgs> mMyEventHandler;
public event Action<int> mIntAction;
CompositeDisposable mCompositeDisposable = new CompositeDisposable();
// Subject is Rx's native event expression and recommend way for use Rx as event.
// Subject.OnNext as fire event,
// expose IObserver is subscibable for external source, it's no need convert.
Subject<int> mSubject = new Subject<int>(); //主题
public IObservable<int> mObservable {
get {
return mSubject; } } //可被观察的
#endregion
#region 生命
void Start()
{
//不用Start,采用Update按键的方式
//StartTest01();
//StartTest02();
//StartTest03();
//StartTest04();
//StartTest05();
}
private void Update()
{
Common.DownKeyCode( KeyCode.Q, StartTest01 );
Common.DownKeyCode( KeyCode.W, StartTest02 );
Common.DownKeyCode( KeyCode.E, StartTest03 );
Common.DownKeyCode( KeyCode.R, StartTest04 );
Common.DownKeyCode( KeyCode.T, StartTest05 );
}
void OnDestroy()
{
// manage subscription lifecycle
mCompositeDisposable.Dispose();
}
#endregion
#region 辅助
private void StartTest01()
{
//01 定义
// convert to IO<EventPattern> as (sender, eventArgs)
Observable.FromEventPattern<EventHandler<MyEventArgs>, MyEventArgs>(
conversion: handler => handler.Invoke,
addHandler: handler => mMyEventHandler += handler,
removeHandler: handler => mMyEventHandler -= handler)//后面都用 h 简代 handler
.Subscribe(onNext: handler => Debug.Log("StartTest01的OnNext CallBack:"+ handler.EventArgs.ToString()) )
.AddTo(mCompositeDisposable); // IDisposable can add to collection easily by AddTo
//02 接下来测试
mMyEventHandler(this, new MyEventArgs {
MyProperty = 666 });
}
private void StartTest02()
{
// convert to IO<EventArgs>, many situation this is useful than FromEventPattern
Observable.FromEvent<EventHandler<MyEventArgs>, MyEventArgs>(
conversion: h => (sender, e) => h(e),
addHandler: h => mMyEventHandler += h,
removeHandler: h => mMyEventHandler -= h)
.Subscribe(onNext: handler => Debug.Log("StartTest02的OnNext CallBack:" + handler.MyProperty) )
.AddTo(mCompositeDisposable);
mMyEventHandler(this, new MyEventArgs {
MyProperty = 666 });
}
private void StartTest03()
{
// You can convert Action like event.
Observable.FromEvent<int>(
addHandler: h => mIntAction += h,
removeHandler: h => mIntAction -= h)
.Subscribe(onNext: handler => Debug.Log("StartTest03的OnNext CallBack:" + handler.ToString()))
.AddTo(mCompositeDisposable);
mIntAction(3); //一个委托(命令、请求都可以说,实质是方法的地址,这个例子没往里面塞具体的方法)
}
private void StartTest04()
{
// AOT Safe EventHandling, use dummy capture, see:https://github.com/neuecc/UniRx/wiki/AOT-Exception-Patterns-and-Hacks
var capture = 0;
Observable.FromEventPattern<EventHandler<MyEventArgs>, MyEventArgs>(
conversion: h =>
{
capture.GetHashCode(); // dummy for AOT
return new EventHandler<MyEventArgs>(h);
},
addHandler: h => mMyEventHandler += h,
removeHandler: h => mMyEventHandler -= h)
.Subscribe(onNext: handler => Debug.Log("StartTest04的OnNext CallBack:" + handler.EventArgs.ToString()))
.AddTo(mCompositeDisposable);
mMyEventHandler(this, new MyEventArgs {
MyProperty = 666 });
}
private void StartTest05()
{
// Subject as like event.
mObservable
.Subscribe(onNext: handler => Debug.Log("StartTest05的OnNext CallBack:") )
.AddTo(mCompositeDisposable);
mSubject.OnNext(1); // fire event
}
#endregion
#region 内部类
public class MyEventArgs : EventArgs
{
public int MyProperty {
get; set; }
public override string ToString()
{
string str = "";
str += "MyProperty\t" + MyProperty + "\n";
return str;
}
}
#endregion
}
}
#pragma warning restore 0067
Sample10_MainThreadDispatcher
結果はコメントに書いてあります
RunTest01(); //abcd
RunTest02();//abcd
RunTest03();//test
RunTest04(); //0 1 2 3 4.....
RunTest05();//()
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
namespace UniRx.Examples
{
public class Sample10_MainThreadDispatcherStart : MonoBehaviour
{
#region 属性
#endregion
#region 生命
/// <summary>首次载入</summary>
void Awake()
{
Sample10_MainThreadDispatcher mainThreadDispatcher = new Sample10_MainThreadDispatcher();
mainThreadDispatcher.Run();
}
#endregion
}
}
using System;
using System.Collections;
using UnityEngine;
namespace UniRx.Examples
{
public class Sample10_MainThreadDispatcher
{
public void Run()
{
RunTest01(); //abcd
RunTest02();//abcd
RunTest03();//test
RunTest04(); //0 1 2 3 4.....
RunTest05();//()
}
private void RunTest05()
{
// Observable.Start use ThreadPool Scheduler as default.
// ObserveOnMainThread return to mainthread
Observable
.Start(() => Unit.Default) // asynchronous work
.ObserveOnMainThread()
.Subscribe(x => Debug.Log(x));
}
private void RunTest04()
{
// Timebased operations is run on MainThread(as default)
// All timebased operation(Interval, Timer, Delay, Buffer, etc...)is single thread, thread safe!
Observable
.Interval(TimeSpan.FromSeconds(1))
.Subscribe(x => Debug.Log(x));
}
private void RunTest03()
{
// Add Action to MainThreadDispatcher. Action is saved queue, run on next update.
MainThreadDispatcher
.Post(_ => Debug.Log("test"), null);
}
/// <summary>运行一次</summary>
private void RunTest02()
{
// We have two way of run coroutine, FromCoroutine or StartCoroutine.
// StartCoroutine is Unity primitive way and it's awaitable by yield return.
// FromCoroutine is Rx, it's composable and cancellable by subscription's IDisposable.
// FromCoroutine's overload can have return value, see:Sample05_ConvertFromCoroutine
Observable
.FromCoroutine(TestAsync)
.Subscribe();
}
/// <summary>运行一次</summary>
private void RunTest01()
{
// MainThreadDispatcher is heart of Rx and Unity integration (结合)
// StartCoroutine can start coroutine besides MonoBehaviour.
MainThreadDispatcher
.StartCoroutine(TestAsync());
}
IEnumerator TestAsync()
{
Debug.Log("a");
yield return new WaitForSeconds(1);
Debug.Log("b");
yield return new WaitForSeconds(1);
Debug.Log("c");
yield return new WaitForSeconds(1);
Debug.Log("d");
}
}
}
サンプル11_ロガー
起動スクリプトが必要です
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
namespace UniRx.Examples
{
public class Sample11_LoggerStart : MonoBehaviour
{
#region 生命
/// <summary>首次载入且Go激活</summary>
void Start()
{
Sample11_Logger logger = new Sample11_Logger();
logger.ApplicationInitialize();
logger.Run();
}
#endregion
}
}
using System;
using System.Collections;
using UniRx.Diagnostics;
using UnityEngine;
namespace UniRx.Examples
{
public class Sample11_Logger
{
// UniRx.Diagnostics.Logger
// logger is threadsafe, define per class with name.
static readonly UniRx.Diagnostics.Logger mLogger = new UniRx.Diagnostics.Logger("Sample11");
// call once at applicationinit
public void ApplicationInitialize()
{
// Log as Stream, UniRx.Diagnostics.ObservableLogger.Listener is IObservable<LogEntry>
// You can subscribe and output to any place.
// 初始化
ObservableLogger.Listener.LogToUnityDebug();
// for example, filter only Exception and upload to web.
// (make custom sink(IObserver<EventEntry>) is better to use)
// 没啥演示,没服务器来收集日志
ObservableLogger.Listener
.Where(x => x.LogType == LogType.Exception)
.Subscribe(x =>
{
//ObservableWWW.Post("", null).Subscribe();
});
}
public void Run()
{
// Debug is write only DebugBuild.
mLogger.Debug("Debug Message");
// or other logging methods
mLogger.Log("Message");
mLogger.Exception(new Exception("test exception"));
}
}
}
サンプル12_反応性プロパティ
// for uGUI(from 4.6)
#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5)
using System;
using UnityEngine;
using UnityEngine.UI;
namespace UniRx.Examples
{
public class Sample12_ReactiveProperty : MonoBehaviour
{
#region 字属
[Header("场景节点")]
public Button MyButton;
public Toggle MyToggle;
public InputField MyInputField;
public Text MyText;
public Slider MySlider;
// You can monitor/modifie in inspector by SpecializedReactiveProperty
[Header("脚本变量")]
public IntReactiveProperty IntRxProp = new IntReactiveProperty();
Enemy enemy = new Enemy(1000);
#endregion
private void Awake()
{
Transform canvasTrans = transform.FindTop("Canvas");
MyButton = canvasTrans.GetComponentDeep<Button>("MyButton") ;
MyToggle = canvasTrans.GetComponentDeep<Toggle>("MyToggle");
MyInputField = canvasTrans.GetComponentDeep<InputField>("MyInputField");
MyText = canvasTrans.GetComponentDeep<Text>("MyText");
MySlider = canvasTrans.GetComponentDeep<Slider>("MySlider");
}
void Start()
{
InitButton();
InitToggle();
InitInputField();
InitSlider();
InitEnemy();
InitInspector();
}
#region 辅助
private void InitInspector()
{
// initial text:)
//滑动细节面板上的属性就会同步Text显示
IntRxProp.SubscribeToText(MyText);
}
private void InitEnemy()
{
// from RxProp, CurrentHp changing(Button Click) is observable
enemy.CurrentHp.SubscribeToText(MyText);
enemy.IsDead.Where(isDead => isDead == true)
.Subscribe(_ =>
{
MyToggle.interactable = MyButton.interactable = false;
});
}
private void InitInputField()
{
// input shows delay after 1 second
//延时一秒,将输入框文字赋值文本组件
#if !(UNITY_4_6 || UNITY_4_7 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2)
MyInputField.OnValueChangedAsObservable()
#else
MyInputField.OnValueChangeAsObservable()
#endif
.Where(x => x != null)
.Delay(TimeSpan.FromSeconds(1))
.SubscribeToText(MyText); // SubscribeToText is UniRx.UI Extension Method
}
private void InitSlider()
{
// converting for human visibility
//
MySlider.OnValueChangedAsObservable()
.SubscribeToText(MyText, x => Math.Round(x, 2).ToString());
}
private void InitToggle()
{
// Toggle, Input etc as Observable(OnValueChangedAsObservable is helper for provide isOn value on subscribe)
// SubscribeToInteractable is UniRx.UI Extension Method, same as .interactable = x)
//Toggle控制Button的Interactable
MyToggle.OnValueChangedAsObservable().SubscribeToInteractable(MyButton);
}
private void InitButton()
{
// UnityEvent as Observable
// (shortcut, MyButton.OnClickAsObservable())
// 点按钮扣99
MyButton.onClick.AsObservable().Subscribe(_ => enemy.CurrentHp.Value -= 99);
}
#endregion
}
#region 内部类
// Reactive Notification Model
public class Enemy
{
public IReactiveProperty<long> CurrentHp {
get; private set; }
public IReadOnlyReactiveProperty<bool> IsDead {
get; private set; }
public Enemy(int initialHp)
{
// Declarative Property
CurrentHp = new ReactiveProperty<long>(initialHp);
IsDead = CurrentHp.Select(x => x <= 0).ToReactiveProperty();
}
}
#endregion
}
#endif
サンプル13_ToDoApp
バグ
ノードが失われています。ToDoList
ノードのサイズが下のボタンを覆っているため (この時点ではマスクがありません)、アイテムを追加した後、下のボタンは無効になります。
本体
// for uGUI(from 4.6)
#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5)
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using UnityEngine.EventSystems;
namespace UniRx.Examples
{
public class Sample13_ToDoApp : MonoBehaviour
{
[Header("场景节点")]
public Text Title;
public Button AddBtn;
public Button ClearBtn;
public InputField ToDoInput;
public GameObject SampleItemPrefab;
public GameObject TodoLst;
[Header("脚本变量")]
ReactiveCollection<GameObject> toDos = new ReactiveCollection<GameObject>();
private void Awake()
{
Transform canvasTrans = transform.FindTop("Canvas");
Title = canvasTrans.GetComponentDeep<Text>("Title");
AddBtn = canvasTrans.GetComponentDeep<Button>("AddBtn");
ClearBtn = canvasTrans.GetComponentDeep<Button>("ClearBtn");
ToDoInput = canvasTrans.GetComponentDeep<InputField>("ToDoInput");
TodoLst = canvasTrans.FindChildDeep("TodoLst").gameObject;
toDos = new ReactiveCollection<GameObject>();
}
void Start()
{
//两个按钮
{
// merge Button click and push enter key on input field.
//增加按钮或输入框回车,同功能
var submit = Observable.Merge(
AddBtn.OnClickAsObservable().Select( _ => ToDoInput.text),
ToDoInput.OnEndEditAsObservable().Where( _ => Input.GetKeyDown(KeyCode.Return)));
// 增加
submit
.Where(x => x != "")
.Subscribe(x =>{
ToDoInput.text = ""; // clear input field
var item = Instantiate(SampleItemPrefab) as GameObject;
(item.GetComponentInChildren(typeof(Text)) as Text).text = x;
toDos.Add(item);});
// 清空已经办好的(勾选了的)
ClearBtn
.OnClickAsObservable()
.Subscribe(_ => {
var removeTargets = toDos.Where(x => x.GetComponent<Toggle>().isOn).ToArray();
foreach (var item in removeTargets)
{
toDos.Remove(item);
}});
}
//对Item的增删改
{
//变化是改变抬头上的文本(数量变化)
toDos
.ObserveCountChanged()
.Subscribe(x => Title.text = "TODO App, ItemCount:" + x);
//增加的将该变量设置父节点
toDos
.ObserveAdd()
.Subscribe(x =>{
x.Value.transform.SetParent(TodoLst.transform, false);});
//清空时销毁
toDos
.ObserveRemove()
.Subscribe(x =>{
GameObject.Destroy(x.Value);});
}
}
}
}
#endif
UIKitExample/EventExample
登録イベント (送信、監視)
オブザーバー (受信、呼び出し、メソッドを呼び出すことができます。ここでの例はパラメーター「Hello World!」と呼ばれます)
コルーチン
内部のクラスが失われ、エラーが報告されます
うp主のファン登録に相当する受け取り
using UnityEngine;
namespace QFramework
{
public class EventGet : MonoBehaviour
{
void Start ()
{
QEventSystem.RegisterEvent(TestEvent.TestOne,GetEvent);
}
void GetEvent(int key, params object[] obj)
{
switch (key)
{
case (int)TestEvent.TestOne:
this.LogInfo(obj[0].ToString());
break;
}
}
}
}
送信、アップマスターに相当
using UnityEngine;
using UniRx;
namespace QFramework
{
public class EventTest : MonoBehaviour
{
void Start()
{
Observable
.EveryUpdate()
.Subscribe( _ =>
QEventSystem.SendEvent(TestEvent.TestOne,"Hello World!"));
}
}
}
列挙する
using UnityEngine;
namespace QFramework
{
public enum TestEvent
{
TestOne
}
}
UIKitExample/ManagerOfManagersExample
指定された ID を実行するためのロジックはありません。ForwardMsg(tmpMsg) のコメントを解除する必要があります。タスク リストに入れておきます。
結果を得ることができる
namespace QFramework
{
using UnityEngine;
[QMonoSingletonPath("[Event]/QMsgCenter")]
public partial class QMsgCenter : MonoBehaviour, ISingleton
{
......
public void SendMsg(QMsg tmpMsg)
{
......
// TODO case (int)PlayerEvent.Run:
ForwardMsg(tmpMsg);
}
プレーヤー、ファンに相当
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace QFramework.Example
{
public class Player : QMonoBehaviour
{
private IManager mManager;
// Use this for initialization
void Start()
{
RegisterEvent(PlayerEvent.Run);
}
// Update is called once per frame
protected override void ProcessMsg(int eventId, QMsg msg)
{
switch (eventId)
{
case (int)PlayerEvent.Run: //查TODO ,去取消注释才有结果
Log.I("收到跑的消息了");
break;
}
}
public override IManager Manager
{
get {
return GameManager.Instance ; }
}
#region 内部类
public class GameManager : QMgrBehaviour, ISingleton
{
public override int ManagerId
{
get {
return QMgrID.Game; }
}
public static GameManager Instance
{
get {
return MonoSingletonProperty<GameManager>.Instance; }
}
public void OnSingletonInit()
{
}
}
#endregion
}
}
マネージャーのマネージャーの例
using System.Collections;
using System.Collections.Generic;
using QFramework;
using UnityEngine;
namespace QFramework.Example
{
public class ManagerOfManagersExample : QMonoBehaviour
{
public override IManager Manager
{
get {
return UIManager.Instance; }
}
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
Debug.Log("单击");
SendEvent(PlayerEvent.Run);
}
}
}
}
ForwardMsg のソース
using System.Collections;
using System.Collections.Generic;
using QFramework.Example;
using UnityEngine;
namespace QFramework
{
/// <summary>管所有Mgr</summary>
public partial class QMsgCenter
{
public static void ForwardMsg(QMsg msg)
{
switch (msg.ManagerID)
{
case QMgrID.Game:
Player.GameManager.Instance.SendMsg(msg);//根据msg.ManagerID,给mgr发消息
break;
}
}
}
}
列挙する
namespace QFramework.Example
{
public enum PlayerEvent
{
Start = QMgrID.Game,
Run,
End
}
}
UIKitExample/UIExample
全体的な動作を確認するために見てください
Bug VS がブレークポイントを削除した後も、エラー リストはまだ保存されています。
modify は、AB パッケージからフォルダーを作成し、スクリプトのすべてのコンテンツを独自のライブラリに転送する拡張メソッドです。
Logのdllを使用するのでコピーするだけ
ResKitサンプル/オーディオ
AB 名は元のファイル名を直接コピーし、システムは自動的に小文字に変更します。
名前の形式を見て、必須の名前付け形式があるのかと思いましたが、実際には単に人々の利益のためです。詳細については、Assets/QFrameworkData/QAssets.cs を参照してください。
using UnityEngine;
using QFramework;
public class AudioTest : MonoBehaviour
{
string mMusicName = "resources://JYJ - BACK SEAT";
//string mMusicName = "BackGroundMusic";
string mSoundName = "TestSound";
private void Start()
{
QFramework.ResMgr.Init();
//
// AudioManager.Instance.SendMsg(new AudioSoundMsg(mSoundName));
AudioManager.Instance.SendMsg(new AudioMusicMsg(mMusicName));
AudioManager.Instance.SendMsg(new AudioStopMusicMsg());
// AudioManager.PlaySound(mSoundName);
AudioManager.PlayMusic(mMusicName);
}
}
これを行う理由は、RealFrame が同様のことを行っており、比較して統合したいためです。
ResKitExample/プール
using UnityEngine;
namespace QFramework
{
public class CallPool : MonoBehaviour
{
private void Start()
{
#region SimpleObjectPool
"====SimpleObjectPool".LogInfo();
var pool = new SimpleObjectPool<Fish>(() => new Fish(),initCount:50);
pool.CurCount.LogInfo();
//
var fish = pool.Allocate();
pool.CurCount.LogInfo();
//
pool.Recycle(fish);
pool.CurCount.LogInfo();
#endregion
#region SafeObjectPool
"====SafeObjectPool".LogInfo();
SafeObjectPool<Bullet>.Instance.Init(50,25);
var bullet = Bullet.Allocate();
SafeObjectPool<Bullet>.Instance.CurCount.LogInfo();
//
bullet.Recycle2Cache();
SafeObjectPool<Bullet>.Instance.CurCount.LogInfo();
#endregion
}
#region 内部类
class Fish
{
}
class Bullet :IPoolable,IPoolType
{
public bool IsRecycled {
get; set; }
public static Bullet Allocate()
{
return SafeObjectPool<Bullet>.Instance.Allocate();
}
public void OnRecycled()
{
"回收了".LogInfo();
}
public void Recycle2Cache()
{
SafeObjectPool<Bullet>.Instance.Recycle(this);
}
}
#endregion
}
}
ResKitExample/RefCounter
using UnityEngine;
namespace QFramework.Course
{
public class RefCounterExample : MonoBehaviour
{
void Start()
{
var room = new Room();
room.EnterPeople();
room.EnterPeople();
room.EnterPeople();
//
room.LeavePeople();
room.LeavePeople();
room.LeavePeople();
}
}
#region 内部类
public class Light
{
public void SwitchOn()
{
Log.E("开灯");
}
public void SwitchOff()
{
Log.E("关灯");
}
}
public class Room : SimpleRC
{
private Light mLight = new Light();
public void EnterPeople()
{
Log.E("进入人了");
if (RefCount == 0)
{
mLight.SwitchOn();
}
Retain();
}
public void LeavePeople()
{
Release();
Log.E("人出来了");
}
protected override void OnZeroRef()
{
mLight.SwitchOff();
}
}
#endregion
}
ResKitExample/ResKit/LoadAssetBundleResExample
using UnityEngine;
using UnityEngine.UI;
namespace QFramework.Example
{
public class AssetBundleResExample : MonoBehaviour
{
private ResLoader mResLoader = ResLoader.Allocate();
public RawImage RawImage;
private void Awake()
{
ResMgr.Init();
}
// Use this for initialization
void Start()
{
Transform canvasTrans = transform.FindTop("Canvas");
RawImage rawImage = canvasTrans.Find("RawImage").GetComponent<RawImage>();
RawImage.texture = mResLoader.LoadSync<Texture2D>("TestImage");
// 通过下边方式也一样
RawImage.texture = mResLoader.LoadSync<Texture2D>("testimage_png","TestImage");
}
private void OnDestroy()
{
mResLoader.Recycle2Cache(); //回收到缓存
mResLoader = null;
}
}
}
ResKitExample/ResKit/LoadAssetBundleResExample
バグ、ここのパッケージングが機能しません
それで、最初に私がやったことは、画像をResourcesに置き、それを取得するパスにResources/を追加することでした(最後のものはResources.Load(string path)です)。
ただし、最初のフォルダーにはリソースがないため、引き続き探します。
時計 ResKit のパッケージ化
01 ResMgr.Init() のメソッドでファイル名を見つけ (図 1、パッケージ化された画像を直接切り取った)、その後、この方法でパッケージ化されていることがわかりました (図 2) 02 以前の問題は、mResLoader.LoadSync で ResDatas.GetAssetData が見つかり、その中の 2 つの静的リストが空でした。つまり、asset_bindle_config はパッケージ化時に生成されないため、asset_bindle_config から何もロードされませんでした。
真ん中
using UnityEngine;
using UnityEngine.UI;
namespace QFramework.Example
{
public class AssetBundleResExample : MonoBehaviour
{
private ResLoader mResLoader = ResLoader.Allocate();
public RawImage RawImage;
private void Awake()
{
ResMgr.Init();
}
// Use this for initialization
void Start()
{
Transform canvasTrans = transform.FindTop("Canvas");
RawImage = canvasTrans.Find("RawImage").GetComponent<RawImage>();
//底层能够走的方法 ResDatas.GetAssetData
//RawImage.texture = mResLoader.LoadSync<Texture2D>("TestImage");
// 通过下边方式也一样
RawImage.texture = mResLoader.LoadSync<Texture2D>("testimage_png","TestImage");
}
private void OnDestroy()
{
mResLoader.Recycle2Cache(); //回收到缓存
mResLoader = null;
}
}
}
ResKitExample/ResKit/LoadResourcesResExample
上記と同じロジックで、「resources://」または「Resources/」を追加して他の論理ブランチに移動します。
using UnityEngine;
using UnityEngine.UI;
namespace QFramework.Example
{
public class LoadResourcesResExample : MonoBehaviour
{
public RawImage RawImage;
private ResLoader mResLoader = ResLoader.Allocate();
// Use this for initialization
private void Start()
{
RawImage.texture = mResLoader.LoadSync<Texture2D>("resources://TestTexture");
}
private void OnDestroy()
{
Log.I("On Destroy ");
mResLoader.Recycle2Cache();
mResLoader = null;
}
}
}
ResKitExample/ResKit
bug 空
実際の内容は、上記 2 つの例をまとめたものです。
しかし、3 番目のアセットは null ("assetobj_prefab", "AssetObj") を報告します。
GameObject prefab = mResLoader.LoadSync<GameObject>("assetobj_prefab", "AssetObj");
prefab.Instantiate()
.Name("这是使用通过 AssetName 和 AssetBundle 加载的对象");
時計の比較
バックトラッキングでは何が問題なのかわからないため、別のプレハブ、はい、UI オブジェクトをロードしてみてください
//回溯看不出哪里错了,所以试试加载其它预制体
GameObject prefab = mResLoader.LoadSync<GameObject>("uitestunirx_prefab", "UITestUniRx");
prefab.Instantiate()
.Name("这是使用通过 AssetName 和 AssetBundle 加载的对象");
見て比較するとラベルが少ないことがわかります
でもテストが終わったらそれが理由ではない
前のコードをコメントアウトしてみてください
LoadSync の方法には、リソース名を直接指定する方法、パッケージ名 + ファイル名を指定する方法の 2 つがあります。同じリソースに対して、使用できる LoadSync は 1 つだけです。どちらを先に使用しても、もう一方は空になります。
次の記述は、コードの 2 番目のブロック mResLoader.LoadSync("AssetObj") を報告します。
GameObject prefab = mResLoader.LoadSync<GameObject>("assetobj_prefab", "AssetObj");
//回溯看不出哪里错了,所以试试加载其它预制体 ,最终发现是QFramework标签
// GameObject prefab = mResLoader.LoadSync<GameObject>("uitestunirx_prefab", "UITestUniRx");
prefab.Instantiate()
.Name("这是使用通过 AssetName 和 AssetBundle 加载的对象");
mResLoader.LoadSync<GameObject>("AssetObj")
.Instantiate()
.Name("这是使用通过 AssetName 加载的对象");
合計を変更する
using System.IO;
using UnityEngine;
namespace QFramework.Example
{
public class ResKitExample : MonoBehaviour
{
private ResLoader mResLoader = ResLoader.Allocate();
private void Awake()
{
ResMgr.Init();
}
private void Start()
{
mResLoader.LoadSync<GameObject>("resources://GameObject")
.Instantiate()
.Name("这是使用 ResKit 加载的对象");
if (true)//二选一,选A,B就报空的那种
{
mResLoader.LoadSync<GameObject>("assetobj_prefab", "AssetObj")
//回溯看不出哪里错了,所以试试加载其它预制体 ,最终发现是QFramework标签
// mResLoader.LoadSync<GameObject>("uitestunirx_prefab", "UITestUniRx");
.Instantiate()
.Name("这是使用通过 AssetName 和 AssetBundle 加载的对象");
}
else
{
mResLoader.LoadSync<GameObject>("AssetObj")
.Instantiate()
.Name("这是使用通过 AssetName 加载的对象");
}
}
private void OnDestroy()
{
mResLoader.Recycle2Cache();
mResLoader = null;
}
}
}
ResKitExample/SpriteAtlas
using System.Collections;
using UnityEngine;
using UnityEngine.U2D;
using UnityEngine.UI;
namespace QFramework
{
/// <inheritdoc />
/// <summary>
/// 参考:http://www.cnblogs.com/TheChenLin/p/9763710.html
/// </summary>
public class TestSpriteAtlas : MonoBehaviour
{
[SerializeField] private Image mImage;
// Use this for initialization
private IEnumerator Start()
{
Transform canvasTrans = transform.FindTop("Canvas");
mImage=canvasTrans.GetComponentInChildren<Image>();
var loader = ResLoader.Allocate();
ResMgr.Init();
#if UNITY_2017_1_OR_NEWER
var spriteAtlas = loader.LoadSync<SpriteAtlas>("spriteatlas");
var square = spriteAtlas.GetSprite("Square");
Log.I(spriteAtlas.spriteCount);
mImage.sprite = square;
#endif
yield return new WaitForSeconds(5.0f);
loader.Recycle2Cache();
loader = null;
}
}
}
UIKitExample/UIExample
A=>B は、A が B を開けることができることを意味します。多くのスクリプトがあります。プロジェクトを参照してください。
1=>2
2=>3
2=>4
3=>5
star 中括弧の書き方
UniRx シリーズのチュートリアルを監視するためのスクリプト
Wang Xiaoti/UniRx 集中
UniRx シリーズのチュートリアル
は長いため、
再利用に適した静的クラスを投稿するかどうかを検討してください
UniRxExtensions
/****************************************************
文件:UniRxExtensions.cs
作者:lenovo
邮箱:
日期:2023/6/6 17:55:35
功能:
来源:https://www.bilibili.com/video/BV1EB4y1z7nY/?spm_id_from=333.337.search-card.all.click&vd_source=54db9dcba32c4988ccd3eddc7070f140
*****************************************************/
using System;
using System.Collections;
using System.Collections.Generic;
using UniRx;
using UnityEngine;
using Random = UnityEngine.Random;
//需要这两个
using UniRx;
using UniRx.Async;
using UniRx.Triggers;
/*
* AddTo,同生共死
* Subject,一个参数,多个用元组
* Where==if,过滤
* First,第一个才有效
* 括号里面的方法可以写 _=> ()=> 形参(比如unit,list)=>
* buffer,事件缓存,事件存一块可以一起输出
* 01 go.UpdateAsObservable() ;02 Observable.EveryUpdate().AddTo(this) 。01的好处是自动AddTo(go)上
* x协程返回IEnumerator,无法适应TryCatch
* ReactiveProperty,常用于UI的MVC
*/
public static partial class UniRxExtensions
{
#region 生命
/// <summary>首次载入且Go激活</summary>
public static void ExampleMonoBehaviour(this MonoBehaviour mono)
{
if (false)
{
DoAfterTime(mono);
DoUpdate(mono);
DoTimer(mono);
}
}
public static void ExampleGameObject(this GameObject go, MonoBehaviour mono)
{
if (false)
{
go.DoWhenHide();
go.DoWhenDestroy();
go.DoWhenMouseDown();
go.DoDelayMouseDown(2f);
go.DoDelayFrameMouseDown(2);
go.DoDelayMouseDownByUpdate(2f);
go.DoWhenCollide();
go.DoUpdate();
go.DoTimer(1f);
IDisposable disposable = go.DoUpdateDispose();//ifxxx,操作disposable
}
}
public static void BindInt(this ReactiveProperty<int> num,MonoBehaviour mono)
{
num
.Skip(1)//跳过第一次的赋值初始化阶段
.Subscribe(_ =>Debug.Log("ValueChange"))
.AddTo(mono);
}
#endregion
#region 辅助
public static void DoWhenHide(this GameObject go)
{
go
.OnDisableAsObservable()
.Subscribe(_ => Debug.Log("DoWhenHide"))
.AddTo(go);
}
public static void DoWhenDestroy(this GameObject go)
{
go
.OnDestroyAsObservable()
.Subscribe(_ => Debug.Log("DoWhenHide"))
.AddTo(go);
}
public static void DoWhenMouseDown(this GameObject go)
{
go
.OnMouseDownAsObservable()
.Subscribe(_ => Debug.Log("DoWhenMouseDown"))
.AddTo(go);
}
public static void DoDelayMouseDown(this GameObject go, float delay)
{
go
.OnMouseDownAsObservable()
.Delay(TimeSpan.FromSeconds(delay))
.Subscribe(_ => Debug.Log("DoDelayMouseDown"))
.AddTo(go);
}
public static void DoDelayFrameMouseDown(this GameObject go, int cnt)
{
go
.OnMouseDownAsObservable()
.DelayFrame( cnt )
.Subscribe(_ => Debug.Log("DoDelayMouseDown"))
.AddTo(go);
}
/// <summary>一般用于if(xxx){disposable.Dispose();}</summary>
public static IDisposable DoUpdateDispose(this GameObject go)
{
IDisposable disposable = go
.UpdateAsObservable()
.Subscribe(_ =>Debug.Log("DoUpdateDispose"))
.AddTo(go);
return disposable;
}
/// <summary>一般用于if(xxx){disposable.Dispose();}</summary>
public static IDisposable DoUpdateDispose(this GameObject go,CompositeDisposable compositeDisposable)
{
IDisposable disposable = go
.UpdateAsObservable()
.Subscribe(_ => Debug.Log("DoUpdateDispose"))
.AddTo(compositeDisposable);
return disposable;
}
public static void DoDelayMouseDownByUpdate(this GameObject go, float delay)
{
go
.UpdateAsObservable()
.Where( _=>
{
if (Input.GetMouseButtonDown(0))
{
Debug.Log("DoDelayMouseDownByUpdate点击鼠标左键");
return true;
}
return false;
})
.Delay(TimeSpan.FromSeconds(delay))
.Subscribe(_ => Debug.Log("DoDelayMouseDownByUpdate"))
.AddTo(go);
}
public static void DoWhenCollide(this GameObject go)
{
go
.OnCollisionEnterAsObservable()
.Subscribe(_ => Debug.Log("DoWhenCollide"))
.AddTo(go);
}
/// <summary>每隔2秒</summary>
public static void DoTimer(this MonoBehaviour mono)
{
Observable
.EveryUpdate()
.Sample(TimeSpan.FromSeconds(2f))
.Subscribe(_ => Debug.Log("DoTimer"))
.AddTo(mono);
}
public static void DoUpdate(this MonoBehaviour mono)
{
Observable
.EveryUpdate()
.Subscribe(_ => Debug.Log("DoUpdate"))
.AddTo(mono);
}
public static void DoUpdate(this GameObject go)
{
go
.UpdateAsObservable()
.Subscribe(_ => Debug.Log("DoUpdate"))
.AddTo(go);
}
public static void DoTimer(this GameObject go,float time)
{
go
.UpdateAsObservable()
.Sample(TimeSpan.FromSeconds(time))
.Subscribe(_ => Debug.Log("DoTimer"))
.AddTo(go);
}
public static void DoAfterTime(this MonoBehaviour mono)
{
Observable
.Timer(TimeSpan.FromSeconds(2f))
.Subscribe(_ => Debug.Log("DoAfterTime"))
.AddTo(mono);
}
#endregion
#region 系统
#endregion
#region 辅助
#endregion
}
UniRxExtensions.FirstLastTake
/****************************************************
文件:UniRxExtensions.FirstLastTake.cs
作者:lenovo
邮箱:
日期:2023/6/7 17:48:10
功能:
*****************************************************/
using System;
using System.Collections;
using System.Collections.Generic;
using UniRx;
using UniRx.Triggers;
using UnityEngine;
using UnityEngine.Events;
using Random = UnityEngine.Random;
public static partial class UniRxExtensions
{
public static void ExampleStart_Keyword(GameObject go)
{
//go.DoFirst();
//go.DoLast();
//go.DoTake(3);
//go.DoBuffer(60 * 25);
//go.DoMerge();
//go.DoReturn();
go.Do();
}
public static void DoFirst(this GameObject go)
{
go
.UpdateAsObservable()
.Where(_ => Input.GetMouseButtonDown(0))
.First(unit => true)
.Subscribe(_ => Debug.Log("DoFirst"))
.AddTo(go);
}
public static void DoLast(this GameObject go)
{
go
.UpdateAsObservable()
.Where(unit => Input.GetMouseButtonDown(0))
.Last(unit => true)
.Subscribe(_ => Debug.Log("DoLast"))
.AddTo(go);
}
public static void DoTake(this GameObject go, int cnt)
{
go
.UpdateAsObservable()
.Where(unit => Input.GetMouseButtonDown(0))
.Take(cnt)
.Subscribe(_ => Debug.Log("DoTake"))
.AddTo(go);
}
/// <summary>每cnt帧的时间输出一次</summary>
public static void DoBuffer(this GameObject go, int cnt)
{
go
.UpdateAsObservable()
.Buffer(cnt)
.Subscribe(_ => Debug.Log("DoBuffer"))
.AddTo(go);
}
public static void DoMerge(this GameObject go)
{
IObservable<Unit> disposable0 = go.UpdateAsObservable()
.Where(_ => Input.GetMouseButtonDown(0));
IObservable<Unit> disposable1 = go.UpdateAsObservable()
.Where(_ => Input.GetMouseButtonDown(1));
disposable0.Merge(disposable1)
.Subscribe(_ => Debug.Log("Mereg单击"))
.AddTo(go);
//相当于
//IObservable<Unit> disposable3 = go.UpdateAsObservable()
// .Where(_ => Input.GetMouseButtonDown(0) || Input.GetMouseButtonDown(1));
}
public static void DoReturn(this GameObject obj)
{
Debug.Log("DoReturn的前面");
Observable
.Return("DoReturn")
.Subscribe(Debug.Log)
.AddTo(obj);
}
/// <summary>提前筛选</summary>
public static void Do(this GameObject go)
{
go.UpdateAsObservable()
.Do(_ => Debug.Log("Do"))
.Subscribe(_ => Debug.Log("Do的Subscribe"))//不订阅就不会带引Do
.AddTo(go);
}
/// <summary>与Where、Delay等结合使用</summary>
public static void DoWithDo(this GameObject go)
{
go.UpdateAsObservable()
.Where(_ => Input.GetMouseButtonDown(0))
.Do(_ => Debug.Log("DoWhereDo按下了鼠标"))
.Delay(TimeSpan.FromSeconds(2f))
.Do(_ => Debug.Log("DoWhereDo延时2秒"))
.Subscribe(_ => Debug.Log("DoWhereDo的Subscribe"))//不订阅就不会带引Do
.AddTo(go);
}
public static void DoStartWith(this GameObject go)
{
Observable
.Return("baidu.com")
.StartWith("https://")
.Subscribe(_ => Debug.Log("DoStartWith的Subscribe"))
.AddTo(go);
}
}
UniRxExtensionsMonoBehavior.Start
/****************************************************
文件:UniRxExtensionsMonoBehaviour.Start.cs
作者:lenovo
邮箱:
日期:2023/6/8 22:40:42
功能:生命函数放这里
*****************************************************/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
public partial class UniRxExtensionsMonoBehaviour : MonoBehaviour
{
#region 生命
/// <summary>首次载入且Go激活</summary>
void Start()
{
//UniRxExtensions.ExampleMonoBehaviour(this);
//UniRxExtensions.ExampleGameObject(gameObject,this);
//UniRxExtensions.ExampleStart_Keyword(gameObject);
//Example_Scene();
//Example_ToObservable();
ExampleStart_Message();
}
#endregion
}
UniRxExtensionsMonoBehaviour.Message_ReactiveProperty
/****************************************************
文件:UniRxExtensionsMonoBehaviour.Message_ReactiveProperty.cs
作者:lenovo
邮箱:
日期:2023/6/7 17:48:10
功能:消息机制
*****************************************************/
using System;
using System.Collections;
using System.Collections.Generic;
using UniRx;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using Random = UnityEngine.Random;
public partial class UniRxExtensionsMonoBehaviour : MonoBehaviour
{
int msgId = 0;
ReactiveProperty<int> mReactiveProperty_Int = new ReactiveProperty<int>();
ReactiveProperty<string> mReactiveProperty_String = new ReactiveProperty<string>();
static int CurTextID = 3;
public void ExampleStart_Message()
{
if (CurTextID == 1)
{
MainThreadingMsg_Receive();//注册
MainThreadingMsg_Publish();//调用
MainThreadingMsg_Publish();
MainThreadingMsg_Publish();
}
//
if (CurTextID == 2)
{
ReactivePropertyChangeValue_Int();
mReactiveProperty_Int.Value++;//调用
mReactiveProperty_Int.Value++;
mReactiveProperty_Int.Value++;
}
//
if (CurTextID == 3)
{
//ReactivePropertyChangeValue_Int();//如果前面没注册
ReactivePropertyChangeValue_String();
mReactiveProperty_String.Value = Guid.NewGuid().ToString();
mReactiveProperty_Int.Value++;
mReactiveProperty_String.Value = Guid.NewGuid().ToString();
}
}
#region 辅助
void ReactivePropertyChangeValue_Int()
{
mReactiveProperty_Int
.Skip(1)//跳过初始化
.Subscribe(_=>Debug.Log("ReactivePropertyChangeValue_Int的Subscribe"))
.AddTo(this);
}
void ReactivePropertyChangeValue_String()
{
mReactiveProperty_String
.Skip(1)//跳过初始化
.Subscribe(_ => Debug.Log("ReactivePropertyChangeValue_String的Subscribe"))
.AddTo(this);
}
void ReactiveProperty_Merge()
{
mReactiveProperty_Int
.Select(_ => Unit.Default)
.Merge(mReactiveProperty_String.Select(_ => Unit.Default))
.Subscribe(_=>Debug.Log("ReactiveProperty_Merge的Subscribe"))
.AddTo(this);
}
/// <summary>多线程的消息,主线程下一帧Update收</summary>
void MultiThreadingMsg_Receive()
{
MessageBroker.Default.Receive<MsgTmp>()
.SubscribeOnMainThread()
.Subscribe(msgTmp =>
Debug.Log("MainThreadingMsg_Receive的Subscribe" + msgTmp.ToString()))
.AddTo(this);
}
/// <summary>单线程的消息,即发即收</summary>
void MainThreadingMsg_Publish()
{
MessageBroker.Default.Publish(new MsgTmp()
{
Idx = msgId,
Val = "绝区零"+ msgId.ToString(),
}) ;
msgId++;
}
void MainThreadingMsg_Receive()
{
MessageBroker.Default.Receive<MsgTmp>()
.Subscribe(msgTmp =>
Debug.Log("MainThreadingMsg_Receive的Subscribe"+msgTmp.ToString()))
.AddTo(this);
}
#endregion
#region 内部类
#endregion
class MsgTmp
{
public int Idx {
get; set; }
public string Val {
get; set; }
public override string ToString()
{
string str = "MsgTmp";
str += "\tIdx=" + Idx;
str += "\tVal=" + Val;
return str;
}
}
}
UniRxExtensionsMonoBehavior.Scene
/****************************************************
文件:UniRxExtensionsMonoBehaviour.Scene.cs
作者:lenovo
邮箱:
日期:2023/6/6 18:6:33
功能:
*****************************************************/
using System;
using System.Collections;
using System.Collections.Generic;
using UniRx;
using UnityEngine;
using Random = UnityEngine.Random;
public partial class UniRxExtensionsMonoBehaviour : MonoBehaviour
{
//意思是一部分放Start,一部分放Update,单用Dic好像搞错了,而且也不每关
Dictionary<Action,Action> startUpdateDic=new Dictionary<Action,Action>();
ReactiveProperty<int> numRp=new ReactiveProperty<int>(0);
//
IDisposable disposable;
CompositeDisposable compositeDisposable;
/// <summary>有场景交互部分</summary>
private void Example_Scene()
{
gameObject.FindTop("Go").ExampleGameObject(this );
numRp.BindInt(this);
//
GameObject Cube1 = gameObject.FindTop("Cube1");
Cube1.DoWhenCollide();
Cube1.DoWhenMouseDown();
//
disposable = gameObject.DoUpdateDispose();
//
disposable = gameObject.DoUpdateDispose(compositeDisposable);
//
disposable = gameObject.DoUpdateDispose(compositeDisposable);
compositeDisposable.AddTo(gameObject);
}
private void Example_SceneUpdate()
{
if (Input.GetMouseButtonDown(0))
{
numRp.Value++;
//
disposable.Dispose();
compositeDisposable.Dispose();
}
}
}
UniRxExtensions.ToObservable
/****************************************************
文件:UniRxExtensions.ToObservable.cs
作者:lenovo
邮箱:
日期:2023/6/7 17:48:10
功能:各种协程转Observable
*****************************************************/
using System;
using System.Collections;
using System.Collections.Generic;
using UniRx;
using UniRx.Triggers;
using UnityEngine;
using UnityEngine.Events;
using Random = UnityEngine.Random;
public partial class UniRxExtensionsMonoBehaviour:MonoBehaviour
{
void Example_ToObservable()
{
//IEnumeratorBody2Observable(enumerator());
IEnumeratorBody2Observable_TryCatch(enumerator_TryCatch());
//
//IEnumerator2ObservableBody();
//IEnumerator2ObservableBody_TryCatch();
}
#region 辅助
/// <summary>转,但方法块在IEnumeratorBody</summary>
void IEnumeratorBody2Observable( IEnumerator from)
{
from.ToObservable()
.DoOnCompleted(()=> Debug.Log("ConvertToObservable")) //这里_(报错)与()(不报错)是不同的
.Subscribe( _ => Debug.Log("ConvertToObservable的Subscribe"))
.AddTo(this);
}
/// <summary>转,但方法块在IEnumeratorBody</summary>
void IEnumeratorBody2Observable_TryCatch(IEnumerator from)
{
from.ToObservable()
.Catch<Unit, Exception>(expcetion =>
{
Debug.LogError("IEnumeratorBody2Observable_TryCatch的Catch<Unit, Exception>");
return Observable.ReturnUnit();
})
.DoOnCompleted(() => Debug.Log("IEnumeratorBody2Observable_TryCatch的DoOnCompleted(该异常不会阻碍DoOnCompleted的打印)")) //这里_(报错)与()(不报错)是不同的
.Subscribe(_ => Debug.Log("IEnumeratorBody2Observable_TryCatch的Subscribe"))
.AddTo(this);
}
IEnumerator enumerator(Action onComplted = null)
{
Debug.Log("enumerator的前");
yield return null;
Debug.Log("enumerator的后");
onComplted?.Invoke();
}
IEnumerator enumerator_TryCatch(Action onComplted = null)
{
int index = 0;
Debug.Log("enumerator的前");
yield return null;
Debug.Log("enumerator的后");
int[] arr = new int[0];
index = arr[0];
}
IObservable<Unit> Obs()
{
IObservable<Unit> res = Observable.ReturnUnit();
res.Do(_ => Debug.Log("IObservable<Unit>的前"))
.DelayFrame(5)
.Do(_ => Debug.Log("IObservable<Unit>的后"));
return res;
}
/// <summary>IObservable<Unit>解决IEnumerator的异常捕捉</summary>
IObservable<Unit> ObsTryCatch()
{
int index = 0;
IObservable<Unit> res = Observable.ReturnUnit();
res=res
.Do(_ => Debug.Log("IObservable<Unit>的前"))
.DelayFrame(5)
.Do(_ => Debug.Log("IObservable<Unit>的后"))
.Do( _=>
{
int[] arr = new int[0];
index = arr[0];
})
.Catch<Unit,Exception>( expcetion=>
{
Debug.LogError(" IObservable<Unit>的异常");
return Observable.ReturnUnit();
});
return res;
}
/// <summary>转,但方法块在Observable</summary>
void IEnumerator2ObservableBody()
{
Obs()
.DoOnCompleted(() => Debug.Log("IObservable<Unit>的DoOnCompleted"))
.Subscribe()
.AddTo(this);
StartCoroutine(Obs()
.DoOnCompleted(() =>
Debug.Log("IObservable<Unit>的StartCoroutine的DoOnCompleted"))
.ToYieldInstruction());
}
/// <summary>转,但方法块在Observable</summary>
void IEnumerator2ObservableBody_TryCatch()
{
ObsTryCatch()
.DoOnCompleted(() => Debug.Log("IObservable<Unit>的TryCatch的DoOnCompleted"))
.Subscribe()
.AddTo(this);
StartCoroutine(ObsTryCatch()
.DoOnCompleted(() =>
Debug.Log("IObservable<Unit>的TryCatch的StartCoroutine的DoOnCompleted"))
.ToYieldInstruction());
}
#endregion
}
ブロガーの inspironxdeUniRx シリーズをご覧ください (UniRX EventHandler は注意深く逆アセンブルされており、入門に適しています)
12.UniRx配列(FromEvent、FromEventPattern、Where、WhenAll、Never)
ボゴ 2010 を視聴する (代表者のスピーチ、分かりやすい)
C# のデリゲーションと各国語シリーズのイベントの説明 (1)
【未完成】TodoListメモデモ
位置
それを中の TodoList フォルダーにドラッグし、圧縮パッケージを変更すると、完全なプロジェクト (QF を含む) になります。
TodoItem
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
namespace QFramework.TodoList
{
public class TodoItem
{
public bool Completed;
public string Content;
public TodoItem(bool v1, string v2)
{
this.Completed = v1;
this.Content = v2;
}
}
}
Todoリスト
using QFramework;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
namespace QFramework.TodoList
{
public class TodoList
{
public List<TodoItem> mTodoItems;
}
}
プレハブ
デモは簡単すぎるので、コードを直接貼り付けるだけです
void CreatePrefab()
{
Transform UIRoot = transform.FindTop("UIRoot");//拖了一个QF的UIRoot预制体
Transform Design = UIRoot.FindChildDeep("Design");
Design.Show();
//
GameObject UITodoList = new GameObject("UITodoList");
UITodoList.SetParent(Design);
UITodoList.GetOrAddComponent<RectTransform>().Stretch();
//
GameObject text = new GameObject("Text");
text.SetParent(UITodoList);
text.GetOrAddComponent<RectTransform>().Stretch();
text.AddComponent<Text>().alignment = TextAnchor.UpperCenter;
text.AddComponent<UIMark>();
// 根据上面拖出UITodoList这个预制体,右键两个@ResKit-AssetBundle Mark 、@UIKit-Create UICode,生成相关脚本
//命名空间要改到,QFramework/Preferences
}
/// <summary>平铺开</summary>
public static RectTransform Stretch(this RectTransform rect)
{
rect.anchorMin = Vector2.zero;
rect.anchorMax = Vector2.one;
rect.sizeDelta = Vector2.zero;
return rect;
}
QFramework/設定エラーのバグ
バグ UIOKPanelData が存在しません
//
これはクラス名なので変更してください
01 エラーメッセージ
エラーを報告したため、名前空間 QFramework.Example を名前空間 QFramework.TodoList に手動で変更しました。図1
02 スクリプトの場所
場所は、Assets/QFramework/Framework/0.Core/Editor/1.PackageManager/Window/PackageKitWindow.cs です。
public class PackageKitWindow : QEditorWindow
{
[MenuItem(FrameworkMenuItems.Preferences, false, FrameworkMenuItemsPriorities.Preferences)]
private static void Open()
{
03 ショートカットキーリピート
Ctrl+E (%e) のショートカットキーを見つけてそれを繰り返し、QF を学ぶ前に個人ライブラリ Common にいくつか持っていって、個人のものを先にコメントアウトしました。
04 jsonファイルがありません
05 TodoList 圧縮パッケージ内のスクリプトを見つけてコピーします
レポートが空です
これまでのところ、最新バージョンにジャンプします
バグ
これはsikアカデミーのビデオの下にある情報です。QFは少し古いため、いくつかの間違いがあります。使用はお勧めしませんが、サンプルとチュートリアル ドキュメントが含まれている最新バージョンを https://github.com/liangxiegame/QFramework からダウンロードすることをお勧めします。