做的是 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
/****************************************************
文件: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 );
}
}
/****************************************************
文件: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()
{
}
}
增加了这两个
文件夹Tests,加了包TestFramework但还报错,索性先删了,
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);
}
}
}
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();
}
}
}
/// 文件夹有就好,没有就创建
public static void Folder_New(string path)
{
if (Directory.Exists(path) == false) //输出path
{
Directory.CreateDirectory(path);
}
}
/****************************************************
文件: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();
}
}
The type or namespace name ‘MenuItemAttribute’ could not be found
报错是AB包,报错是跳到打package的脚本
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
}
}
The type or namespace name ‘EditorUserBuildSettings’ does not exist in the namespace ‘UnityEditor’
程序集对 Editor的勾选问题。
我这里是新建了一个程序集Common,想把一些脚本复制过来,当时Common程序集没勾选Editor。
安装TestFramework,import所有案例(此时只有1.3.4才有案例)
案例2开始可以进行Test
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));
}
}
}
我这里对着 案例02 的 程序集 复制过来 改名字的
然后Editor文件架下的只勾选Editor
上面的设置一样还没报错(盲猜V0_0_4引用了UnityEditor.TestRunner可能有问题)
直接导入凉鞋的包会报错,就是这个引用的问题
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());
}
}
}
#if UNITY_EDITOR
using NUnit.Framework;
namespace QFramework
{
public class V0_0_4
{
class MonoSingletonTestClass : MonoSingleton<MonoSingletonTestClass>
{
}
[Test]
public void MonoSingeltonTest()
{
var instanceA = MonoSingletonTestClass.Instance;
var instanceB = MonoSingletonTestClass.Instance;
Assert.AreEqual(instanceA.GetHashCode(), instanceB.GetHashCode());
Assert.AreEqual(instanceA.name, "MonoSingletonTestClass");
}
}
}
#endif
"EmbeddedLinux",报错不支持,
也是赋值修改一个程序集,根据它的引用,去放一个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
}
}
00 程序及设置没包括Editor
00 放到根目录
注意的是
01 打的两个AB包是6
02 打包的两个方式是 1,4 ,结果都一样,重复打包被自动覆盖
03 用包的前提是不能勾选2
04 用包的两个例子是 3,5
一直认刚开始导包的时间,后面导出的还是开始的时间
DateTime.Now.ToString() 用法
private static string GeneratePackageName()
{
// return "QFramework_" + DateTime.Now.ToString("yyyyMMddHHMM");///注意年小写的yyyy
return "Common_" + DateTime.Now.ToString("yyyyMMddHHmm");///注意年小写的yyyy
}
我复制一些相同的脚本到自己的另一个程序集。报错了,如下图将这3个脚本拖到最外面的Editor就正常。
后来发现是 #UNITY_EDITOR的问题(包裹住MenuItem)
。。。
原因盲猜Unity识别不了程序集中的 Editor 中的脚本,需要手动加#UNITY_EDITOR
。。。
原版直接就正常的不需要拖,因为凉鞋直接手写 namespace,不采用程序集的方式。
01 链式编程风格突出(针对回调,计时的)
02 Action => Res => UI (后者基于前者)。对应的里面有Example(示例),Action => Res => UI外加一个libs
01 写注释(Unity的代码就是不能自己写注释,不友好。哪怕通过xml之类的实现注释与代码的分离,只要我悬停鼠标有说明就好了),如图一
02 摘Extensions(框架暂时用你的,Extensions容易抄,整合进我的,也是对自己的Extensions的整理(拖进这个工程没报错))
直接一样用2017.3左右的版本不会报错导致运行不了,还自动弹出DoTween的面板。
但是还会抛这个错误
像这种,真的是忍不住想用自己的库。
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
//mBtnMove.onClick.AddListener(() => { mCube.transform.DOMoveX(5, 1f); });
mBtnMove = transform.FindTop("Canvas").GetButtonDeep
(
"BtnMove"
,() => { mCube.transform.DOMoveX(5, 1f); }
);
}
}
}
直接导进入,直接使用自动生成的CSharp和Editor两个项目是没有问题的。如图一。
但是导入自带的库,带有的程序集要设置下(看着QFramework的其它程序集设置的,RootName好像感谢也没关系 )。如图二。
主要是 存在同名的 类 ,需要加限定。具体看下一条
因为要用的ResMgr在QFramework是单例类,不是类型(不确定是不是这原因),用不了using xxx=xxx的形式(这个是客观存在的,加了也没用),只能都加限定 QFramework.ResMgr
圈圈中的 (未找到)
Assets/QFramework/Framework/3.EditorToolKit/Editor/UnityEditorRushTools/CustomHierarchy.cs
重新导入,正常没问题的。
这5个属于在unity2018被弃用的。但我没找到类似的替代
Assets/QFramework/Framework/3.EditorToolKit/Editor/UnityEditorRushTools/CustomHierarchy.cs
我标了TODO。如图一
。。。
untiy2017还能找到,如图二
unity2020找到不到(好歹给个Obsolute)
手册显示过期
NetworkIdentity
删VS缓存
所以又改回默认的Mono
01 程序集设置,看里面的其它程序集来设置
02 命名冲突,加限定,我冲突了 ResMgr,UIMgr
03 5个过时语句,暂时注释掉
重新导入+注释那5句过时的
可以考到没其他报错。只有一个不管什么版本都报的错
修改增删 程序集 时,多次卡死这 处理条。
就是编译错误。很可能只能任务管理器强制退出,并且下次进入有 EnterSafeMode 的选择面板
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 执行完成");
}
}
}
}
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 执行完成");
}
}
}
}
报AB包还是资源的错
using UnityEngine;
using QFramework;
using ResMgr = QFramework.ResMgr;
public class AudioTest : MonoBehaviour
{
private void Start()
{
ResMgr.Init();
//
AudioManager.Instance.SendMsg(new AudioSoundMsg("TestSound"));
AudioManager.Instance.SendMsg(new AudioMusicMsg("BackGroundMusic"));
AudioManager.Instance.SendMsg(new AudioStopMusicMsg());
AudioManager.PlaySound("TestSound");
AudioManager.PlayMusic("BackgroundMusic");
}
}
因为 + - * /和链式编程的 “.”
还是觉得放左边比较泛用。
。。。。。。
但是用过VS,发现,你在比如“,”前面回车,不会自动缩进,“,”后面回车就会自动缩进。
我以为的跟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();
其实我不理解为什么宁愿这样写注释(下),也不愿写summary的注释(上)(哪怕只是做教程)
太熟悉了?
简洁?
编译快?
使用一个方法Identity()同名,完全一样,使用位置是 (程序集CSharp,命名空间QFramework.Example),图中2。
同名一个在( 程序集Common && 没有命名空间),图中1。
同名一个在(程序集QFramework.Core.Runtime && 命名空间QFramework),图中3。
。。。
程序集程序集Common,QFramework.Core.Runtime 都是Auto Refrenced
系统自动认的是 第二个
。。。
不清楚因素,认最近文件夹路径?
命名空间和程序集
举了3种示例
GameObject:Object
MonoBehaviour:Behaviour:Component:Object
Transform:Component:Object
using UnityEngine;
namespace QFramework.Example
{
///
/// CEGO EXAMPLE:GameObject 链式调用支持
///
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
}
}
}
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
//mBtnMove.onClick.AddListener(() => { mCube.transform.DOMoveX(5, 1f); });
mBtnMove = transform.FindTop("Canvas").GetButtonDeep
(
"BtnMove"
,() => { mCube.transform.DOMoveX(5, 1f); }
);
}
}
}
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
。。。
可以看到没报
底层应该是找程序集,找类型,
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();
}
}
}
}
01 我们刚上手的,直接拆类(一个类一个脚本)
02 按命名空间分 QFramework.、 QFramework.Example和暴露的(CSharp)
03 看脚本时,看到PCClient,MobileServer(不清楚Clent要用PC做定语言,Server要用Mobile作定语)
预制体的路径保持不变,我加了文件夹Prefabs,放在里面。这个没影响
01 打AB包,图2
有打在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;
}
reimport解决的
先了解引用关系
以前有一种解决方式reImport
UniRx.Async:
UniRx.Async.Editor:UniRx.Async
UniRx:UniRx.Async
UniRx.Example:UniRx、UniRx.Async
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
);
}
}
}
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
}
Singleton
MonoSingleton
ISingleton,MonoBehaviour
ISingleton
单例执行删除,但静态变量仍然存在着
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);
}
}
}
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");
}
}
}
一个预制体,叫Xxx
两个脚本,都是partial,脚本1命名为 XxxComponents(我改成Xxx.Components),脚本2叫Xxx
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;
}
}
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);
}
}
}
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
{
///
/// 2018/3/30
///
public class TestUniRx : MonoBehaviour
{
#region 字属
public static readonly UniRx.Diagnostics.Logger log = new UniRx.Diagnostics.Logger("L Log");
//IReactiveProperty isChange = new ReactiveProperty(false);
[Header("ReactiveSubscribe的")]
private CompositeDisposable disposables = new CompositeDisposable();
/// ReactiveSubscribe的初始符
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 辅助
/// 双击
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);
}
/// 属性
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);
}
/// 协程
void Coroutine()
{
Sample10_MainThreadDispatcher temp = new Sample10_MainThreadDispatcher();
CurrentSub = temp.Run();
Debug.Log(temp);
}
/// GameObj
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
void TsfSubscribe()
{
CurrentSub = transform
.ObserveEveryValueChanged(x => x.position)
.Subscribe(x => Debug.Log(x));
}
#endregion
#region 内部类
/// 从Assets/QFramework/Example/LibsExample/UniRxExample/OfficialExamples/Sample10_MainThreadDispatcher.cs
/// 复制修改的类
/// 都运行打印很乱,可以注释其它一个一个运行
///
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
}
}
单独贴一下。
运行时,Add一下,后面自动Change
Remove一下,后面也自动Change
/// GameObj
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("-------------------------------");
}
只写方法,自己用MonoBehaviour来调用
///
private void StartTest01()
{
// Basic: Download from google.
//ObservableWWW.Get("http://google.co.jp/") //我这边超时错误
ObservableWWW
.Get("https://baidu.com/")//返回
.Subscribe(
onNext: res => Debug.Log(res.Substring(0, 100)), // onSuccess
onError: error => Debug.LogException(error)); // onError
}
private void StartTest02()
{
int textId = 2;//外网测不了时
if(textId == 1)
{
// Linear Pattern with LINQ Query Expressions
// download after google, start bing download
var query = from google in ObservableWWW.Get("http://google.com/")
from bing in ObservableWWW.Get("http://bing.com/")
select new { google, bing };
var cancel = query.Subscribe(x => {
Debug.LogFormat("{0}:{1}"
, x.google.Substring(0, 100)
, x.bing.Substring(0, 100));
});
// Call Dispose is cancel downloading.
cancel.Dispose();
}
if(textId ==2)//有时会报错Empty reply from server,多运行几下
{
var query = from baidu in ObservableWWW.Get("http://baidu.com/")
from sougou in ObservableWWW.Get("http://sougou.com/")
select new { baidu, sougou };
var cancel = query
.Subscribe(res => {
Debug.Log(res.baidu);
Debug.Log(res.sougou);
Debug.LogFormat("{0}:{1}"
, res.baidu.Substring(0, 5)
, res.sougou.Substring(0, 5));
});
// Call Dispose is cancel downloading.
//cancel.Dispose();
}
}
private void StartTest03_WhenAll()
{
int curID = 2;
if (curID == 1)
{
// Observable.WhenAll is for parallel asynchronous operation
// (It's like Observable.Zip but specialized for single async operations like Task.WhenAll of .NET 4)
var parallel = Observable.WhenAll(
ObservableWWW.Get("http://google.com/"),
ObservableWWW.Get("http://bing.com/"),
ObservableWWW.Get("http://unity3d.com/"));
parallel.Subscribe(xs =>
{
Debug.Log(xs[0].Substring(0, 100)); // google
Debug.Log(xs[1].Substring(0, 100)); // bing
Debug.Log(xs[2].Substring(0, 100)); // unity
});
}
if (curID == 2)
{
//意思是res的复数
var reses = Observable.WhenAll(
ObservableWWW.Get("https://baidu.com/")
, ObservableWWW.Get("https://sougou.com/")
, ObservableWWW.Get("https://www.bilibili.com/")
);
reses.Subscribe(res =>
{
Debug.Log(res[0].Substring(0, 100));
Debug.Log(res[1].Substring(0, 100));
Debug.Log(res[2].Substring(0, 100));
});
}
}
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();
}
}
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();
}
}
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);
}
}
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")
);
}
}
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_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 生命
/// 首次载入且Go激活
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
}
}
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
一个打印数字
一个请求网址,有时会报错(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 辅助
/// =Range(1, 10),然后Return(100)
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
}
}
#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
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));
}
}
}
#pragma warning disable 0067
using System;
using System.Reflection;
using UnityEngine;
namespace UniRx.Examples
{
public class Sample09_EventHandling : MonoBehaviour
{
#region 字属
/// Foo,function object Oriented,即面向对象函数,原命名为FooBar
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 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, 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
结果写在注释里面
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 生命
/// 首次载入
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);
}
/// 运行一次
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();
}
/// 运行一次
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");
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
namespace UniRx.Examples
{
public class Sample11_LoggerStart : MonoBehaviour
{
#region 生命
/// 首次载入且Go激活
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
// You can subscribe and output to any place.
// 初始化
ObservableLogger.Listener.LogToUnityDebug();
// for example, filter only Exception and upload to web.
// (make custom sink(IObserver) 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"));
}
}
}
// 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
节点丢失
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
一个注册事件(发东西的,被观察的)
一个观察者(收东西的,被调用的,可以被调用方法,这里的例子是被调用了一个 参数"Hello World!")
里面的类没了,报错
using UnityEngine;
namespace QFramework
{
public class EventGet : MonoBehaviour
{
void Start ()
{
QEventSystem.RegisterEvent(TestEvent.TestOne,GetEvent);
}
void GetEvent(int key, params object[] obj)
{
switch (key)
{
case (int)TestEvent.TestOne:
this.LogInfo(obj[0].ToString());
break;
}
}
}
}
using UnityEngine;
using UniRx;
namespace QFramework
{
public class EventTest : MonoBehaviour
{
void Start()
{
Observable
.EveryUpdate()
.Subscribe( _ =>
QEventSystem.SendEvent(TestEvent.TestOne,"Hello World!"));
}
}
}
using UnityEngine;
namespace QFramework
{
public enum TestEvent
{
TestOne
}
}
给的ID跑的逻辑是没有的,需要取消注释 ForwardMsg(tmpMsg); 我放到了任务列表
namespace QFramework
{
using UnityEngine;
[QMonoSingletonPath("[Event]/QMsgCenter")]
public partial class QMsgCenter : MonoBehaviour, ISingleton
{
......
public void SendMsg(QMsg tmpMsg)
{
......
// TODO case (int)PlayerEvent.Run:
ForwardMsg(tmpMsg);
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace QFramework.Example
{
public class Player : QMonoBehaviour
{
private IManager mManager;
// Use this for initialization
void Start()
{
RegisterEvent(PlayerEvent.Run);
}
// Update is called once per frame
protected override void ProcessMsg(int eventId, QMsg msg)
{
switch (eventId)
{
case (int)PlayerEvent.Run: //查TODO ,去取消注释才有结果
Log.I("收到跑的消息了");
break;
}
}
public override IManager Manager
{
get { return GameManager.Instance ; }
}
#region 内部类
public class GameManager : QMgrBehaviour, ISingleton
{
public override int ManagerId
{
get { return QMgrID.Game; }
}
public static GameManager Instance
{
get { return MonoSingletonProperty<GameManager>.Instance; }
}
public void OnSingletonInit()
{
}
}
#endregion
}
}
using System.Collections;
using System.Collections.Generic;
using QFramework;
using UnityEngine;
namespace QFramework.Example
{
public class ManagerOfManagersExample : QMonoBehaviour
{
public override IManager Manager
{
get { return UIManager.Instance; }
}
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
Debug.Log("单击");
SendEvent(PlayerEvent.Run);
}
}
}
}
using System.Collections;
using System.Collections.Generic;
using QFramework.Example;
using UnityEngine;
namespace QFramework
{
/// 管所有Mgr
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
}
}
其中用到Log的dll,复制即可
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做过类似的,想比较整合起来
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
}
}
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
}
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;
}
}
}
所以一开始做的是:图片放Resources,路径加 Resources/ 能拿到( 最后走的是Resorces.Load(string path))
但是初始文件夹是没有Resources的,所以继续找
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("TestImage");
// 通过下边方式也一样
RawImage.texture = mResLoader.LoadSync<Texture2D>("testimage_png","TestImage");
}
private void OnDestroy()
{
mResLoader.Recycle2Cache(); //回收到缓存
mResLoader = null;
}
}
}
跟上面一样的逻辑,加了"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;
}
}
}
实际内容是将上面两个例子汇总了一下。
但是第三条的Asset报null,(“assetobj_prefab”, “AssetObj”)。
GameObject prefab = mResLoader.LoadSync<GameObject>("assetobj_prefab", "AssetObj");
prefab.Instantiate()
.Name("这是使用通过 AssetName 和 AssetBundle 加载的对象");
回溯看不出哪里错了,所以试试加载其它预制体,可以的,一个UI物体
//回溯看不出哪里错了,所以试试加载其它预制体
GameObject prefab = mResLoader.LoadSync<GameObject>("uitestunirx_prefab", "UITestUniRx");
prefab.Instantiate()
.Name("这是使用通过 AssetName 和 AssetBundle 加载的对象");
就是有两种 LoadSync方式,直接资源名、包名+文件名。同一种资源,只能采用一种 LoadSync。先用谁,另一个就报空。
下面的写法就会报空第二块代码 mResLoader.LoadSync(“AssetObj”)
GameObject prefab = mResLoader.LoadSync<GameObject>("assetobj_prefab", "AssetObj");
//回溯看不出哪里错了,所以试试加载其它预制体 ,最终发现是QFramework标签
// GameObject prefab = mResLoader.LoadSync("uitestunirx_prefab", "UITestUniRx");
prefab.Instantiate()
.Name("这是使用通过 AssetName 和 AssetBundle 加载的对象");
mResLoader.LoadSync<GameObject>("AssetObj")
.Instantiate()
.Name("这是使用通过 AssetName 加载的对象");
using System.IO;
using UnityEngine;
namespace QFramework.Example
{
public class ResKitExample : MonoBehaviour
{
private ResLoader mResLoader = ResLoader.Allocate();
private void Awake()
{
ResMgr.Init();
}
private void Start()
{
mResLoader.LoadSync<GameObject>("resources://GameObject")
.Instantiate()
.Name("这是使用 ResKit 加载的对象");
if (true)//二选一,选A,B就报空的那种
{
mResLoader.LoadSync<GameObject>("assetobj_prefab", "AssetObj")
//回溯看不出哪里错了,所以试试加载其它预制体 ,最终发现是QFramework标签
// mResLoader.LoadSync("uitestunirx_prefab", "UITestUniRx");
.Instantiate()
.Name("这是使用通过 AssetName 和 AssetBundle 加载的对象");
}
else
{
mResLoader.LoadSync<GameObject>("AssetObj")
.Instantiate()
.Name("这是使用通过 AssetName 加载的对象");
}
}
private void OnDestroy()
{
mResLoader.Recycle2Cache();
mResLoader = null;
}
}
}
using System.Collections;
using UnityEngine;
using UnityEngine.U2D;
using UnityEngine.UI;
namespace QFramework
{
///
///
/// 参考:http://www.cnblogs.com/TheChenLin/p/9763710.html
///
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;
}
}
}
A=>B,表示A可以打开B。脚本多,看工程
1=>2
2=>3
2=>4
3=>5
王小梯 / UniRx精讲
UniRx系列教程
长,考虑要不要贴
适合复用的就静态类
/****************************************************
文件: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 生命
/// 首次载入且Go激活
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);
}
/// 一般用于if(xxx){disposable.Dispose();}
public static IDisposable DoUpdateDispose(this GameObject go)
{
IDisposable disposable = go
.UpdateAsObservable()
.Subscribe(_ =>Debug.Log("DoUpdateDispose"))
.AddTo(go);
return disposable;
}
/// 一般用于if(xxx){disposable.Dispose();}
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);
}
/// 每隔2秒
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.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);
}
/// 每cnt帧的时间输出一次
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 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);
}
/// 提前筛选
public static void Do(this GameObject go)
{
go.UpdateAsObservable()
.Do(_ => Debug.Log("Do"))
.Subscribe(_ => Debug.Log("Do的Subscribe"))//不订阅就不会带引Do
.AddTo(go);
}
/// 与Where、Delay等结合使用
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.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 生命
/// 首次载入且Go激活
void Start()
{
//UniRxExtensions.ExampleMonoBehaviour(this);
//UniRxExtensions.ExampleGameObject(gameObject,this);
//UniRxExtensions.ExampleStart_Keyword(gameObject);
//Example_Scene();
//Example_ToObservable();
ExampleStart_Message();
}
#endregion
}
/****************************************************
文件: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);
}
/// 多线程的消息,主线程下一帧Update收
void MultiThreadingMsg_Receive()
{
MessageBroker.Default.Receive<MsgTmp>()
.SubscribeOnMainThread()
.Subscribe(msgTmp =>
Debug.Log("MainThreadingMsg_Receive的Subscribe" + msgTmp.ToString()))
.AddTo(this);
}
/// 单线程的消息,即发即收
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.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;
/// 有场景交互部分
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.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 辅助
/// 转,但方法块在IEnumeratorBody
void IEnumeratorBody2Observable( IEnumerator from)
{
from.ToObservable()
.DoOnCompleted(()=> Debug.Log("ConvertToObservable")) //这里_(报错)与()(不报错)是不同的
.Subscribe( _ => Debug.Log("ConvertToObservable的Subscribe"))
.AddTo(this);
}
/// 转,但方法块在IEnumeratorBody
void IEnumeratorBody2Observable_TryCatch(IEnumerator from)
{
from.ToObservable()
.Catch<Unit, Exception>(expcetion =>
{
Debug.LogError("IEnumeratorBody2Observable_TryCatch的Catch" );
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的前" ))
.DelayFrame(5)
.Do(_ => Debug.Log("IObservable的后" ));
return res;
}
/// IObservable解决IEnumerator的异常捕捉
IObservable<Unit> ObsTryCatch()
{
int index = 0;
IObservable<Unit> res = Observable.ReturnUnit();
res=res
.Do(_ => Debug.Log("IObservable的前" ))
.DelayFrame(5)
.Do(_ => Debug.Log("IObservable的后" ))
.Do( _=>
{
int[] arr = new int[0];
index = arr[0];
})
.Catch<Unit,Exception>( expcetion=>
{
Debug.LogError(" IObservable的异常" );
return Observable.ReturnUnit();
});
return res;
}
/// 转,但方法块在Observable
void IEnumerator2ObservableBody()
{
Obs()
.DoOnCompleted(() => Debug.Log("IObservable的DoOnCompleted" ))
.Subscribe()
.AddTo(this);
StartCoroutine(Obs()
.DoOnCompleted(() =>
Debug.Log("IObservable的StartCoroutine的DoOnCompleted" ))
.ToYieldInstruction());
}
/// 转,但方法块在Observable
void IEnumerator2ObservableBody_TryCatch()
{
ObsTryCatch()
.DoOnCompleted(() => Debug.Log("IObservable的TryCatch的DoOnCompleted" ))
.Subscribe()
.AddTo(this);
StartCoroutine(ObsTryCatch()
.DoOnCompleted(() =>
Debug.Log("IObservable的TryCatch的StartCoroutine的DoOnCompleted" ))
.ToYieldInstruction());
}
#endregion
}
12.UniRx序列(FromEvent、FromEventPattern、Where、WhenAll、Never)
大白话系列之C#委托与事件讲解(一)
拖入里面的TodoList文件夹,改压缩包,是完整工程(包括QF)
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;
}
}
}
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
}
/// 平铺开
public static RectTransform Stretch(this RectTransform rect)
{
rect.anchorMin = Vector2.zero;
rect.anchorMax = Vector2.one;
rect.sizeDelta = Vector2.zero;
return rect;
}
//
看了,也就是所在类名,改一下
我报错了,所以手动改namespace QFramework.Example 为 namespace QFramework.TodoList。图一
位置是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()
{
发现Ctrl+E(%e)快捷键,重复了,之前学QF摘了一些到个人库Common,先注释掉个人的
报空
至此,跳到最新版本
这是sik学院视频下的资料,QF有点老了,也有一些报错。不建议用,建议到https://github.com/liangxiegame/QFramework下载最新的,里面例子,教程文档什么都有。