【主跑例子】 Framework01、02;QFramework00(我跟着视频的旧版本,但推荐用最新的)、01(无)、02(无)、03(无)

总体介绍

做的是 00,10,13,考虑做10。
11,12没下载,当时把这两个误认为 00,10
用到了UniRx

Framework有2个
00 Unity 游戏框架搭建 2019 第一季 C# 核心知识与简易 Manager Of Managers 框架搭建 120课数
01 Unity 游戏框架搭建 2019 第二季 模块/系统设计、命名、测试(资源管理/热更新) 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

public
大写Xxx

---------------------------------------------------

00 第一季 C# 核心知识与简易 Manager Of Managers 框架搭建

在这里插入图片描述

消息 MonoBehaviour与MsgDispatcher

/****************************************************
    文件: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(将MsgDispatcher内置到MonoBehaviour)

/****************************************************
    文件: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 第二季 模块/系统设计、命名、测试(资源管理/热更新)

bug TestFramework报错

增加了这两个
文件夹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();
		}
	}
}

stars Directory.CreateDirectory

    /// <summary>文件夹有就好,没有就创建</summary>
    public static void Folder_New(string path)
    {
        if (Directory.Exists(path) == false) //输出path
        {
            Directory.CreateDirectory(path);
        }

    }

stars 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();
    }

}





bug 打包时 ‘MenuItemAttribute’ could not be found

The type or namespace name ‘MenuItemAttribute’ could not be found
报错是AB包,报错是跳到打package的脚本

bug Test的dll引用

这个Alt+回车可以解决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缺少引用

在这里插入图片描述

原版有这两个

在这里插入图片描述

bug ‘EditorUserBuildSettings’ does not exist

The type or namespace name ‘EditorUserBuildSettings’ does not exist in the namespace ‘UnityEditor’
程序集对 Editor的勾选问题。
我这里是新建了一个程序集Common,想把一些脚本复制过来,当时Common程序集没勾选Editor。

watch TestFramework

安装TestFramework,import所有案例(此时只有1.3.4才有案例)
案例2开始可以进行Test
在这里插入图片描述

案例02 Exercise 1_ Solution

在这里插入图片描述
在这里插入图片描述

主脚本


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));
        }
    }
}

bug 凉鞋的Test(其中的文件夹)

程序集设置

我这里对着 案例02 的 程序集 复制过来 改名字的
然后Editor文件架下的只勾选Editor

程序集设置 不同处

其它文件架下的,勾选any。
在这里插入图片描述

程序集设置 相同处

上面的设置一样还没报错(盲猜V0_0_4引用了UnityEditor.TestRunner可能有问题)
直接导入凉鞋的包会报错,就是这个引用的问题
在这里插入图片描述

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_4Editor

#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

在这里插入图片描述

总结 Test文件夹跑通了

bug 不支持 “EmbeddedLinux”,

    "EmbeddedLinux",报错不支持,

在这里插入图片描述

在这里插入图片描述

watch 凉鞋的Playground(其中的文件夹)

也是赋值修改一个程序集,根据它的引用,去放一个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
	}
}

在这里插入图片描述

bug ‘MenuItem’ could not be found

00 程序及设置没包括Editor
00 放到根目录

bug 过时 UnityEditor.BuildTarget

在这里插入图片描述

watch 凉鞋的AssetBundleExample

注意的是
01 打的两个AB包是6
02 打包的两个方式是 1,4 ,结果都一样,重复打包被自动覆盖
03 用包的前提是不能勾选2
04 用包的两个例子是 3,5
在这里插入图片描述
在这里插入图片描述

bug 导包时的时间

一直认刚开始导包的时间,后面导出的还是开始的时间
DateTime.Now.ToString() 用法

    private static string GeneratePackageName()
    {
      // return "QFramework_" + DateTime.Now.ToString("yyyyMMddHHMM");///注意年小写的yyyy
        return "Common_" + DateTime.Now.ToString("yyyyMMddHHmm");///注意年小写的yyyy
    }

bug 一些Editor的类没识别到

我复制一些相同的脚本到自己的另一个程序集。报错了,如下图将这3个脚本拖到最外面的Editor就正常。
后来发现是 #UNITY_EDITOR的问题(包裹住MenuItem)
。。。
原因盲猜Unity识别不了程序集中的 Editor 中的脚本,需要手动加#UNITY_EDITOR
。。。
原版直接就正常的不需要拖,因为凉鞋直接手写 namespace,不采用程序集的方式。
在这里插入图片描述

---------------------------------------------------

13 框架搭建 决定版:理论强化篇(第三季)

---------------------------------------------------

10 简介 QFramework 使用指南

01 链式编程风格突出(针对回调,计时的)
02 Action => Res => UI (后者基于前者)。对应的里面有Example(示例),Action => Res => UI外加一个libs

modify 我做了什么

01 写注释(Unity的代码就是不能自己写注释,不友好。哪怕通过xml之类的实现注释与代码的分离,只要我悬停鼠标有说明就好了),如图一
02 摘Extensions(框架暂时用你的,Extensions容易抄,整合进我的,也是对自己的Extensions的整理(拖进这个工程没报错))
在这里插入图片描述

watch 2017.3.xxx

直接一样用2017.3左右的版本不会报错导致运行不了,还自动弹出DoTween的面板。
但是还会抛这个错误
在这里插入图片描述

bug 2020.3.23f1c1

modify 引入库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); }
            );
        }
    }
}

bug 程序集设置

直接导进入,直接使用自动生成的CSharp和Editor两个项目是没有问题的。如图一。
但是导入自带的库,带有的程序集要设置下(看着QFramework的其它程序集设置的,RootName好像感谢也没关系 )。如图二。
主要是 存在同名的 类 ,需要加限定。具体看下一条
图一

图二

bug ResMgr、UIMgr等命名在两个程序集之间冲突

因为要用的ResMgr在QFramework是单例类,不是类型(不确定是不是这原因),用不了using xxx=xxx的形式(这个是客观存在的,加了也没用),只能都加限定 QFramework.ResMgr

bug 项目模块识别有误

圈圈中的 (未找到)
Assets/QFramework/Framework/3.EditorToolKit/Editor/UnityEditorRushTools/CustomHierarchy.cs
重新导入,正常没问题的。
在这里插入图片描述

半用 注释掉报错的那5个地方

这5个属于在unity2018被弃用的。但我没找到类似的替代
Assets/QFramework/Framework/3.EditorToolKit/Editor/UnityEditorRushTools/CustomHierarchy.cs
我标了TODO。如图一
。。。
untiy2017还能找到,如图二
unity2020找到不到(好歹给个Obsolute)
手册显示过期
NetworkIdentity
图一

图二 unity2017.3.xxx

没用 删VS缓存

删VS缓存

没用 改为ILCpp

所以又改回默认的Mono

bug unity没报错,VS报错。但能运行

随便截一个,引用关系有啊,如图二
在这里插入图片描述
图二

watch 总结

01 程序集设置,看里面的其它程序集来设置
02 命名冲突,加限定,我冲突了 ResMgr,UIMgr
03 5个过时语句,暂时注释掉

bug 一个总存在的报错

重新导入+注释那5句过时的
可以考到没其他报错。只有一个不管什么版本都报的错
在这里插入图片描述

bug MonoComplier.Tick

修改增删 程序集 时,多次卡死这 处理条。
就是编译错误。很可能只能任务管理器强制退出,并且下次进入有 EnterSafeMode 的选择面板
在这里插入图片描述
在这里插入图片描述

watch 项目结构

在这里插入图片描述

01 延时

3种计时写法,2种开协程,一种主线程
底层都是 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");
    }
}

在这里插入图片描述

bug 标点符号写哪边

因为 + - * /和链式编程的 “.”
还是觉得放左边比较泛用。
。。。。。。
但是用过VS,发现,你在比如“,”前面回车,不会自动缩进,“,”后面回车就会自动缩进。
我以为的跟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();

watch 注释

其实我不理解为什么宁愿这样写注释(下),也不愿写summary的注释(上)(哪怕只是做教程)
太熟悉了?
简洁?
编译快?
在这里插入图片描述

bug 程序集和命名空间的关系

使用一个方法Identity()同名,完全一样,使用位置是 (程序集CSharp,命名空间QFramework.Example),图中2。
同名一个在( 程序集Common && 没有命名空间),图中1。
同名一个在(程序集QFramework.Core.Runtime && 命名空间QFramework),图中3。
。。。
程序集程序集Common,QFramework.Core.Runtime 都是Auto Refrenced
系统自动认的是 第二个
。。。
不清楚因素,认最近文件夹路径?
命名空间和程序集
在这里插入图片描述

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

都是看脚本,所以有了下一条的收录
在这里插入图片描述

modify 如果你需要收录一些可以转移(转移影响不大)的脚本

01 UnityAPIExtensions.cs
02 DotNetExtensions.cs
A Framework.Core.Runtime
B Framework.Core.Editor
C Common(你自己的)
。。。
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 我们刚上手的,直接拆类(一个类一个脚本)
02 按命名空间分 QFramework.、 QFramework.Example和暴露的(CSharp)
03 看脚本时,看到PCClient,MobileServer(不清楚Clent要用PC做定语言,Server要用Mobile作定语)
在这里插入图片描述

拉父类

在这里插入图片描述

打包Client,uity运行Server

在这里插入图片描述

打包Server,unity运行Client

bug 打包的运行后找不到资源

预制体的路径保持不变,我加了文件夹Prefabs,放在里面。这个没影响
01 打AB包,图2

在这里插入图片描述
图2

bug 找到不到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,拖进预制体,打包,Build

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;
            }

bug 套接字不能重复

reimport解决的

bug 突然间不能附加进程调试

先了解引用关系
以前有一种解决方式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


}


bug IL2CPP

改回Mono
在这里插入图片描述

LibsExample/SingletonExample/0.Singleton

Singleton
MonoSingleton
ISingleton,MonoBehaviour
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
两个脚本,都是partial,脚本1命名为 XxxComponents(我改成Xxx.Components),脚本2叫Xxx

watch 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;
	}
}

watch 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);
		}
	}
}

watch 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      

    }
}


watch 01 效果

在这里插入图片描述

watch 02 效果

检测双击的

在这里插入图片描述

网图WWW

在这里插入图片描述

监听一个布尔值

在这里插入图片描述

监听一个列表

单独贴一下。
运行时,Add一下,后面自动Change
Remove一下,后面也自动Change
在这里插入图片描述

        /// <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("-------------------------------");
        }

监听Transform

在这里插入图片描述

LibsExample/UniRxExample/OfficialExamples

Sample01_ObservableWWW

只写方法,自己用MonoBehaviour来调用

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
        }

在这里插入图片描述

from、select

在这里插入图片描述

        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();
            }
        }

WhenAll

在这里插入图片描述

       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();
            }
        }

WWWErrorException

在这里插入图片描述

       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

一个打印数字
一个请求网址,有时会报错(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

运行了两次,第二次单击鼠标结束协程
在这里插入图片描述

#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));
        }
    }
}

Sample09_EventHandling

StartTest01

按下Q
在这里插入图片描述

StartTest02

在这里插入图片描述

StartTest03

在这里插入图片描述

StartTest04

在这里插入图片描述

StartTest05

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");
        }
    }
}

Sample11_Logger

需要启动脚本
在这里插入图片描述

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"));
        }
    }
}

Sample12_ReactiveProperty

在这里插入图片描述

// 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

Sample13_ToDoApp

bug

节点丢失
ToDoList这个节点大小盖住了下面的按钮(此时没有Mask),意味着加了一个Item后,下面的按钮就失效了

主体

在这里插入图片描述

// 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!")
在这里插入图片描述

协程

里面的类没了,报错

收,相当于订阅Up主的粉丝

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;
			}
		}
	}
}

发,相当于Up主

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);
		}

Player ,相当于粉丝

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

    }


}

ManagerOfManagersExample

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

watch 看总体运行

在这里插入图片描述

bug VS删除断点后,错误列表还保存着

modify 从打AB包创建文件夹的拓展方法,转移所在脚本的所有内容到自己的库

其中用到Log的dll,复制即可

ResKitExample/Audio

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/Pool

在这里插入图片描述
在这里插入图片描述

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

bug 走这里的打包不行

在这里插入图片描述
所以一开始做的是:图片放Resources,路径加 Resources/ 能拿到( 最后走的是Resorces.Load(string path))
在这里插入图片描述

但是初始文件夹是没有Resources的,所以继续找

watch ResKit中打包

01 在ResMgr.Init()的方法中找到了一个文件名(图一,直接截打包好的图),然后顺藤摸瓜发现,通过这个方式打包(图二)
02 之前卡的是,mResLoader.LoadSync中找到 ResDatas.GetAssetData,里面的两个静态列表都是空的,也就是没有从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 空

实际内容是将上面两个例子汇总了一下。
但是第三条的Asset报null,(“assetobj_prefab”, “AssetObj”)。

            GameObject prefab = mResLoader.LoadSync<GameObject>("assetobj_prefab", "AssetObj");
            prefab.Instantiate()
				.Name("这是使用通过 AssetName  和 AssetBundle 加载的对象");

在这里插入图片描述

watch 对比

回溯看不出哪里错了,所以试试加载其它预制体,可以的,一个UI物体
在这里插入图片描述

            //回溯看不出哪里错了,所以试试加载其它预制体
            GameObject prefab = mResLoader.LoadSync<GameObject>("uitestunirx_prefab", "UITestUniRx");
            prefab.Instantiate()
				.Name("这是使用通过 AssetName  和 AssetBundle 加载的对象");

watch 然后对比发现少了标签

但测试完不是这原因
在这里插入图片描述

watch 注释掉前面的代码就可以

就是有两种 LoadSync方式,直接资源名、包名+文件名。同一种资源,只能采用一种 LoadSync。先用谁,另一个就报空。
下面的写法就会报空第二块代码 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 加载的对象");

modify 总的

在这里插入图片描述


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 一种花括号的写法

在这里插入代码片

watch UniRx系列教程的脚本

王小梯 / 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);
    }

}




UniRxExtensionsMonoBehaviour.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;
        }
    }
}





UniRxExtensionsMonoBehaviour.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



}




watch 博主 inspironxdeUniRx系列(对UniRX的EventHandler拆解得很仔细,适合入门)

12.UniRx序列(FromEvent、FromEventPattern、Where、WhenAll、Never)

watch 波哥2010 (讲delegate,讲得易懂)

大白话系列之C#委托与事件讲解(一)

【未完成】TodoList备忘录Demo

位置

拖入里面的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;
        }
    }
}

TodoList

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;
    }

bug QFramework/Preferences报错

bug UIOKPanelData不存在

在这里插入图片描述

//
看了,也就是所在类名,改一下

在这里插入图片描述

01 错误信息

我报错了,所以手动改namespace QFramework.Example 为 namespace QFramework.TodoList。图一
在这里插入图片描述

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压缩包找该脚本复制

报空
至此,跳到最新版本

bug

这是sik学院视频下的资料,QF有点老了,也有一些报错。不建议用,建议到https://github.com/liangxiegame/QFramework下载最新的,里面例子,教程文档什么都有。

---------------------------------------------------

---------------------------------------------------

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
axure-chrome-extension.crx是Axure网页原型设计工具的扩展文件。Axure是一款强大的交互式原型设计软件,用于创建高保真度的网页、应用程序和其他用户界面设计。Axure的Chrome扩展提供了便捷的方式,可以将Axure原型设计直接预览在Chrome浏览器中。 要下载axure-chrome-extension.crx,可以按照以下步骤进行操作: 第一步,打开浏览器,进入Axure的官方网站(https://www.axure.com/)。 第二步,在Axure官方网站上,找到并点击下载页面的链接,通常位于主页顶部菜单或页面底部。 第三步,在下载页面上,浏览页面内容,找到与Chrome扩展相关的下载链接或按钮。通常会提供多种下载选择,包括用于不同浏览器的扩展文件。 第四步,点击与Chrome相关的下载链接或按钮,开始下载axure-chrome-extension.crx文件。 第五步,等待下载完成。下载速度取决于您的互联网连接速度和文件大小。 第六步,下载完成后,打开Chrome浏览器。 第七步,将下载的axure-chrome-extension.crx文件拖放到Chrome浏览器的扩展管理页面。您可以通过输入"chrome://extensions/"在地址栏中访问该页面。 第八步,Chrome浏览器会自动安装axure-chrome-extension.crx文件,并在安装完成后显示扩展的图标。 通过上述步骤,您可以成功下载并安装axure-chrome-extension.crx文件,开始使用Axure的Chrome扩展,方便预览和测试您的原型设计。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值