想必大家也知道,U3D中可以使用线程,但是却不能在子线程中访问U3D的类型,这里我就分享下我的做法。
首先分享两个脚本~
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
public class CoroutineWrapper : MonoBehaviour {
#region 单例
static CoroutineWrapper inst;
private readonly static object mutex = new object();
public static CoroutineWrapper Inst {
get {
lock (mutex) {
if (inst == null) {
var obj = new GameObject("CoroutineWrapper");
inst = obj.AddComponent<CoroutineWrapper>();
}
return inst;
}
}
}
void Awake() {
inst = this;
DontDestroyOnLoad(this);
}
#endregion
public IEnumerator ExeDelay(int frames,Action ev) {
for (int i = 0; i < frames;i++ ) {
yield return new WaitForEndOfFrame();
}
ev();
}
public IEnumerator ExeDelayS(float sec, Action ev) {
yield return new WaitForSeconds(sec);
ev();;
}
public static void EXES(float sec, Action ev) {
inst.StartCoroutine(inst.ExeDelayS(sec,ev));
}
public static void EXEF(int frames, Action ev) {
inst.StartCoroutine(inst.ExeDelay(frames, ev));
}
public static void EXEE(Func<IEnumerator> ien) {
inst.StartCoroutine(ien());
}
public Action OnPerFrame;
void Update() {
if (OnPerFrame != null)
OnPerFrame();
}
}
另一个~
using System;
using System.Collections;
using System.Collections.Generic;
/// <summary>
/// 安全线程调用
/// 需要场上存在脚本 CoroutineWrapper
/// </summary>
public class ThreadWrapper{
static List<Action> actLst = new List<Action>();
static bool isInited = false;
static object mutex = new object();
/// <summary>
/// 用此方法以在子线程调用不允许调用的方法,实质是主线程执行
/// </summary>
public static void Invoke(Action act) {
if (!isInited) {
UnityEngine.Debug.LogError("ThreadWrapper的Init()还没被调用过");
return;
}
lock (mutex) {
if(act!=null)
actLst.Add(act);
}
}
public static void Init() {
if (!isInited) {
CoroutineWrapper.Inst.OnPerFrame += Loop;
isInited = true;
}
}
static void Loop() {
if (actLst != null && actLst.Count > 0) {
lock (mutex) {
CoroutineWrapper.EXEF(1, actLst[0]);
actLst.RemoveAt(0);
}
}
}
}
举个栗子:
我想UGUI在不操作5秒后淡出,然后又想用.net里的Timer,那么姿势如下:
using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using YangXun;
using System.Timers;
public class ui_main : MonoBehaviour {
Component[] allUIele;
Timer timer = new Timer(5000);
// Use this for initialization
void Start () {
var t1 = CoroutineWrapper.Inst;
ThreadWrapper.Init();
allUIele = GetComponentsInChildren<Component>();
timer.AutoReset = false;
timer.BeginInit();
timer.Elapsed += (a, b) => {
ThreadWrapper.Invoke(() => {
Debug.Log("timer trigger");
foreach (var i in allUIele)
if (i is Graphic)
((Graphic)i).CrossFadeAlpha(0.1f, 2, true);
UIisHide = true;
});
};
timer.Start();
}
bool UIisHide = false;
void Update() {
if (Input.GetMouseButtonDown(0)) {
timer.Stop();
if (UIisHide) {
foreach (var i in allUIele)
if (i is Graphic)
((Graphic)i).CrossFadeAlpha(1, 0.2f, true);
}
}
if (Input.GetMouseButtonUp(0)) {
timer.Start();
}
if (Input.GetKeyUp(KeyCode.Escape))
Application.Quit();
}
}
格式有点问题的样子,大约就是这样喵